1

私は車両の作業指示を管理するシステムを開発しています。作業指示書のIDは、OT-001-16となります。 OT-が文字列であるSQL ServerのストアドプロシージャのIDカウンタをリセットします

001-文字が続く、カウンタで、最終的には数16は現在の年です。

例:

現在の年が2018年である場合、IDはOT-001-18でなければなりません。

年が変更されると、カウンタが001から再開する必要があります。私はそれを行うストアドプロシージャを持っていますが、私はもっと多くの作業をしていると思います。

これは私のストアドプロシージャのコードです:

CREATE PROCEDURE ot (@name varchar(100), @area varchar(100), @idate varchar(100), @edate varchar(100)) 
AS 
BEGIN 
    SET NOCOUNT ON; 
    DECLARE @aux varchar(100); 
    DECLARE @aux2 varchar(100); 
    DECLARE @aux3 int; 
    DECLARE @aux4 varchar(100); 

    SELECT @aux = id_workorder FROM idaux; 

    IF (@aux IS NULL) 
    SET @aux = CONCAT('OT-000-', RIGHT(YEAR(GETDATE()), 2)); 

    SET 
    @aux2 = SUBSTRING(
    @aux, CHARINDEX('-', @aux) + 1, 
    LEN(@aux) - CHARINDEX('-', @aux) - CHARINDEX('-', REVERSE(@aux))); 

    SET @aux3 = CAST(@aux2 AS int) + 1; 

    SET @aux4 = @aux3; 

    IF @aux3 < 1000 
    IF @aux3 >= 10 
     SET @aux4 = CONCAT('0', @aux4); 
    ELSE 
     SET @aux4 = CONCAT('00', @aux4); 
    ELSE 
    SET @aux4 = @aux4; 

    DECLARE @f varchar(100); 
    DECLARE @y varchar(50); 

    SELECT TOP 1 
    @y = id_workorder 
    FROM workorder 
    WHERE (RIGHT(id_workorder, 2)) = (RIGHT(YEAR(GETDATE()), 2)) 
    ORDER BY id_workorder DESC; 

    DECLARE @yy varchar(10); 

    SET 
    @yy = RIGHT(@y, 2); 
    DECLARE @yn varchar(10); 

    SET 
    @yn = RIGHT(YEAR(GETDATE()), 2); 

    BEGIN 
    IF @yn = @yy 
    BEGIN 
     DECLARE @laux varchar(20) 
     SET @f = 'OT-' + @aux4 + '-' + RIGHT(YEAR(GETDATE()), 2); 
     INSERT INTO workorder (id_workorder, name, area, initial_date, end_date) 
     VALUES (@f, @name, @area, @idate, @edate); 

     SELECT 
     @laux = id_workorder 
     FROM idaux 

     IF (@laux IS NULL) 
     BEGIN 
     INSERT idaux (id_workorder) VALUES (@f); 
     END 
     ELSE 
     BEGIN 
     UPDATE idaux SET id_workorder = @f; 
     END 
    END 
    ELSE 
    BEGIN 
     SET @f = CONCAT('OT-001-', (RIGHT(YEAR(GETDATE()), 2))); 
     INSERT INTO workorder (id_workorder, name, area, initial_date, end_date) 
     VALUES (@f, @name, @area, @idate, @edate); 

     SELECT @laux = id_workorder FROM idaux; 

     IF (@laux IS NULL) 
     BEGIN 
     INSERT idaux (id_workorder) VALUES (@f); 
     END 
     ELSE 
     BEGIN 
     UPDATE idaux SET id_workorder = @f; 
     END 
    END 
    END 

END 

は基本的に、私は最後の作業の順序IDを保存するためにAUXILIARテーブルを作成し、その後、この表から、私はIDを取得し、私は新しい可能なIDと比較idauxと呼ばれます文字列処理によって。次に、保存された最後のIDの年が現在の年と等しい場合、カウンタは増加しますが、カウンタが001に再起動されない場合、新しいIDが補助テーブルで更新され、作業オーダーがテーブルworkorderに挿入されます。

私のストアドプロシージャは動作しますが、私はストアドプロシージャを最適化するためにあなたの助けが必要です。コメントに投稿された質問。

+0

このIDが格納されているテーブルの設定についてお問い合わせできますか?完全なIDを 'OT-001-18'として表示したいと思います。しかし、このようにテーブルに格納するのは便利ではありません。私はむしろ1つの列を 'int'として保存し、もう1つの列に今年の' int'としてカウンタを保存し、計算された列(おそらくは 'persistent')を作成して自動的にフルを作成しますID。もちろん、2つの列に対するユニークな制約も追加する必要があります。 DB設定に基づいて、プロシージャをより最適化することができます。 – Ralph

答えて

1

のBINARY照合を試みてテストしていません注意してください、私はあなたの仕事の注文を追跡するために、ストアドプロシージャ、基礎となるテーブルのセットアップをいただきたい方法です:

create database tmpWorkOrders; 
go 

use tmpWorkOrders; 
go 

/* 
    The work order ID (as you wish to see it) and the 
    work order counter (per year) will be separated into 
    two separate columns (with a unique constraint). 
    The work order ID (you wish to see) is automatically 
    generated for you and stored "persisted": 
    http://stackoverflow.com/questions/916068/sql-server-2005-computed-column-is-persisted 
*/ 
create table WorkOrders 
    (
     SurrogateKey   int identity(1, 1) primary key not null, 
     WorkOrderYear  int not null, 
     WorkOrderCounter  int not null, 
     WorkOrderID as 
      N'OT-' + right(N'000' + cast(WorkOrderCounter as nvarchar), 3) 
      + N'-' + right(cast(WorkOrderYear as nvarchar), 2)persisted, 
     WorkOrderDescription nvarchar(200), 
     constraint UQ_WorkOrderIDs 
      unique nonclustered (WorkOrderYear, WorkOrderCounter) 
    ); 
go 

create procedure newWorkOrder 
    (@WorkOrderYear int = null, 
    @WorkOderCounter int = null, 
    @WorkOrderDescription nvarchar(200) = null 
    ) 
as 
    begin 
     /* 
      If no year is given the the current year is assumed 
     */ 
     if @WorkOrderYear is null 
      begin 
       set @WorkOrderYear = year(current_timestamp); 
      end; 
     /* 
      If no work order counter (for the above year) is given 
      then the next available one will be given 
     */ 
     if @WorkOderCounter is null 
      begin 
       set @WorkOderCounter 
        = isnull(
          (
           select max(WorkOrderCounter) 
           from WorkOrders 
           where WorkOrderYear = @WorkOrderYear 
         ) + 1, 
          0 
          ); 
      end; 
     else 
     /* 
       If a work order counter has been passed to the 
       stored procedure then it must be validated first 
      */ 
      begin 
       /* 
        Does the work order counter (for the given year) 
        already exist? 
       */ 
       if exists 
        (
         select 1 
         from dbo.WorkOrders as wo 
         where wo.WorkOrderYear = @WorkOrderYear 
           and wo.WorkOrderCounter = @WorkOderCounter 
        ) 
        begin 
         /* 
          If the given work order counter already exists 
          then the next available one should be assigned. 
         */ 
         while exists 
          (
           select 1 
           from dbo.WorkOrders as wo 
           where wo.WorkOrderYear = @WorkOrderYear 
             and wo.WorkOrderCounter = @WorkOderCounter 
          ) 
          begin 
           set @WorkOderCounter = @WorkOderCounter + 1; 
          end; 
        end; 
      end; 
     /* 
      The actual insert of the new work order ID 
     */ 
     insert into dbo.WorkOrders 
      (
       WorkOrderYear, 
       WorkOrderCounter, 
       WorkOrderDescription 
      ) 
     values 
      (@WorkOrderYear, 
      @WorkOderCounter, 
      @WorkOrderDescription 
      ); 
    end; 
go 

/* 
    Some test runs with the new table and stored procedure... 
*/ 

exec dbo.newWorkOrder @WorkOrderYear = null, 
         @WorkOderCounter = null, 
         @WorkOrderDescription = null; 

exec dbo.newWorkOrder @WorkOrderYear = null, 
         @WorkOderCounter = 3, 
         @WorkOrderDescription = null; 

exec dbo.newWorkOrder @WorkOrderYear = null, 
         @WorkOderCounter = 0, 
         @WorkOrderDescription = null; 

exec dbo.newWorkOrder @WorkOrderYear = null, 
         @WorkOderCounter = 0, 
         @WorkOrderDescription = null; 

exec dbo.newWorkOrder @WorkOrderYear = null, 
         @WorkOderCounter = 0, 
         @WorkOrderDescription = null; 

/* 
    ...reviewing the result of the above. 
*/ 

select * 
from dbo.WorkOrders as wo; 

enter image description here

「次に利用可能な」作業オーダーカウンターは、テーブルのユニークキー制約に違反しなくなるまで最大+ 1および1回増加して1回与えられます。このように、2つの異なる可能性があります。

+0

うまくやっていて、きれいに見え、永続的な列はすばらしいです。必須ではありませんが、アプリケーション/レポートに役立ちます。 –

+1

ありがとうございます。上記の解決策における唯一の汚れた部分は、1.000を超える「作業命令カウンタ」の処理です。作業中ですが、「作業指示書ID」に正しく表示されません。しかし、それはOPのために見ている。基本的には、OPの彼女の現在の状態を分析しているのに対し、私は有効な解決策を提供しています。私は**両方のアプローチ/ソリューションが役立つと思われると推測しています。 – Ralph

+0

私たちはあなたが答えにタグをつけたと言うことができると思います。 :) –

1

結果を最適化して保証するために変更できるコードに基づいて、いくつかの観察があります。

あなたのテーブル構造はわかりませんが、あなたのIDにナチュラルキーを使用しているようです。

  • 代わりに、(何の文字列は必要ありません)あなたのテーブルの効率をジョイン追加しますが、潜在的にあなたの現在の設計では、セキュリティの別のレイヤーを追加するだけでなく、このようなINT/BIGINTとして代理キーを使用します。
  • また、列を正規のフラグに正規化してください。たとえば、OT-001-05には3つの要素があります。OTは作業オーダーの一種で、001はIDで、15は年です。現在、OTは年を決定するIDを決定します。

SELECT @aux = id_workorder FROM idaux;

  • idauxは説明されませんでした。それは単一の価値ですか?表形式の場合は、結果を保証するか、将来破損する可能性があります。
  • MAX(id_workorder)を追加しても、思ったとおりの結果は得られません。これはVARCHARなので、結ばれていない最も左の文字の最大値が返されます。

@aux, CHARINDEX('-', @aux) + 1, LEN(@aux) - CHARINDEX('-', @aux) - CHARINDEX('-', REVERSE(@aux)));

  • これは結構ですが、全体的に、あなたは自分の変数にそれらの要素のすべての3つを分割することにより、デバッグするコードが明確かつ容易に作ることができます。あなたの方法はまだ使用していますが、少し簡略化しました(個人的にはCHARINDEX)。

    SET @aux = @Type -- 'OT' SET @aux2 = @ID -- The result of your previous code SET @aux3 = @Year -- your YY from GETDATE() -- then join SET @Work_Order = CONCAT(@aux, '-', @aux2, '-', @aux3)

更新: は現在、idauxであなたの列には、列の途中でIDを持っています。 これは、IDの比較が列の真ん中で行われるため、悲惨な結果を招きます。つまり、せいぜいあなたはPATINDEXで逃げるかもしれませんが、まだテーブルのテーブルスキャンを実行しています。索引(FULLTEXTのために保存されていない)は、あまり最適化されずに利用されます。

ID要素を独自の列に入れると、その列のBINARY照合を使用するとパフォーマンスが向上することがあります。私は混合コラムここ

関連する問題