2012-06-08 93 views
3

我試圖找到一種方法來自動增加表中的第二個主鍵列當新條目是爲第一個主鍵列添加。我想這裏最好的例子就是這裏。如何爲第一個主鍵列添加新條目時自動增加表中的第二個主鍵列

假設我有一個表:

CREATE TABLE T 
(
    SecNum INT NOT NULL, 
    EntryID INT NOT NULL, 
    Value FLOAT, 
) CONSTRAINT [PK_T] PRIMARY KEY CLUSTERED 
(
    [SecNum] ASC, 
    [EntryID] ASC 
) 

我會運行下面的語句:

INSERT INTO T (SecNum, Value) VALUES (0, 10) 

我的表應該是這樣的:

SECNUM | ENTRYID | VALUE 
------------------------- 
    0   0  10 

我會運行下面的語句:

INSERT INTO T (SecNum, Value) VALUES (0, 10) 

我的表應該是這樣的:

SECNUM | ENTRYID | VALUE 
------------------------- 
    0   0  10 
    0   1  10 

我會運行下面的語句:

INSERT INTO T (SecNum, Value) VALUES (1, 20) 

我的表應該是這樣的:

SECNUM | ENTRYID | VALUE 
------------------------- 
    0   0  10 
    0   1  10 
    1   0  20 
+0

等待 - 在你的第三個例子中,你的意思是** ENTRYID **列中最後一行的值是** 3 **嗎? – lkaradashkov

+2

類似這樣的事情不容易完成 - 它非常混亂和笨拙,我總是建議忘記它,並使用一個「INT IDENTITY」列。 –

+1

@lkaradashkov - 我不這麼認爲,否則爲什麼會是複合鍵?歐普希望當添加新的SECNUM時'ENTRYID'開始全部結束 – Lamak

回答

2

這是可能的使用INSTEAD OF觸發器:

CREATE TRIGGER TriggerName 
ON T 
INSTEAD OF INSERT 
AS 
    -- THIS TOP BIT IS OPTIONAL, IT WILL ALLOW ENTRY ID TO BE OVERRIDDEN IF 
    -- IT IS SUPPLIED TO THE INSERT AND WILL NOT VIOLATE THE PRIMARY KEY 
    IF NOT EXISTS 
     ( SELECT 1 
      FROM T 
        INNER JOIN inserted i 
         ON i.SecNum = T.secNum 
         AND i.EntryID = T.EntryID 
      UNION 
      SELECT 1 
      FROM inserted 
      WHERE EntryID IS NULL 
     ) 
     BEGIN 
      INSERT T (SecNum, EntryID, Value) 
      SELECT SecNum, EntryID, Value 
      FROM inserted 
     END 
    ELSE 
    -- IF OVERRIDE ABILITY IS NOT REQUIRED JUST USE THE BELOW INSERT 
     BEGIN 
      INSERT T (SecNum, EntryID, Value) 
      SELECT i.SecNum, COALESCE(LastID, 0), i.Value 
      FROM inserted I 
        LEFT JOIN 
        ( SELECT SecNum, MAX(T.EntryID) + 1 [LastID] 
         FROM T 
         GROUP BY SecNum 
        ) T 
         ON T.SecNum = i.SecNum 

     END 

Example here

無論其這是不是很優雅。值得一提的是它是否真的有必要?您能否使用代理主鍵逃脫,並使用ROW_NUMBER()來即時創建條目ID?

INSERT INTO T (SecNum, Value, EntryId) 
SELECT 0, 10, count(*) 
FROM T WHERE SecNum = 0 

這是不乾淨的解決方案,並且將相當表現不佳也:

+0

這看起來很有趣。在我的例子中,我喜歡sqlfiddle.com。從來沒有聽說過... – Denis

1

您的問題可以通過使用instead of insert觸發

create trigger Trigger1 on T INSTEAD OF INSERT 
as 
begin         
     insert into T(SecNum,EntryID,Value) 
     select SecNum, 
      (select count(*) from T where SecNum = i.SecNum) as EntryID, 
      value 
     from inserted i 
end 
1

如何像這樣來解決。但它應該完成工作。

+0

這首先需要應用程序邏輯來維護。沒有任何東西可以阻止某人打開SSMS並插入不符合格式的隨機值。其次,它只適用於表中已經存在的插入secnum的值。如果表格爲空,則不會插入行。 [見這裏](http://sqlfiddle.com/#!3/0829f/1) – GarethD

+0

對不起,我不確定我理解。如果表格是空的,是不是會插入0,10,0? 而我不知道這是如何需要應用程序邏輯? (*) FROM T WHERE SecNum = pk1。插入一行所需的所有數據就在那裏。沒有外部依賴性。 – CodingWithLegos

+0

Re:空表,不,因爲如果T中沒有行,那麼'SELECT * FROM T'將不返回任何行,因此不會插入行(請參閱我的示例小提琴)。 Re:應用程序邏輯,這種方法不會強制數據庫遵守邏輯,它只是意味着這個特定的語句符合邏輯。如果插入到表中的唯一方法是這種方法,它可以工作,但是即使secNum = 100沒有現有行,停止另一個開發人員執行INSERT T VALUES(100,100,100)無意中破壞了模式,即使它可能沒有被打算。 – GarethD

1

這是如何做到這一點沒有在表中存儲的值(我不知道你爲什麼要保存它)

DECLARE @T TABLE 
    (
     SecNum INT NOT NULL, 
     EntryID INT, 
     Value FLOAT 
    ) 

DATA

INSERT INTO @T 
     (SecNum, Value) 
VALUES (0, 10) 
INSERT INTO @T 
     (SecNum, Value) 
VALUES (0, 10) 
INSERT INTO @T 
     (SecNum, Value) 
VALUES (1, 20) 

QUERY

SELECT SecNum, 
     ROW_NUMBER() OVER (PARTITION BY value ORDER BY Value) - 1 AS EntryID, 
     Value 
FROM @T 

結果

SecNum EntryID Value 
0   0 10 
0   1 10 
1   0 20 

如果用的EntryID和SECNUM價值變動使用此查詢:

SELECT SecNum, 
     ROW_NUMBER() OVER (PARTITION BY Value,SecNum ORDER BY Value, SecNum) - 1 AS EntryID, 
     Value 
FROM @t 

結果2

SecNum EntryID Value 
0   0 10 
0   1 10 
1   0 10 
1   0 20 
+0

當然,你的第一個查詢應該讀取'ROW_NUMBER()OVER(通過值分區的SecNum ORDER)'不'ROW_NUMBER()OVER(分區BY值ORDER BY值)' – GarethD

+0

第二個查詢(兩列分區) ...如果有任何意義。 – SQLMason

相關問題