5

非常に具体的なビジネス要件を渡されましたが、それをデータベース内で機能するように変換するのに苦労しています。

複数の部門があり、すべてファイルと呼ばれるものを扱っています。各ファイルには一意の識別子がありますが、この識別子がどのように割り当てられるかは、ファイルが関連付けられている部門によって異なります。

部門 ABC、DEF、および GHI は、パターンに従って次の ID を提供するシステムを必要とします...部門 JKL および MNO は、独自の ID を指定できる必要があります。

これは、生成されたファイル番号が半複雑であるという事実によってさらに悪化します。それらのファイル番号は次のパターンに従います。

[a-z]{3,4}\d{2}-\d{4} 

(年に対応する 2 桁の部門に対応する 3 文字または 4 文字のプレフィックス、ダッシュの後に生成された 4 桁の番号 - 例: ABC13-0001)

ダッシュの前の部分は簡単に生成できます...ファイルテーブルには、プレフィックス列を持つ部門テーブルへの必須の外部キー参照があり、年を簡単に取得できます。うまくいかないように見えるのは、ダッシュの後の部分です。

4桁のIDです。各部門は、次に生成される ID が可能な限りその部門と連続している必要があります (ID の仕様でもギャップが生じる可能性があることを認識しているため、できるだけ連続していると言います)。その上、毎年 0001 にリセットする必要があります。重複がないようにすることは、これらすべての中で最も重要な部分です。

したがって、これらすべての部門で使用されるファイル テーブルは 1 つだけです。そのため、JKL と MNO を処理できるようにするために、FileNumber フィールドを一意の制約で varchar(12) に設定しました。一意である限り、必要なものは何でも入力できます。あとは、他の部門の一意のファイル番号を生成する方法だけです。

私の最初の本能は、生成されたファイル番号に問題が発生した場合でも、各レコードが一意の識別子であることを保証するために、ファイル テーブルに代理 ID プライマリ キーを与えることです。

次に、部門ごとに 2 つの列 (1 つは数字用、もう 1 つは日付用) を持つ単一行テーブルを作成します。番号は、特定の部門の 4 桁の識別子サフィックスの最後に使用された番号 (int として) であり、日付は割り当てられた日付です。日付を保存すると、最後の ID が取得されてから年が変更されたかどうかを確認できるため、lastid + 1 の代わりに 1 を割り当てることができます。

次に、ファイル テーブルの挿入トリガーは、次を使用してファイル ID を生成します。

  • 部門プレフィックスを取得するための部門テーブルへの外部キー
  • CONVERT(VARCHAR, YEAR( GETDATE() ) % 100) は、現在の 2 桁の年を取得します
  • 上記のユーティリティ テーブルを選択して、最後の ID + 1 を取得します (または、現在の年が最終更新日の年と異なる場合は 1 にリセットします)。

トリガーは最終的に、最後に使用された ID と日付でユーティリティ テーブルを更新します。

理論的には、それはうまくいくと思います...そして、ファイルID列の一意の制約により、生成されたファイルIDが既に存在する場所への挿入が妨げられます。しかし、それは非常にもろく感じられ、トリガーがユーティリティ テーブルの更新に失敗した場合に、部門が新しいファイルを作成するのを妨げる可能性がある一意の制約が諸刃の剣であると予見できます。結局のところ、そうでない場合は、次にファイル番号が生成されるときに、生成された同じ ID を使用しようとして失敗します。もっと良い方法があるはずです。

私の他の考えは、ID整数列とnull以外の日付フィールドだけを持つ部門ごとのテーブルをデフォルトの(getdate())...で作成し、ファイルテーブルのトリガーに新しい行を挿入させ、それを使用することでしたID。また、指定された部門 ID テーブルのすべての行を削除し、新年に ID をリセットする役割も果たします。私にはより安全に感じますが、ID を生成するためだけに、最大 9999 のレコードを持つ 5 つのユーティリティ テーブル (ID を自動生成する部門ごとに 1 つ) があります。

簡単なものがありませんか?私はこれを正しい方法で行っていますか?もっと簡単な方法があるはずだと思わずにはいられません。SQL サーバーにこれを任せようとするのは正しいでしょうか、それとも、このデータベースの上に構築するデスクトップ アプリケーションでこれを行うべきでしょうか?

4

1 に答える 1

1

したがって、これを過度に複雑にしている可能性があると思います。また、要件を誤解している可能性もあります。別のテーブルなどは必要ないと思います。既存の ID を確認してインクリメントするだけで済みます。SQLFiddle は現在機能していないようですが、ローカル DB で思いついた方法を次に示します。

create table dept_ids (
  id varchar(12) primary key
  )

insert into dept_ids values('ABC13-0001')
insert into dept_ids values('DEF13-0001')
insert into dept_ids values('GHI13-0001')
insert into dept_ids values('JKL13-0001')
insert into dept_ids values('ABC13-0002')

declare 
    @dept varchar(4)
    , @year varchar(2)
    , @prefix varchar(8)
    , @new_seq int

set @dept = 'ABC'
select @year = right(cast(DATEPART(yy, getdate()) as varchar(4)), 2)
set @prefix = @dept + @year + '-'

select @new_seq = isnull(right(max(id), 4), 0) + 1 from dept_ids where id like @prefix + '%'

select new_id = @prefix + right(replicate('0', 4) + cast(@new_seq as varchar(4)), 4)

これはもちろん、getdate() と ISNULL チェックを使用して、さまざまな部門と年のシナリオを処理します。独自のシーケンス値を入力できる部門の場合、そのパラメーターの null チェックを追加し、存在する場合はこの値の生成をスキップできます。

単純化しすぎている場合は、お気軽にお知らせください。調整いたします。

于 2013-10-22T18:09:07.007 に答える