Triggerোকানো বা আপডেট করা যায় কীভাবে তা নির্ধারণ করবেন কীভাবে আপডেট ট্রিগার সন্নিবেশ করুন


162

আমাকে টেবিল A ​​তে একটি সন্নিবেশ, আপডেট ট্রিগার লিখতে হবে যা টেবিল বি থেকে সমস্ত সারি মুছে ফেলবে যার এক কলামে (ডেস্ক বলুন) সারণীর এ এর ​​কলামে সন্নিবেশিত / আপডেট হওয়া মানের মতো মান রয়েছে (কল 1 বলে)। আমি কীভাবে এটি লিখতে পারি যাতে আমি আপডেট এবং সন্নিবেশ উভয় ক্ষেত্রেই পরিচালনা করতে পারি। কোনও আপডেট বা সন্নিবেশ করানোর জন্য ট্রিগার কার্যকর করা হয়েছে কিনা তা আমি কীভাবে নির্ধারণ করব।

উত্তর:


167

ট্রিগারগুলির কাছে "আগে" এবং "পরে" ডেটা ট্র্যাক করার জন্য বিশেষ INSERTEDএবং DELETEDসারণী রয়েছে। সুতরাং আপনি IF EXISTS (SELECT * FROM DELETED)আপডেট সনাক্ত করার মতো কিছু ব্যবহার করতে পারেন । আপনার কেবল DELETEDআপডেটে সারি রয়েছে তবে সর্বদা সারি থাকেINSERTED

ট্রিগার তৈরি করুন " sertedোকানো " সন্ধান করুন

সম্পাদনা করুন, 23 নভেম্বর 2011

মন্তব্যের পরে, এই উত্তরটি কেবলমাত্র INSERTEDএবং UPDATEDট্রিগারগুলির জন্য।
স্পষ্টতই, মুছে ফেলুন ট্রিগারগুলির "সর্বদা সারি" থাকতে পারে না INSERTEDযেমন আমি উপরে বলেছি


সম্পূর্ণ উত্তরের জন্য নীচে @ মাইকটাইভির উত্তরটি দেখুন। এটি অসম্পূর্ণ।
লরেঞ্জ মেয়ার

1
@ লোরেঞ্জমায়ার আসল প্রশ্নটির দরকার নেই। আমারও উপস্থিত রয়েছে (মুছে ফেলা থেকে * নির্বাচন করুন)। আপনি কেন এটি সম্পূর্ণ না বলে মনে করছেন তা নিশ্চিত নন ...
gbn

@ লরেঞ্জমায়ার যা উল্লেখ করতে পারেন তা হ'ল " আপনার আপডেটের ক্ষেত্রে কেবল সরিয়ে দেওয়া সারি রয়েছে, তবে সর্বদা সন্নিবেশিত সারি রয়েছে। " এটি সর্বদা সত্য নয় কারণ এমন সময়গুলি থাকে যখন আপডেট / সন্নিবেশ ট্রিগার বলা হয় এবং INSERTED হয় খালি। আমার উত্তরে আমি ব্যাখ্যা করি যে কীভাবে কোনও ডেটা পরিবর্তন থেকে বাদ দিয়ে ভবিষ্যদ্বাণী করা হতে পারে। এই ইভেন্টে, ট্রিগারটিকে এখনও ডিএমএল প্রয়াসের জন্য ডাকা হয়েছে, কিন্তু মোছা এবং সন্নিবেশিত টেবিলগুলি খালি রয়েছে। এটি কারণ হ'ল এসকিউএল এখনও সময়ের জন্য অ্যাকাউন্ট করে যখন আপনি প্রতিটি ডিএমএল প্রচেষ্টা লগ করতে চান (এমনকি তারা কোনও ডেটা পরিবর্তন না করে) al
মাইকটাইভি

127
CREATE TRIGGER dbo.TableName_IUD
ON dbo.TableName
AFTER INSERT, UPDATE, DELETE
AS 
BEGIN
    SET NOCOUNT ON;

    --
    -- Check if this is an INSERT, UPDATE or DELETE Action.
    -- 
    DECLARE @action as char(1);

    SET @action = 'I'; -- Set Action to Insert by default.
    IF EXISTS(SELECT * FROM DELETED)
    BEGIN
        SET @action = 
            CASE
                WHEN EXISTS(SELECT * FROM INSERTED) THEN 'U' -- Set Action to Updated.
                ELSE 'D' -- Set Action to Deleted.       
            END
    END
    ELSE 
        IF NOT EXISTS(SELECT * FROM INSERTED) RETURN; -- Nothing updated or inserted.

    ...

    END

1
আমি লিখুন পছন্দ করি নিবন্ধ থেকেও 1 যেমন আমি মনে করি এটি আরও সুস্পষ্টভাবে অভিপ্রায়কে ইঙ্গিত করে, তবে এমএসএসকিউএল প্রোগ্রামাররা যদি হতাশ হয়ে থাকি তবে যদি এই প্রসঙ্গে কোনও পার্থক্য আসে ...
লুকা লানস্কি

26
যদি উপস্থিতি (নির্বাচন * ...) এবং যদি উপস্থিত থাকে (নির্বাচন 1) ... ঠিক একইরকম পারফরম্যান্স রয়েছে। সারিটি মোটেও পড়া হয় না বা পাওয়া যায় না। প্রকৃতপক্ষে আপনি যদি অস্তিত্বগুলি (নির্বাচন করুন 1/0 ...) ব্যবহার করতে পারেন এবং এটি এখনও কাজ করবে এবং শূন্য ত্রুটির দ্বারা বিভাজন ঘটবে না।
এন্ডারজু

1
আমি সন্নিবেশ, আপডেট এবং মুছে ফেলার জন্য পৃথক ট্রিগার তৈরি করছিলাম they এখন তারা একত্রিত হতে পারে তা জানতে পেরে দুর্দান্ত!
ইউজেএস

2
যদি কেউ INSERT এ একটি ক্যোয়ারী লিখেন এবং দুটি পৃথক সারি মুছে ফেলুন (নতুন সারি সন্নিবেশ করান এবং একই স্ক্রিপ্টে অন্য একটি সারি মুছুন), তবে কি সম্ভব যে উপরোক্ত উপায়ে যে ট্রিগারটি সেট আপ করা হয়েছে তা আসলে এটি একটি আপডেট হিসাবে চিহ্নিত হবে (যদিও অভিপ্রায়টি সত্ত্বেও) সন্নিবেশিত / মোছা স্কেল-টেবিলগুলিতে ডেটা থাকার কারণে কি আসলে একটি আপডেট নয়?
mche

87

আপনি কোনও মুছুন এমন বিবৃতি যা কিছু মুছে না তা চালনা করে এই পরামর্শগুলির মধ্যে অনেকগুলি বিবেচনায় নেই।
বলুন আপনি মুছে ফেলার চেষ্টা করছেন যেখানে কোনও আইডি এমন কোনও মানের সমান হয় যা টেবিলটিতে নেই।
আপনার ট্রিগারটি এখনও কল হয়েছে তবে মোছা বা সন্নিবেশ করা টেবিলগুলিতে কিছুই নেই।

নিরাপদ থাকতে এটি ব্যবহার করুন:

--Determine if this is an INSERT,UPDATE, or DELETE Action or a "failed delete".
DECLARE @Action as char(1);
    SET @Action = (CASE WHEN EXISTS(SELECT * FROM INSERTED)
                         AND EXISTS(SELECT * FROM DELETED)
                        THEN 'U'  -- Set Action to Updated.
                        WHEN EXISTS(SELECT * FROM INSERTED)
                        THEN 'I'  -- Set Action to Insert.
                        WHEN EXISTS(SELECT * FROM DELETED)
                        THEN 'D'  -- Set Action to Deleted.
                        ELSE NULL -- Skip. It may have been a "failed delete".   
                    END)

তাদের উত্তরগুলির জন্য @ কেনডগ এবং @ নেট_প্রোগকে বিশেষ ধন্যবাদ।
আমি তাদের লিপি থেকে এটি নির্মিত।


3
এই এক পুরষ্কার, অস্তিত্বহীন মুছে ফেলা পরিচালনা। ভাল কাজ!
অ্যান্ড্রু ওল্ফ

6
আমাদের এমন একটি আপডেটও থাকতে পারে যা কোনও সারিগুলিকে প্রভাবিত করে না (বা এমনকি কোনও INSERT)।
রাজ্জান সোসোল

@ অ্যান্ড্রু ওল্ফ? আপনি কি বলছেন? প্রশ্নটি সুনির্দিষ্টভাবে বলেছে যে "আমাকে টেবিল এ তে একটি সন্নিবেশ, আপডেট ট্রিগার লিখতে হবে" । ডিফল্ট ট্রিগারগুলি সম্পর্কে কিছুই নেই।
ypercubeᵀᴹ

@ ইয়পারক्यूबᵀᴹ দুঃখিত, আমার প্রায় 80% ট্রিগার তিনটি সময়ই কভার করে।
অ্যান্ড্রু ওল্ফ

18

আমি নিম্নলিখিত ব্যবহার করছি, এটি সঠিকভাবে মুছে ফেলা বিবৃতি সনাক্ত করে যা কিছুই মুছে না:

CREATE TRIGGER dbo.TR_TableName_TriggerName
    ON dbo.TableName
    AFTER INSERT, UPDATE, DELETE
AS
BEGIN
    SET NOCOUNT ON;

    IF NOT EXISTS(SELECT * FROM INSERTED)
        -- DELETE
        PRINT 'DELETE';
    ELSE
    BEGIN
        IF NOT EXISTS(SELECT * FROM DELETED)
            -- INSERT
            PRINT 'INSERT';
        ELSE
            -- UPDATE
            PRINT 'UPDATE';
    END
END;

4
যদিও এইটি ভুলভাবে এমন বিবৃতি সনাক্ত করে যা কিছুই সন্নিবেশ করে না বা কিছুই আপডেট করে না।
রোমান পেকার

11

প্রচুর অনুসন্ধানের পরেও আমি একটি একক এসকিউএল সার্ভার ট্রিগারের সঠিক উদাহরণটি খুঁজে পাইনি যা ট্রিগার ক্রিয়াকলাপ INSERT, আপডেট এবং ডিলিটের সমস্ত (3) তিনটি শর্তাদি পরিচালনা করে। অবশেষে আমি একটি পাঠ্যের একটি লাইন পেয়েছি যা এই বিষয়ে কথা বলেছিল যে যখন একটি মোছা বা আপডেট হয়, সাধারণ মোছা টেবিলটিতে এই দুটি ক্রিয়াকলাপের রেকর্ড থাকে। সেই তথ্যের উপর ভিত্তি করে, আমি তখন একটি ছোট অ্যাকশন রুটিন তৈরি করেছি যা নির্ধারণ করে যে ট্রিগারটি সক্রিয় করা হয়েছে কেন। কোনও INSERT বনাম আপডেটের ট্রিগারে ঘটতে একটি সাধারণ কনফিগারেশন এবং নির্দিষ্ট ক্রিয়াকলাপ উভয় ক্ষেত্রেই এই ধরণের ইন্টারফেসের প্রয়োজন হয়। এই ক্ষেত্রে, আপডেটের জন্য আলাদা ট্রিগার তৈরি করা এবং INSERT রক্ষণাবেক্ষণের সমস্যায় পরিণত হবে। (অর্থাৎ প্রয়োজনীয় সাধারণ ডেটা অ্যালগরিদম ফিক্সের জন্য উভয়ই ট্রিগার সঠিকভাবে আপডেট হয়েছিল?)

সে লক্ষ্যে, আমি মাইক্রোসফ্ট এসকিউএল সার্ভারের জন্য একটি ট্রিগারে INSERT, আপডেট, পরিচালনা করার জন্য নিম্নলিখিত মাল্টি-ট্রিগার ইভেন্ট কোড স্নিপেটটি দিতে চাই।

CREATE TRIGGER [dbo].[INSUPDDEL_MyDataTable]
ON [dbo].[MyDataTable] FOR INSERT, UPDATE, DELETE
AS 

-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with caller queries SELECT statements.
-- If an update/insert/delete occurs on the main table, the number of records affected
-- should only be based on that table and not what records the triggers may/may not
-- select.
SET NOCOUNT ON;

--
-- Variables Needed for this Trigger
-- 
DECLARE @PACKLIST_ID varchar(15)
DECLARE @LINE_NO smallint
DECLARE @SHIPPED_QTY decimal(14,4)
DECLARE @CUST_ORDER_ID varchar(15)
--
-- Determine if this is an INSERT,UPDATE, or DELETE Action
-- 
DECLARE @Action as char(1)
DECLARE @Count as int
SET @Action = 'I' -- Set Action to 'I'nsert by default.
SELECT @Count = COUNT(*) FROM DELETED
if @Count > 0
    BEGIN
        SET @Action = 'D' -- Set Action to 'D'eleted.
        SELECT @Count = COUNT(*) FROM INSERTED
        IF @Count > 0
            SET @Action = 'U' -- Set Action to 'U'pdated.
    END

if @Action = 'D'
    -- This is a DELETE Record Action
    --
    BEGIN
        SELECT @PACKLIST_ID =[PACKLIST_ID]
                    ,@LINE_NO = [LINE_NO]
        FROM DELETED

        DELETE [dbo].[MyDataTable]
        WHERE [PACKLIST_ID]=@PACKLIST_ID AND [LINE_NO]=@LINE_NO
    END
 Else
    BEGIN
            --
            -- Table INSERTED is common to both the INSERT, UPDATE trigger
            --
            SELECT @PACKLIST_ID =[PACKLIST_ID]
                ,@LINE_NO = [LINE_NO]
                ,@SHIPPED_QTY =[SHIPPED_QTY]
                ,@CUST_ORDER_ID = [CUST_ORDER_ID]
            FROM INSERTED 

         if @Action = 'I'
            -- This is an Insert Record Action
            --
            BEGIN
                INSERT INTO [MyChildTable]
                    (([PACKLIST_ID]
                    ,[LINE_NO]
                    ,[STATUS]
                VALUES
                    (@PACKLIST_ID
                    ,@LINE_NO
                    ,'New Record'
                    )
            END
        else
            -- This is an Update Record Action
            --
            BEGIN
                UPDATE [MyChildTable]
                    SET [PACKLIST_ID] = @PACKLIST_ID
                          ,[LINE_NO] = @LINE_NO
                          ,[STATUS]='Update Record'
                WHERE [PACKLIST_ID]=@PACKLIST_ID AND [LINE_NO]=@LINE_NO
            END
    END   

9

আমি বিশ্বাস করি নেস্টেড আইএফএসকে কিছুটা বিভ্রান্ত করে এবং:

ফ্ল্যাটটি নেস্টেড [পাইথনের জেন] এর চেয়ে ভাল

;)

DROP TRIGGER IF EXISTS AFTER_MYTABLE

GO

CREATE TRIGGER dbo.AFTER_MYTABLE ON dbo.MYTABLE AFTER INSERT, UPDATE, DELETE 

AS BEGIN 

    --- FILL THE BEGIN/END SECTION FOR YOUR NEEDS.

    SET NOCOUNT ON;

    IF EXISTS(SELECT * FROM INSERTED)  AND EXISTS(SELECT * FROM DELETED) 
        BEGIN PRINT 'UPDATE' END 
    ELSE IF EXISTS(SELECT * FROM INSERTED)  AND NOT EXISTS(SELECT * FROM DELETED) 
        BEGIN PRINT 'INSERT' END 
    ELSE IF    EXISTS(SELECT * FROM DELETED) AND NOT EXISTS(SELECT * FROM INSERTED)
        BEGIN PRINT 'DELETED' END
    ELSE BEGIN PRINT 'NOTHING CHANGED'; RETURN; END  -- NOTHING

END

9
Declare @Type varchar(50)='';
IF EXISTS (SELECT * FROM inserted) and  EXISTS (SELECT * FROM deleted)
BEGIN
    SELECT @Type = 'UPDATE'
END
ELSE IF EXISTS(SELECT * FROM inserted)
BEGIN
    SELECT @Type = 'INSERT'
END
ElSE IF EXISTS(SELECT * FROM deleted)
BEGIN
    SELECT @Type = 'DELETE'
END

5

এটা চেষ্টা কর..

ALTER TRIGGER ImportacionesGS ON dbo.Compra 
    AFTER INSERT, UPDATE, DELETE
AS
BEGIN
  -- idCompra is PK
  DECLARE @vIdCompra_Ins INT,@vIdCompra_Del INT
  SELECT @vIdCompra_Ins=Inserted.idCompra FROM Inserted
  SELECT @vIdCompra_Del=Deleted.idCompra FROM Deleted
  IF (@vIdCompra_Ins IS NOT NULL AND @vIdCompra_Del IS NULL)  
  Begin
     -- Todo Insert
  End
  IF (@vIdCompra_Ins IS NOT NULL AND @vIdCompra_Del IS NOT NULL)
  Begin
     -- Todo Update
  End
  IF (@vIdCompra_Ins IS NULL AND @vIdCompra_Del IS NOT NULL)
  Begin
     -- Todo Delete
  End
END

4

আমি @ অ্যালেক্স দ্বারা পোস্ট করা উত্তরটিও পছন্দ করি, আমি উপরে @ গ্রাহামের সমাধানটিতে এই প্রকরণটি দিচ্ছি

এটি প্রথম পরীক্ষার জন্য COLUMNS_UPDATED ব্যবহারের বিপরীতে INSERTED এবং UPDATED টেবিলগুলিতে একচেটিয়াভাবে রেকর্ড অস্তিত্ব ব্যবহার করে। চূড়ান্ত কেসটি বিবেচনা করা হয়েছে তা জেনেও এটি ভৌতিক প্রোগ্রামার ত্রাণ সরবরাহ করে ...

declare @action varchar(4)
    IF EXISTS (SELECT * FROM INSERTED)
        BEGIN
            IF EXISTS (SELECT * FROM DELETED) 
                SET @action = 'U'  -- update
            ELSE
                SET @action = 'I'  --insert
        END
    ELSE IF EXISTS (SELECT * FROM DELETED)
        SET @action = 'D'  -- delete
    else 
        set @action = 'noop' --no records affected
--print @action

আপনি নীচের মত একটি বিবৃতি দিয়ে NOOP পাবেন:

update tbl1 set col1='cat' where 1=2

মনে হচ্ছে প্রথমটি ENDভুলভাবে ইনডেন্ট করা হয়েছে! (প্রশ্নের ঘটাচ্ছে যেখানে প্রথম BEGINবন্ধ করা হয়)
S.Serpooshan

অন্যথায় যদি এবং চূড়ান্ত অন্য একক বিবৃতি ধারণ করে। শুরু এবং শেষটি সত্যিই অপ্রয়োজনীয় কারণ আইএফ / অন্য কোনও একক বিবৃতি is আমি ইনডেন্টিং সংশোধন করেছি। সাহায্যের জন্য ধন্যবাদ.
গ্রেগ

3

এটি একটি দ্রুততর উপায় হতে পারে:

DECLARE @action char(1)

IF COLUMNS_UPDATED() > 0 -- insert or update
BEGIN
    IF EXISTS (SELECT * FROM DELETED) -- update
        SET @action = 'U'
    ELSE
        SET @action = 'I'
    END
ELSE -- delete
    SET @action = 'D'

4
এই পদ্ধতিতে বড় সংখ্যক কলাম সহ টেবিলগুলির জন্য কাজ করে না কারণ কলামগুলি_পাদিত () একটি ভেরিবিনারি প্রদান করে যা বিশাল। সুতরাং "> 0" ব্যর্থ হয়েছে কারণ কলাম_আপডেটেড ()
গ্রাহাম

3

প্রস্তাবিত দুটি সমাধানগুলির একটি সম্ভাব্য সমস্যা হ'ল সেগুলি কীভাবে লেখা হয় তার উপর নির্ভর করে একটি আপডেট ক্যোয়ারী শূন্য রেকর্ড আপডেট করতে পারে এবং একটি সন্নিবেশ ক্যোয়ারী শূন্য রেকর্ড সন্নিবেশ করতে পারে। এই ক্ষেত্রে, sertedোকানো এবং মোছা রেকর্ডসেটগুলি খালি থাকবে। অনেক ক্ষেত্রে, sertedোকানো এবং মুছে ফেলা উভয় রেকর্ডসই যদি খালি থাকে তবে আপনি কিছু না করে কেবল ট্রিগারটি থেকে বেরিয়ে আসতে চাইতে পারেন।


2

গ্রাহামে আমি একটি ছোট ত্রুটি পেয়েছি অন্যথায় শীতল সমাধান:

এটি যদি COLUMNS_UPDATED () < > 0 -> 0 এর
পরিবর্তে সন্নিবেশ করা বা আপডেট করা উচিত কারণ সম্ভবত শীর্ষ বিটটি স্বাক্ষরিত পূর্ণসংখ্যা চিহ্ন বিট ... (?) হিসাবে ব্যাখ্যা করা হয়। সুতরাং মোট:

DECLARE @action CHAR(8)  
IF COLUMNS_UPDATED() <> 0 -- delete or update?
BEGIN     
  IF EXISTS (SELECT * FROM deleted) -- updated cols + old rows means action=update       
    SET @action = 'UPDATE'     
  ELSE
    SET @action = 'INSERT' -- updated columns and nothing deleted means action=insert
END 
ELSE -- delete     
BEGIN
  SET @action = 'DELETE'
END

1

এটি আমার জন্য কৌশলটি করে:

declare @action_type int;
select @action_type = case
                       when i.id is not null and d.id is     null then 1 -- insert
                       when i.id is not null and d.id is not null then 2 -- update
                       when i.id is     null and d.id is not null then 3 -- delete
                     end
  from      inserted i
  full join deleted  d on d.id = i.id

যেহেতু সমস্ত কলামগুলি একসাথে আপডেট করা যায় না আপনি এটি পরীক্ষা করে দেখতে পারেন যে কোনও নির্দিষ্ট কলাম এই জাতীয় কিছু দ্বারা আপডেট হচ্ছে:

IF UPDATE([column_name])

একটি চ্যালেঞ্জ ডাব্লু / এই সমাধানটি আপনাকে কলামের নাম জানতে হবে। অন্যদের মধ্যে এমন কিছু তৈরি করা হয়েছে যাতে আপনি কেবল স্নিপেট লাইব্রেরি থেকে পেস্ট অনুলিপি করতে পারেন। ছোট বিষয়, তবে বিবেচনা করা সমস্ত বিষয়, একটি জেনেরিক সমাধান কেস নির্দিষ্ট সমাধানের চেয়ে ভাল। এই প্রোগ্রামটিতে।
গ্রেগ

1
declare @insCount int
declare @delCount int
declare @action char(1)

select @insCount = count(*) from INSERTED
select @delCount = count(*) from DELETED

    if(@insCount > 0 or @delCount > 0)--if something was actually affected, otherwise do nothing
    Begin
        if(@insCount = @delCount)
            set @action = 'U'--is update
        else if(@insCount > 0)
            set @action = 'I' --is insert
        else
            set @action = 'D' --is delete

        --do stuff here
    End

1
পারফরম্যান্সের কারণে আমি COUNT (*) ব্যবহার করব না - এটির পুরো টেবিলটি স্ক্যান করা দরকার। আমি পরিবর্তে যদি মুছে ফেলার জন্য একই থাকে তবে উপস্থিত থাকি (সন্নিবেশিত থেকে নির্বাচন করুন) ব্যবহার করে একটি পতাকা সেট করব। আমি জানি সাধারণত সেখানে দু'একটি সারি আক্রান্ত হয় তবে কেন সিস্টেমটি ধীর করে দিন।
এন্ডারজু

আমি সমাধান হিসাবে খুব অনুরূপ কিছু পোস্ট করতে চলেছিলাম। এটি কিছুটা শব্দযুক্ত, তবে খুব পঠনযোগ্য। ফেয়ার ট্রেড অফ আমি উপরের গ্রাহস সলিউশনটিও পছন্দ করি।
গ্রেগ

1

আমি "কম্পিউটার বিজ্ঞানের মার্জিত" সমাধানগুলি পছন্দ করি। আমার সমাধানটি এখানে প্রতিস্থাপিত হওয়ার জন্য [সন্নিবেশ করা] এবং [মুছে ফেলা] সিউডোটেবলগুলি একবারে হিট করে এবং ফলাফলটিকে কিছুটা ম্যাপিং ভেরিয়েবলের মধ্যে রাখে। তারপরে INSERT, আপডেট এবং ডিলিটের প্রতিটি সম্ভাব্য সংমিশ্রণটি দক্ষ বাইনারি মূল্যায়ন (সম্ভাব্য INSERT বা মোছার সংযোজন বাদে) সহ সহজেই ট্রিগার জুড়ে পরীক্ষা করা যেতে পারে।

এটি এই ধারণাটি তৈরি করে যে ডিএমএলের বিবৃতিটি কোনও সারি সংশোধন না করা হলে (যা বেশিরভাগ ক্ষেত্রে সন্তুষ্ট হওয়া উচিত) তা বিবেচনা করে না। সুতরাং এটি রোমান পেকারের সমাধানের মতো সম্পূর্ণ না হলেও এটি আরও কার্যকর।

এই পদ্ধতির সাথে, আমাদের প্রতি টেবিলের জন্য একটি "INSERT, আপডেট, মুছে ফেলুন" ট্রিগার করার সম্ভাবনা রয়েছে, আমাদের এ) ক্রিয়া আদেশের উপর সম্পূর্ণ নিয়ন্ত্রণ এবং খ) মাল্টি-অ্যাকশন-প্রযোজ্য ক্রিয়াকলাপে একটি কোড প্রয়োগকরণ one (স্পষ্টতই, প্রতিটি বাস্তবায়নের মডেলটির উপকারিতা এবং বিপরীতে রয়েছে; আসলে কী সবচেয়ে ভাল কাজ করে তার জন্য আপনাকে পৃথকভাবে আপনার সিস্টেমগুলি মূল্যায়ন করতে হবে))

নোট যে, "বিদ্যমান নির্বাচন (*« ঢোকানো / মুছে যাওয়া »থেকে)" বিবৃতি খুব কার্যকরী যেহেতু কোন ডিস্ক অ্যাক্সেস (হয় https://social.msdn.microsoft.com/Forums/en-US/01744422-23fe-42f6 -9ab0-a255cdf2904a )।

use tempdb
;
create table dbo.TrigAction (asdf int)
;
GO
create trigger dbo.TrigActionTrig
on dbo.TrigAction
for INSERT, UPDATE, DELETE
as
declare @Action tinyint
;
-- Create bit map in @Action using bitwise OR "|"
set @Action = (-- 1: INSERT, 2: DELETE, 3: UPDATE, 0: No Rows Modified 
  (select case when exists (select * from inserted) then 1 else 0 end)
| (select case when exists (select * from deleted ) then 2 else 0 end))
;
-- 21 <- Binary bit values
-- 00 -> No Rows Modified
-- 01 -> INSERT -- INSERT and UPDATE have the 1 bit set
-- 11 -> UPDATE <
-- 10 -> DELETE -- DELETE and UPDATE have the 2 bit set

raiserror(N'@Action = %d', 10, 1, @Action) with nowait
;
if (@Action = 0) raiserror(N'No Data Modified.', 10, 1) with nowait
;
-- do things for INSERT only
if (@Action = 1) raiserror(N'Only for INSERT.', 10, 1) with nowait
;
-- do things for UPDATE only
if (@Action = 3) raiserror(N'Only for UPDATE.', 10, 1) with nowait
;
-- do things for DELETE only
if (@Action = 2) raiserror(N'Only for DELETE.', 10, 1) with nowait
;
-- do things for INSERT or UPDATE
if (@Action & 1 = 1) raiserror(N'For INSERT or UPDATE.', 10, 1) with nowait
;
-- do things for UPDATE or DELETE
if (@Action & 2 = 2) raiserror(N'For UPDATE or DELETE.', 10, 1) with nowait
;
-- do things for INSERT or DELETE (unlikely)
if (@Action in (1,2)) raiserror(N'For INSERT or DELETE.', 10, 1) with nowait
-- if already "return" on @Action = 0, then use @Action < 3 for INSERT or DELETE
;
GO

set nocount on;

raiserror(N'
INSERT 0...', 10, 1) with nowait;
insert dbo.TrigAction (asdf) select top 0 object_id from sys.objects;

raiserror(N'
INSERT 3...', 10, 1) with nowait;
insert dbo.TrigAction (asdf) select top 3 object_id from sys.objects;

raiserror(N'
UPDATE 0...', 10, 1) with nowait;
update t set asdf = asdf /1 from dbo.TrigAction t where asdf <> asdf;

raiserror(N'
UPDATE 3...', 10, 1) with nowait;
update t set asdf = asdf /1 from dbo.TrigAction t;

raiserror(N'
DELETE 0...', 10, 1) with nowait;
delete t from dbo.TrigAction t where asdf < 0;

raiserror(N'
DELETE 3...', 10, 1) with nowait;
delete t from dbo.TrigAction t;
GO

drop table dbo.TrigAction
;
GO

আমার প্রসঙ্গে এই সমাধানের জন্য ধন্যবাদ। আপনি কি আপডেট / sertedোকানো সারিটির সর্বশেষ আপডেটকৃত কলামটি আপডেট করার কোনও উপায়ের পরামর্শ দিবেন? আপনি কি অন্য টেবিলে মুছে ফেলা সারির আইডি (কী তৈরি হতে পারে) এর কোনও উপায় সঞ্চয় করার পরামর্শ দিতে চান?
সেবাস্টিয়ান

0

দ্রুত সমাধান মাইএসকিউএল

যাইহোক: আমি মাইএসকিউএল পিডিও ব্যবহার করছি।

(1) একটি স্বয়ংবৃদ্ধি সারণীতে প্রতিটি স্ক্রিপ্ট প্রথমে একবার চালানোর পরে বর্ধিত কলাম থেকে সর্বাধিক মান (আমার কলামের নাম = আইডি) পান:

$select = "
    SELECT  MAX(id) AS maxid
    FROM    [tablename]
    LIMIT   1
";

(২) আপনি মাইএসকিউএল কোয়েরিটি সাধারণভাবে চালান এবং ফলাফলটি পূর্ণসংখ্যায় ফেলে দেন, যেমন:

$iMaxId = (int) $result[0]->maxid;

(3) "INSERT INTO ... DUPLICATE KEY UPDATE" এর পরে ক্যোয়ারীটি আপনার সর্বাধিক পছন্দসই উপায়ে সর্বশেষ idোকানো আইডি পান, যেমন:

$iLastInsertId = (int) $db->lastInsertId();

(4) তুলনা করুন এবং প্রতিক্রিয়া জানান: যদি সর্বশেষতম আইডটি টেবিলের সর্বোচ্চের চেয়ে বেশি হয় তবে এটি সম্ভবত একটি INSERT, তাই না? এবং বিপরীতভাবে.

if ($iLastInsertId > $iMaxObjektId) {
    // IT'S AN INSERT
}
else {
    // IT'S AN UPDATE
}

আমি জানি এটি দ্রুত এবং সম্ভবত নোংরা। এবং এটি একটি পুরানো পোস্ট। তবে, আরে, আমি দীর্ঘদিন ধরে সমাধানটির সন্ধান করছিলাম এবং সম্ভবত যে কেউ আমার পথটিকে কিছুটা কার্যকর মনে করেছে। শুভকামনা!


0

শুধু সহজ উপায়

CREATE TRIGGER [dbo].[WO_EXECUTION_TRIU_RECORD] ON [dbo].[WO_EXECUTION]
WITH EXECUTE AS CALLER
FOR INSERT, UPDATE
AS
BEGIN  

  select @vars = [column] from inserted 
  IF UPDATE([column]) BEGIN
    -- do update action base on @vars 
  END ELSE BEGIN
    -- do insert action base on @vars 
  END

END 

আমার এসএমএস আইডি অনুসারে আপনি কীভাবে আপনার যুক্তিটি মোড়কটি দিয়ে শুরু করতে পারেন তা যদি আপনার শুরু হয় না - এন্ডে এলসি শুরু - অবরুদ্ধ ব্লকগুলি আপনার সিনট্যাক্সটি সঠিক নয়।
এরুটান 409

0

প্রথম দৃশ্যে আমি অনুমান করেছি যে আপনার টেবিলটিতে পরিচয় কলাম রয়েছে

CREATE TRIGGER [dbo].[insupddel_yourTable] ON [yourTable]
FOR INSERT, UPDATE, DELETE
AS
IF @@ROWCOUNT = 0 return
SET NOCOUNT ON;
DECLARE @action nvarchar(10)
SELECT @action = CASE WHEN COUNT(i.Id) > COUNT(d.Id) THEN 'inserted'
                      WHEN COUNT(i.Id) < COUNT(d.Id) THEN 'deleted' ELSE 'updated' END
FROM inserted i FULL JOIN deleted d ON i.Id = d.Id

দ্বিতীয় দৃশ্যে আইডেন্টিটি কলাম ব্যবহার করার দরকার নেই

CREATE TRIGGER [dbo].[insupddel_yourTable] ON [yourTable]
FOR INSERT, UPDATE, DELETE
AS
IF @@ROWCOUNT = 0 return
SET NOCOUNT ON;
DECLARE @action nvarchar(10),
        @insCount int = (SELECT COUNT(*) FROM inserted),
        @delCount int = (SELECT COUNT(*) FROM deleted)
SELECT @action = CASE WHEN @insCount > @delCount THEN 'inserted'
                      WHEN @insCount < @delCount THEN 'deleted' ELSE 'updated' END

আমার একই সমস্যা আছে কেউ আমাকে সহায়তা করতে পারে। নীচের লিঙ্কটি দেখুন stackoverflow.com/questions/26043106/…
রমেশ এস

0
DECLARE @INSERTEDCOUNT INT,
        @DELETEDCOUNT INT

SELECT @INSERTEDCOUNT = COUNT([YourColumnName]) FROM inserted

SELECT @DELETEDCOUNT = COUNT([YourColumnName]) FROM deleted

যদি তার আপডেট হয়

 @INSERTEDCOUNT = 1
 @DELETEDCOUNT = 1

যদি এটি সন্নিবেশ করা হয়

 @INSERTEDCOUNT = 1
 @DELETEDCOUNT = 0

0

আমি exists (select * from inserted/deleted)দীর্ঘসময় ধরে এই প্রশ্নগুলি ব্যবহার করেছি , তবে এটি শূন্য সিআরইউডি অপারেশনের জন্য এখনও যথেষ্ট নয় (যখন কোনও টেবিলে insertedএবং deletedটেবিলে কোনও রেকর্ড নেই )। সুতরাং এই বিষয়টি সামান্য গবেষণা করার পরে আমি আরও সুনির্দিষ্ট সমাধান পেয়েছি:

declare
    @columns_count int = ?? -- number of columns in the table,
    @columns_updated_count int = 0

-- this is kind of long way to get number of actually updated columns
-- from columns_updated() mask, it's better to create helper table
-- or at least function in the real system
with cte_columns as (
    select @columns_count as n
    union all
    select n - 1 from cte_columns where n > 1
), cte_bitmasks as (
    select
        n,
        (n - 1) / 8 + 1 as byte_number,
        power(2, (n - 1) % 8) as bit_mask
    from cte_columns
)
select
    @columns_updated_count = count(*)
from cte_bitmasks as c
where
    convert(varbinary(1), substring(@columns_updated_mask, c.byte_number, 1)) & c.bit_mask > 0

-- actual check
if exists (select * from inserted)
    if exists (select * from deleted)
        select @operation = 'U'
    else
        select @operation = 'I'
else if exists (select * from deleted)
    select @operation = 'D'
else if @columns_updated_count = @columns_count
    select @operation = 'I'
else if @columns_updated_count > 0
    select @operation = 'U'
else
    select @operation = 'D'

columns_updated() & power(2, column_id - 1) > 0কলামটি আপডেট হয়েছে কিনা তাও ব্যবহার করা সম্ভব , তবে বড় সংখ্যক কলাম সহ টেবিলের জন্য এটি নিরাপদ নয়। আমি গণনার জন্য কিছু জটিল পদ্ধতি ব্যবহার করেছি (নীচে সহায়ক নিবন্ধটি দেখুন)।

এছাড়াও, এই পদ্ধতিটি এখনও সঠিকভাবে সন্নিবেশ হিসাবে কিছু আপডেটগুলিকে শ্রেণিবদ্ধ করবে (যদি টেবিলের প্রতিটি কলাম আপডেট দ্বারা প্রভাবিত হয়), এবং সম্ভবত এটি সন্নিবেশগুলিকে শ্রেণিবদ্ধ করবে যেখানে কেবল ডিফল্ট মানগুলি মুছে ফেলা হিসাবে sertedোকানো হয়, তবে সেগুলি বিরল ক্রিয়াকলাপের রাজা (এ আমার সিস্টেমে লিজ তারা হয়)। তা ছাড়া এই মুহুর্তে কীভাবে এই সমাধানটি উন্নত করা যায় তা আমি জানি না।


0
declare @result as smallint
declare @delete as smallint = 2
declare @insert as smallint = 4
declare @update as smallint = 6
SELECT @result = POWER(2*(SELECT count(*) from deleted),1) + POWER(2*(SELECT 
     count(*) from inserted),2)

if (@result & @update = @update) 
BEGIN
  print 'update'
  SET @result=0
END
if (@result & @delete = @delete)
  print 'delete'
if (@result & @insert = @insert)
  print 'insert'

0

আমি এই কাজ:

select isnull((select top 1 1 from inserted t1),0) + isnull((select top 1 2 from deleted t1),0)

1 -> .োকান

2 -> মুছুন

3 -> আপডেট

set @i = isnull((select top 1 1 from inserted t1),0) + isnull((select top 1 2 from deleted t1),0)
--select @i

declare @action varchar(1) = case @i when 1 then 'I' when 2 then 'D' when 3 then 'U' end
--select @action


select @action c1,* from inserted t1 where @i in (1,3) union all
select @action c1,* from deleted t1 where @i in (2)

0
DECLARE @ActionType CHAR(6);
SELECT  @ActionType = COALESCE(CASE WHEN EXISTS(SELECT * FROM INSERTED)
                                     AND EXISTS(SELECT * FROM DELETED)  THEN 'UPDATE' END,
                               CASE WHEN EXISTS(SELECT * FROM DELETED)  THEN 'DELETE' END,
                               CASE WHEN EXISTS(SELECT * FROM INSERTED) THEN 'INSERT' END);
PRINT   @ActionType;
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.