9

मैंने यह अपने करियर में कुछ बार देखा है, और मेरे स्थानीय सहयोगियों में से कोई भी इसका उत्तर देने में सक्षम नहीं है। मान लें कि मेरे पास एक सारणी है जिसमें "विवरण" फ़ील्ड है जो एक उम्मीदवार कुंजी है, सिवाय इसके कि कभी-कभी उपयोगकर्ता प्रक्रिया के माध्यम से आधा रास्ते बंद कर देगा। तो शायद 25% रिकॉर्ड्स के लिए यह मान शून्य है, लेकिन उन सभी के लिए जो पूर्ण नहीं हैं, यह अद्वितीय होना चाहिए।एसक्यूएल क्या मेरे पास एक टेबल पर "सशर्त रूप से अद्वितीय" बाधा हो सकती है?

एक और उदाहरण एक तालिका हो सकती है जो रिकॉर्ड के कई "संस्करण" को बनाए रखना चाहिए, और थोड़ा मान इंगित करता है कि कौन सा "सक्रिय" है। तो "उम्मीदवार कुंजी" हमेशा पॉप्युलेट होती है, लेकिन तीन संस्करण हो सकते हैं जो समान हैं (सक्रिय बिट में 0 के साथ) और केवल एक जो सक्रिय है (सक्रिय बिट में 1)।

मेरे पास इन समस्याओं को हल करने के लिए वैकल्पिक तरीके हैं (पहले मामले में, नियम कोड को लागू करें, या तो संग्रहीत प्रक्रिया या व्यावसायिक परत में, और दूसरे में, एक ट्रिगर के साथ एक संग्रह तालिका को पॉप्युलेट करें और तालिकाओं को यूनियन करें इतिहास की आवश्यकता है)। मैं विकल्पों को नहीं चाहता (जब तक कि बेहतर तरीके से बेहतर समाधान न हों), मैं बस सोच रहा हूं कि एसक्यूएल का कोई स्वाद इस तरह से "सशर्त विशिष्टता" व्यक्त कर सकता है। मैं एमएस एसक्यूएल का उपयोग कर रहा हूं, इसलिए यदि इसमें ऐसा करने का कोई तरीका है, तो बढ़िया। मैं ज्यादातर समस्या में अकादमिक रूप से रुचि रखते हैं।

+2

संभावित डुप्लिकेट: http://stackoverflow.com/questions/866061/conditional-unique-constraint –

+1

एसक्यूएल सर्वर के किन संस्करणों? – gbn

+0

सिलिको में सूचक के लिए धन्यवाद। यह निश्चित रूप से स्थिति 2 पर लागू होता है। मैंने पोस्ट करने से पहले खोज की थी, लेकिन वास्तव में मैंने उन खोजशब्दों पर खोज नहीं की जिन्हें मैंने अंततः शीर्षक में उपयोग किया था या मुझे यह मिल गया होगा! आपके द्वारा पोस्ट किया गया लिंक काफी पता स्थिति # 1 नहीं है, जिसे 2005 में टॉम एच के सुझाव और 2008 में आर्थर के साथ हल किया गया है। जीबीएन: मैं 2005 का उपयोग कर रहा हूं, यही कारण है कि मुझे इंडेक्स के बारे में पता नहीं था 2008 में फ़िल्टर। –

उत्तर

28

आप एसक्यूएल सर्वर 2008 का उपयोग कर रहे हैं, तो एक सूचकांक फिल्टर होगा हो सकता है आपके समाधान:

http://msdn.microsoft.com/en-us/library/ms188783.aspx

यह मैं कैसे लागू कई शून्य वाले अद्वितीय सूचकांक

CREATE UNIQUE INDEX [IDX_Blah] ON [tblBlah] ([MyCol]) WHERE [MyCol] IS NOT NULL 
+1

आह - फ़ंक्शन आधारित इंडेक्स ... डीबीए उन –

+0

@ ओएमजी टोनियों को नाराज करते हैं जबकि डीबीए के लिए चूसने वाला यह एकमात्र व्यावहारिक समाधान है – msarchet

+0

@msarchet: कार्य एटीएम की मदद करने के तरीके में हो रहा है, लेकिन ओपी में वर्णित तालिका सेटअप है मेरे लिए आदर्श नहीं है। लेकिन डीबीए के साथ लड़ने का आनंद लें =) –

0

टिप्पणियों के लिए धन्यवाद, इस उत्तर का प्रारंभिक संस्करण गलत था।

create table NullAndUnique 
    (
    id int identity, 
    name varchar(50), 
    uniqueName as case 
     when name is null then cast(id as varchar(51)) 
     else name + '_' end, 
    unique(uniqueName) 
    ) 

insert into NullAndUnique default values 
insert into NullAndUnique default values -- Works 
insert into NullAndUnique default values -- not accidentally :) 
insert into NullAndUnique (name) values ('Joel') 
insert into NullAndUnique (name) values ('Joel') -- Boom! 

यह मूल रूप से id उपयोग करता है जब name रिक्त है:

यहाँ एक चाल एक अभिकलन स्तंभ को प्रभावी ढंग से एसक्यूएल सर्वर में एक नल अद्वितीय बाधा की अनुमति देता है का उपयोग कर रहा है। + '_' उन मामलों से बचने के लिए है जहां नाम संख्यात्मक हो सकता है, जैसे 1, जो id से टकरा सकता है।

+1

वास्तव में? एमएसडीएन से: "एक अद्वितीय इंडेक्स में उपयोग किए जाने वाले कॉलम को न्यूल पर सेट किया जाना चाहिए, क्योंकि एक अद्वितीय इंडेक्स बनने पर एकाधिक शून्य मान डुप्लिकेट माना जाता है।" – Arthur

+6

नहीं, SQL सर्वर एक अद्वितीय बाधा से ढके कॉलम में एकाधिक शून्य मानों को अनुमति नहीं देता है। एसक्यूएल मानक निर्दिष्ट करता है कि इसे अनुमति दी जानी चाहिए (जैसा कि न्यूल भी स्वयं के बराबर नहीं है), लेकिन माइक्रोसॉफ्ट के एसक्यूएल सर्वर ने इस बिंदु पर मानक का पालन नहीं किया है। –

0

महत्व देता अन्य विधि है सशर्त नियमों को लागू करने के लिए कि एक अद्वितीय इंडेक्स या चेक बाधा संभाल नहीं सकती है ट्रिगर का उपयोग करना है।

1

ओरेकल करता है। ओरेकल में इंडेक्स में बी वृक्ष द्वारा पूरी तरह से शून्य कुंजी को अनुक्रमित नहीं किया गया है, और ओरेकल अद्वितीय बाधाओं को लागू करने के लिए बी पेड़ इंडेक्स का उपयोग करता है।

एक मान लिया जाये कि ACTIVE_FLAG 1 पर सेट किया जा रहा पर आधारित संस्करण ID_COLUMN की कामना:

CREATE UNIQUE INDEX idx_versioning_id ON mytable 
    (CASE active_flag WHEN 0 THEN NULL ELSE active_flag END, 
    CASE active_flag WHEN 0 THEN NULL ELSE id_column END); 
2

विवरण जो अभी तक पूर्ण नहीं कर रहे हैं के मामले में, मैं एक ही तालिका में उन नहीं होगा के रूप में अंतिम रूप दिया विवरण। अंतिम तालिका में विवरण पर एक अद्वितीय अनुक्रमणिका या प्राथमिक कुंजी होगी।

सक्रिय/निष्क्रिय के मामले में, मेरे पास "संग्रह" या "इतिहास" तालिका के साथ अलग-अलग टेबल हो सकते हैं, लेकिन कम से कम एमएस एसक्यूएल सर्वर में ऐसा करने का एक और संभावित तरीका उपयोग के माध्यम से है अनुक्रमित दृश्य का:

CREATE TABLE Test_Conditionally_Unique 
(
    my_id INT NOT NULL, 
    active BIT NOT NULL DEFAULT 0 
) 
GO 
CREATE VIEW dbo.Test_Conditionally_Unique_View 
WITH SCHEMABINDING 
AS 
    SELECT 
     my_id 
    FROM 
     dbo.Test_Conditionally_Unique 
    WHERE 
     active = 1 
GO 
CREATE UNIQUE CLUSTERED INDEX IDX1 ON Test_Conditionally_Unique_View (my_id) 
GO 

INSERT INTO dbo.Test_Conditionally_Unique (my_id, active) 
VALUES (1, 0) 
INSERT INTO dbo.Test_Conditionally_Unique (my_id, active) 
VALUES (1, 0) 
INSERT INTO dbo.Test_Conditionally_Unique (my_id, active) 
VALUES (1, 0) 
INSERT INTO dbo.Test_Conditionally_Unique (my_id, active) 
VALUES (1, 1) 
INSERT INTO dbo.Test_Conditionally_Unique (my_id, active) 
VALUES (2, 0) 
INSERT INTO dbo.Test_Conditionally_Unique (my_id, active) 
VALUES (2, 1) 
INSERT INTO dbo.Test_Conditionally_Unique (my_id, active) 
VALUES (2, 1) -- This insert will fail 

आप इस विधि को नल/मूल्यवान विवरणों के लिए भी उपयोग कर सकते हैं।

+0

धन्यवाद, यह 2005 पर काम करता है, और मैं वास्तव में एक अलग समस्या पर आज अनुक्रमित विचारों के साथ बस गड़बड़ कर रहा था। यह वास्तव में एक महान आवेदन है! –

0

मैं आपके इच्छित उपयोग या आपकी तालिकाओं से पूरी तरह से अवगत नहीं हूं, लेकिन आप एक से एक रिश्ते का उपयोग करने का प्रयास कर सकते हैं। इस "कभी-कभी" अद्वितीय कॉलम को एक नई तालिका में विभाजित करें, नई तालिका में उस कॉलम पर यूनिक इंडेक्स बनाएं और मूल तालिका पीके का उपयोग करके मूल तालिका में FK वापस करें। "अद्वितीय" डेटा मौजूद होने पर केवल इस नई तालिका में एक पंक्ति होनी चाहिए।

पुराने टेबल:

TableA 
ID pk 
Col1 sometimes unique 
Col... 

नई टेबल:

TableA 
ID 
Col... 

TableB 
ID PK, FK to TableA.ID 
Col1 unique index 
संबंधित मुद्दे