बेशक किसी को मेज पर प्राथमिक कुंजी नहीं बदलनी चाहिए - लेकिन यह वही है जो ट्रिगर्स (भाग में) के लिए होना चाहिए, लोगों को उन चीजों को करने से रोकना है जो उन्हें नहीं करना चाहिए। यह ओरेकल या MySQL में एक ट्रिगर लिखने के लिए एक छोटा कार्य है जो प्राथमिक कुंजी में परिवर्तन को रोकता है और उन्हें रोकता है, लेकिन SQL सर्वर में बिल्कुल आसान नहीं है।
if exists
(
select *
from inserted changed
join deleted old
where changed.rowID = old.rowID
and changed.id != old.id
)
... [roll it all back]
यही वजह है लोगों ROWID की एसक्यूएल सर्वर बराबर के लिए googling बाहर जाना:
क्या निश्चित रूप से आप के लिए किया जाएगा करने के लिए सक्षम होने के लिए प्यार होता है बस कुछ इस तरह से करते हैं। खैर, एसक्यूएल सर्वर में यह नहीं है; तो आपको एक और दृष्टिकोण के साथ आना होगा।
एक तेज, लेकिन दुख की बात नहीं है कि बमप्रूफ, संस्करण अद्यतन ट्रिगर के बजाय एक लिखना है जो यह देखने के लिए दिखता है कि किसी भी डाली गई पंक्तियों में प्राथमिक कुंजी को अद्यतन तालिका में या इसके विपरीत नहीं मिला है या नहीं। यह सबसे पकड़ होता है, लेकिन सभी नहीं, त्रुटियों की:
if exists
(
select *
from inserted lost
left join updated match
on match.id = lost.id
where match.id is null
union
select *
from deleted new
left join inserted match
on match.id = new.id
where match.id is null
)
-- roll it all back
लेकिन यह अभी भी एक अद्यतन की तरह पकड़ नहीं करता है ...
update myTable
set id = case
when id = 1 then 2
when id = 2 then 1
else id
end
अब, मैं इस धारणा बनाने की कोशिश की है कि सम्मिलित और हटाए गए तालिकाओं को इस तरह से आदेश दिया जाता है कि एक साथ सम्मिलित और हटाए गए तालिकाओं के माध्यम से कर्सर आपको उचित मिलान पंक्तियां देगा। और यह काम करने के लिए अपवाद। असल में आप ट्रिगर को ओरेकल में उपलब्ध प्रत्येक-पंक्ति ट्रिगर्स के बराबर में बदलते हैं और MySQL में अनिवार्य है ... लेकिन मुझे लगता है कि प्रदर्शन बड़े पैमाने पर अपडेट पर खराब होगा क्योंकि यह SQL सर्वर के मूल व्यवहार नहीं है। यह भी एक धारणा पर निर्भर करता है कि मैं वास्तव में कहीं भी दस्तावेज नहीं ढूंढ सकता हूं और इसलिए इस पर निर्भर रहने के लिए अनिच्छुक हूं। लेकिन कोड ने इस तरह से संरचित किया है कि मेरे SQL सर्वर 2008 R2 स्थापना पर ठीक से काम करने के लिए APPEARS। इस पोस्ट के अंत में लिपि तेजी से लेकिन बमरोधी समाधान और दूसरे, छद्म-ओरेकल समाधान के व्यवहार दोनों के व्यवहार को हाइलाइट करती है।
किसी को भी किसी ऐसे स्थान पर जहां मेरी धारणा दस्तावेज और गारंटी है माइक्रोसॉफ्ट द्वारा मैं एक बहुत ही आभारी पुरुष होगी करने के लिए मुझसे बात कर सकता है ...
begin try
drop table kpTest;
end try
begin catch
end catch
go
create table kpTest(id int primary key, name nvarchar(10))
go
begin try
drop trigger kpTest_ioU;
end try
begin catch
end catch
go
create trigger kpTest_ioU on kpTest
instead of update
as
begin
if exists
(
select *
from inserted lost
left join deleted match
on match.id = lost.id
where match.id is null
union
select *
from deleted new
left join inserted match
on match.id = new.id
where match.id is null
)
raisError('Changed primary key', 16, 1)
else
update kpTest
set name = i.name
from kpTest
join inserted i
on i.id = kpTest.id
;
end
go
insert into kpTest(id, name) values(0, 'zero');
insert into kpTest(id, name) values(1, 'one');
insert into kpTest(id, name) values(2, 'two');
insert into kpTest(id, name) values(3, 'three');
select * from kpTest;
/*
0 zero
1 one
2 two
3 three
*/
-- This throws an error, appropriately
update kpTest set id = 5, name = 'FIVE' where id = 1
go
select * from kpTest;
/*
0 zero
1 one
2 two
3 three
*/
-- This allows the change, inappropriately
update kpTest
set id = case
when id = 1 then 2
when id = 2 then 1
else id
end
, name = UPPER(name)
go
select * from kpTest
/*
0 ZERO
1 TWO -- WRONG WRONG WRONG
2 ONE -- WRONG WRONG WRONG
3 THREE
*/
-- Put it back
update kpTest
set id = case
when id = 1 then 2
when id = 2 then 1
else id
end
, name = LOWER(name)
go
select * from kpTest;
/*
0 zero
1 one
2 two
3 three
*/
drop trigger kpTest_ioU
go
create trigger kpTest_ioU on kpTest
instead of update
as
begin
declare newIDs cursor for select id, name from inserted;
declare oldIDs cursor for select id from deleted;
declare @thisOldID int;
declare @thisNewID int;
declare @thisNewName nvarchar(10);
declare @errorFound int;
set @errorFound = 0;
open newIDs;
open oldIDs;
fetch newIDs into @thisNewID, @thisNewName;
fetch oldIDs into @thisOldID;
while @@FETCH_STATUS = 0 and @errorFound = 0
begin
if @thisNewID != @thisOldID
begin
set @errorFound = 1;
close newIDs;
deallocate newIDs;
close oldIDs;
deallocate oldIDs;
raisError('Primary key changed', 16, 1);
end
else
begin
update kpTest
set name = @thisNewName
where id = @thisNewID
;
fetch newIDs into @thisNewID, @thisNewName;
fetch oldIDs into @thisOldID;
end
end;
if @errorFound = 0
begin
close newIDs;
deallocate newIDs;
close oldIDs;
deallocate oldIDs;
end
end
go
-- Succeeds, appropriately
update kpTest
set name = UPPER(name)
go
select * from kpTest;
/*
0 ZERO
1 ONE
2 TWO
3 THREE
*/
-- Succeeds, appropriately
update kpTest
set name = LOWER(name)
go
select * from kpTest;
/*
0 zero
1 one
2 two
3 three
*/
-- Fails, appropriately
update kpTest
set id = case
when id = 1 then 2
when id = 2 then 1
else id
end
go
select * from kpTest;
/*
0 zero
1 one
2 two
3 three
*/
-- Fails, appropriately
update kpTest
set id = id + 1
go
select * from kpTest;
/*
0 zero
1 one
2 two
3 three
*/
-- Succeeds, appropriately
update kpTest
set id = id, name = UPPER(name)
go
select * from kpTest;
/*
0 ZERO
1 ONE
2 TWO
3 THREE
*/
drop table kpTest
go
आप अपने प्राथमिक कुंजी को बदलने नहीं किया जाना चाहिए। –
एक परिपूर्ण दुनिया में आप बिल्कुल सही हैं। हालांकि मैं डेटाबेस और एप्लिकेशन के बाहर काम कर रहा हूं जो इस तालिका का उपयोग करता है, इसलिए मैं उस नियम को लागू नहीं कर सकता – keith