2013-10-19 10 views
5

एक प्रवेश प्रणाली मैं निम्नलिखित डेटाबेस स्कीमा है के लिए के लिए ट्रिगर:इसके बजाय के- डालने एकाधिक तालिकाओं

CREATE TABLE [dbo].[Categories] (
    [Id]  INT   IDENTITY (1, 1) NOT NULL, 
    [App]  NVARCHAR (30) NULL, 
    [Source] NVARCHAR (30) NULL, 
    [LogLevel] NVARCHAR (5) NULL, 
    [Logger] NVARCHAR (120) NULL, 
    CONSTRAINT [PK_Categories] PRIMARY KEY NONCLUSTERED ([Id] ASC), 
    CONSTRAINT [UK_Categories] UNIQUE NONCLUSTERED ([App] ASC, [Source] ASC, [LogLevel] ASC, [Logger] ASC) 
); 

CREATE TABLE [dbo].[Occurences] (
    [PointInTime] BIGINT NOT NULL, 
    [CategoryId] INT NOT NULL, 
    [Noise]  INT NOT NULL, 
    CONSTRAINT [PK_Occurences] PRIMARY KEY CLUSTERED ([PointInTime] ASC, [CategoryId] ASC, [Noise] ASC), 
    CONSTRAINT [FK_Category] FOREIGN KEY ([CategoryId]) REFERENCES [Categories] ([Id]) 
); 

डिजाइन लक्ष्य अधिक महंगा तारों के रूप में लॉगिंग डेटा की एक बड़ी राशि के लिए अनुमति देने के लिए है एक अलग मेज में फैक्टर कर रहे हैं।

शब्दार्थ दोनों तालिकाओं एक भी तार्किक तालिका इस दृश्य द्वारा परिभाषित के रूप में:

CREATE VIEW [dbo].[HistoricLogEntries] 
    AS SELECT o.PointInTime, o.Noise, c.App, c.[Source], c.LogLevel, c.Logger 
    FROM Occurences o 
    JOIN Categories c ON o.CategoryId = c.Id; 

मैं अब दृश्य पर एक के बजाय के- डालने-ट्रिगर है, जो जहाँ मेरे मुसीबतों शुरू निर्धारण कैसे करेंगे ।

CREATE TRIGGER InsteadTrigger on [dbo].[HistoricLogEntries] 
INSTEAD OF INSERT 
AS 
BEGIN 
    INSERT INTO Categories 
    SELECT i.App, i.[Source], i.LogLevel, i.Logger 
    FROM INSERTED i; 

    INSERT INTO Occurences 
    SELECT i.PointInTime, i.Noise, c.Id AS CategoryId 
    FROM INSERTED i 
    JOIN Categories c ON i.App = c.App AND i.[Source] = c.[Source] AND i.LogLevel = c.LogLevel AND i.Logger = c.Logger; 
END 

वहाँ स्पष्ट पहली समस्या यह है कि पहले डालने की जाँच नहीं कर रहा है टपल डेटाबेस में पहले से ही है कि क्या है: मैं निम्नलिखित का प्रयास किया है। मुझे पता होगा कि एक वैल्यू डालने के मामले में ऐसा कैसे करें, लेकिन यहां मुझे एक से अधिक पंक्ति सम्मिलित करने के लिए खाता है।

एक और चीज जिसे मैं समझा नहीं सकता वह यह है कि पहली प्रविष्टि सफल होने पर ट्रिगर भी काम नहीं करता है। मुझे एक विदेशी कुंजी उल्लंघन मिलता है - जैसे कि पहली प्रविष्टि वास्तव में कुछ भी सम्मिलित नहीं करती थी।

मैंने सोचा कि यह एक सामान्य सेटअप होना चाहिए, तो हो सकता है कि किसी के पास कुछ समान उदाहरण कोड हो?

उत्तर

8

SQL2008 के लिए + मैं नई श्रेणियों डालने के लिए मिलाएं बयान का प्रयोग करेंगे:

MERGE dbo.Categories WITH (HOLDLOCK) AS c 
USING INSERTED AS i ON i.App = c.App 
AND i.[Source] = c.[Source] 
AND i.LogLevel = c.LogLevel 
AND i.Logger = c.Logger 
WHEN NOT MATCHED BY TARGET THEN 
    INSERT (App, [Source], LogLevel, Logger) 
    VALUES (i.App, i.[Source], i.LogLevel, i.Logger); 

मैं HOLDLOCK तालिका संकेत to prevent race condition प्रयोग किया है:

[...] के साथ डेटा सम्मिलित करने से समवर्ती सत्र को रोकने के लिए एक ही कुंजी, केवल एक सत्र कुंजी को पढ़ने के लिए एक असंगत ताला अधिग्रहण किया जाना चाहिए (मेरा नोट: इस मामले में UK_Categories अद्वितीय अनुक्रमणिका) और लेनदेनतक लॉक होना चाहिएकम्प्लिट्स [...]

और FK त्रुटियों को रोकने के:।

The INSERT statement conflicted with the FOREIGN KEY constraint "FK_Category". The conflict occurred in database "Test", table "dbo.Categories", column 'Id'. 

मैं दूसरे INSERT इस प्रकार के भीतर हर स्तंभ का नाम जोड़ना होगा:

INSERT INTO Occurences (PointInTime, Noise, CategoryId) 
SELECT i.PointInTime, i.Noise, c.Id AS CategoryId 
FROM INSERTED i 
JOIN Categories c ON i.App = c.App 

कारण इन एफके त्रुटियों में से कॉलम के क्रम में एक असंगतता है:

1) CREATE के भीतर कॉलम का क्रम (शोर बनाम CategoryID देखें तालिका

[PointInTime] BIGINT NOT NULL, 
    [CategoryId] INT NOT NULL, 
    [Noise]  INT NOT NULL, 

लेकिन

2) दूसरा डालने के भीतर कॉलम के क्रम अलग है):

ALTER TRIGGER InsteadTrigger on [dbo].[HistoricLogEntries] 
INSTEAD OF INSERT 
AS 
BEGIN  
    MERGE dbo.Categories WITH (HOLDLOCK) AS c 
    USING INSERTED AS i ON i.App = c.App 
    WHEN NOT MATCHED BY TARGET THEN 
     INSERT (App) 
     VALUES (i.App); 

    INSERT INTO Occurences (PointInTime, Noise, CategoryId) 
    SELECT i.PointInTime, i.Noise, c.Id AS CategoryId 
    FROM INSERTED i 
    JOIN Categories c ON i.App = c.App 
END 
GO 
:

INSERT INTO Occurences 
-- or INSERT INTO Occurences (PointInTime, CategoryId, Noise) 
SELECT i.PointInTime, i.Noise, c.Id AS CategoryId 
FROM ... 

यह मेरा समाधान है

+1

यह वास्तव में व्यापक है, और प्रश्न पोस्ट करने के तुरंत बाद।आपका बहुत बहुत धन्यवाद! – John

संबंधित मुद्दे