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(); 

我的表約束的/ etc代碼

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 

的原因唯一約束是因爲主複合鍵的一部分也是一個外鍵另外兩張桌子。 我不斷收到的錯誤是當它在唯一約束列中存在重複值時對我大叫。一旦所有東西都從開發中轉移到生產中,這可能會發生,因爲可能會重新提交一張票。

有沒有辦法讓外鍵沒有唯一的鍵約束? 如果不是,我該如何解決這個問題?

+0

您不應該編輯您的問題來提出完全不同的問題:改爲發佈爲新問題。 – 2011-05-09 13:58:08

回答

4

這是我們在編程中遇到的很多情況之一。 Technology_A不會讓我做Operation_B,但它應該!然後,在我們頭撞牆的一段時間後,我們放棄(或轉向Stackoverflow)。我們這樣做是因爲我們沒有按照預期使用該技術(這是好的,這就是我們學習的方式)

這裏的問題是您的數據庫模式。

你試圖用一張表做太多。您不應該在跟蹤#個事件的同一張表中存儲票(相同票可能存在多次)。

在我看來,有兩個很好的策略來糾正這種情況。首先,我將創建一個帶有單列主鍵的票據表。然後,我將創建一個存儲票證的每個實例的表。

enter image description here

實施例:Ticket43是封閉的,但重新打開和再次關閉。這意味着(如果我正確地讀你的問題),票證有兩個實例。這意味着它將在原始表中有兩個條目,但在我提出的新建模式中,它將在Tickets中有一個條目,在Ticket_Instances中有兩個條目。

注意:您需要確保存儲票證中實例之間永不改變的票證信息以及Ticket_Instances中特定於實例的票證信息。

錄製票數,我會做的僅僅是寫像下面這樣的視圖或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觸發器。您可以創建一經插入Ticket_Instances表中的觸發器,而觸發SQL將做到以下幾點:

  • 如果TicketID不Ticket_Counts存在,然後將TicketID到Ticket_Counts與TicketCount 0
  • 然後,Ticket_Counts中TicketCount增加1 Ticket_Counts中的TicketID

使用此方法,您只需通過TicketID訪問Ticket_Counts即可獲取該特定Ticket的出現次數。

我想你會發現一旦你更新你的模式,你的約束錯誤就會消失。

+0

感謝您的幫助。我沒有完全按照這個建議。相反,我使用了分離器表來解決這個問題。 Tickets Table將其複合主鍵發送到中間表,該中間表僅發送我需要的其他兩個表作爲外鍵。這只是意味着中間表將不得不更新與票號是全部,這是好的,因爲它的工作原理。 – Will 2011-05-09 14:56:26

+0

很高興你的工作。有很多方法可以實現這個目標,但有時候很容易被一張桌子做得比他們能夠有效地處理更多。祝你好運 – 2011-05-09 18:17:14