3

私は SQL Server 2008 R2、C#、および ASP.Net を使用しています。チケット番号と、そのチケットがテーブルに表示される回数で構成される複合主キーを持つテーブルがあります。チケットの頻度は、C# コードによって計算されます。

VTTTickets.InsertParameters[0].DefaultValue = VTTTTicketNoBox.Text;
string CommString = "SELECT COUNT(*) FROM [Tickets] WHERE [Ticket_No] = " + 
VTTTTicketNoBox.Text;
string ConnString = ConfigurationManager.ConnectionStrings[1].ConnectionString;
OdbcConnection Conn = new OdbcConnection(ConnString);
Conn.Open();
OdbcCommand FooCommand = newOdbcCommand(CommString,Conn);
int FooVal = Convert.ToInt32(FooCommand.ExecuteScalar()) + 1;
VTTTickets.InsertParameters[1].DefaultValue = Convert.ToString(FooVal);
VTTTTicketNoBox.Text = "";
Conn.Close();

私のテーブルの制約/その他のコード

CONSTRAINT [PK_Tickets] PRIMARY KEY CLUSTERED 
([Ticket_No] ASC, [Ticket_Sub_No] ASC)
WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = ON,
ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY],
CONSTRAINT [Unique_Ticket_No] UNIQUE NONCLUSTERED 
([Ticket_No] ASC)
WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = ON,     
ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY],
) ON [PRIMARY]
GO

一意制約の理由は、主複合キーのその部分が他の 2 つのテーブルの外部キーでもあるためです。私が取得し続けるエラーは、一意の制約付き列に重複した値が存在することを私に怒鳴るときです。チケットが再送信される可能性があるため、すべてが開発から本番環境に移行すると、これが発生する可能性があります。

一意キー制約なしで外部キーを作成する方法はありますか? そうでない場合、どうすればこの問題を回避できますか?

4

1 に答える 1

5

これは、プログラミングでよく遭遇する状況の 1 つです。Technology_A では Operation_B を実行できませんが、実行する必要があります。そして、しばらく頭を壁にぶつけた後、あきらめます (または Stackoverflow に向かいます)。私たちがこれを行うのは、テクノロジーを意図したとおりに使用していないためです (これは問題ありません。それが私たちが学習する方法です!)

ここでの問題は、データベース スキーマです。

1 つのテーブルで多くのことをしようとしています。発生回数を追跡している同じテーブルにチケットを保存しないでください (同じチケットが複数回存在する可能性があります)。

私の意見では、この状況を修正するには 2 つの優れた戦略があります。まず、1 列の主キーを持つチケット テーブルを作成します。次に、チケットの各インスタンスを格納するテーブルを作成します。

ここに画像の説明を入力

例: Ticket43 は閉じられていますが、再度開かれ、再び閉じられています。これは、(あなたの質問を正しく読んだ場合)、チケットに 2 つのインスタンスがあったことを意味します。これは、元のテーブルには 2 つのエントリがあることを意味しますが、新しく提案されたスキーマでは、Tickets に 1 つのエントリ、Ticket_Instances に 2 つのエントリがあります。

注: インスタンス間で変更されないチケット情報は Tickets に格納し、インスタンス固有のチケット情報は Ticket_Instances に格納するようにしてください。

Ticket Counts を記録するには、最初に次のようなビューまたは SQL を記述します。

SELECT
  count(*) as TicketCount,
  TicketID
FROM
  Ticket_Instances as TI
GROUP BY
  TicketID

これをオンデマンドで計算する必要がない場合は、次を使用することをお勧めします。

  • ASP.NET キャッシュ (上記の SQL を実行し、10 分の TTL でキャッシュに詰め込みます)
  • トリガーによって入力される Ticket_Counts テーブルを使用する

そこではオプション 2 を好むと思います (ただし、オプション 1 を使用します)。

トリガー方法:

Ticket_Instances が決して削除されないと仮定すると、Insert Trigger だけが必要です。挿入時に Ticket_Instances テーブルにトリガーを作成すると、そのトリガー SQL は次のようになります。

  • TicketID が Ticket_Counts に存在しない場合は、TicketCount を 0 にして、TicketID を Ticket_Counts に挿入します。
  • 次に、Ticket_Counts の TicketID の 1 だけ TicketCount を増やします。

このメソッドでは、TicketID で Ticket_Counts にアクセスするだけで、その特定のチケットの発生回数を取得できます。

スキーマを更新すると、制約エラーが消えることがわかると思います。

于 2011-05-08T01:37:49.853 に答える