كيف يمكنني تقييد أعمدة متعددة لمنع التكرار، ولكن تجاهل القيم الخالية؟

StackOverflow https://stackoverflow.com/questions/675398

سؤال

وهنا قليلا التجربة ركضت في قاعدة بيانات أوراكل (10G). وبصرف النظر عن الراحة التنفيذ (أوراكل)، وأنا لا يمكن معرفة لماذا تقبل بعض الملاحق ورفض الآخرين.

create table sandbox(a number(10,0), b number(10,0));
create unique index sandbox_idx on sandbox(a,b);

insert into sandbox values (1,1); -- accepted
insert into sandbox values (1,2); -- accepted
insert into sandbox values (1,1); -- rejected

insert into sandbox values (1,null); -- accepted
insert into sandbox values (2,null); -- accepted
insert into sandbox values (1,null); -- rejected

insert into sandbox values (null,1); -- accepted
insert into sandbox values (null,2); -- accepted
insert into sandbox values (null,1); -- rejected

insert into sandbox values (null,null); -- accepted
insert into sandbox values (null,null); -- accepted

وإذا افترضنا أنه من المنطقي أن يكون في بعض الأحيان بعض الصفوف مع بعض القيم العمود المجهول، أستطيع أن أفكر في حالتين استخدام المحتملة التي تنطوي على التكرارات منع:
 1. أريد أن رفض مكررة، ولكن عندما تقبل قيمة أي عمود مقيدة وغير معروف.
 2. أريد أن رفض التكرارات، حتى في الحالات التي يكون فيها قيمة عمود مقيدة وغير معروف.

ويبدو أوراكل تنفذ شيئا مختلفا على الرغم من:
 3. رفض مكررة، ولكنها تقبل (فقط) عندما <م> جميع قيم العمود مقيدة غير معروفة.

ويمكنني التفكير في طرق للاستفادة من تنفيذ أوراكل للوصول الى استخدام القضية (2) - على سبيل المثال، لها قيمة خاصة ل"غير معروف"، وجعل الأعمدة غير قيم الفارغة. ولكن لا يمكنني معرفة كيفية الحصول على استخدام حالة (1).

وبعبارة أخرى، كيف يمكنني الحصول على أوراكل لعمل مثل هذا؟

create table sandbox(a number(10,0), b number(10,0));
create unique index sandbox_idx on sandbox(a,b);

insert into sandbox values (1,1); -- accepted
insert into sandbox values (1,2); -- accepted
insert into sandbox values (1,1); -- rejected

insert into sandbox values (1,null); -- accepted
insert into sandbox values (2,null); -- accepted
insert into sandbox values (1,null); -- accepted

insert into sandbox values (null,1); -- accepted
insert into sandbox values (null,2); -- accepted
insert into sandbox values (null,1); -- accepted

insert into sandbox values (null,null); -- accepted
insert into sandbox values (null,null); -- accepted
هل كانت مفيدة؟

المحلول 2

create unique index sandbox_idx on sandbox
 (case when a is null or b is null then null else a end,
  case when a is null or b is null then null else b end);

وهناك مؤشر وظيفي! أساسا أنا فقط بحاجة للتأكد من أن جميع الصفوف أريد أن تجاهل (أي - قبول) الحصول على ترجمتها إلى جميع بلا قيم. قبيحة، ولكن ليس بعقب القبيح. يعمل كما تريد.

وترد عليها بمساعدة حل لسؤال آخر: <لأ href = "https://stackoverflow.com/questions/182262/how-to-constrain-a-database-table-so-only-one -row يمكن أن يكون بين واحد في معين القيمة في "> كيفية تقييد جدول قاعدة بيانات حتى صف واحد فقط يمكن أن يكون لها قيمة خاصة في عمود؟

وهكذا ذهبت إلى هناك وإعطاء توني اندروز يشير أيضا. :)

نصائح أخرى

وحاول المؤشر القائم على وظيفة:

وإنشاء فهرس فريد sandbox_idx على رمل (CASE WHEN لIS NULL THEN NULL عندما ب فارغة فارغة THEN ELSE و|| '،' || ب END)؛

وهناك طرق أخرى لسلخ هذا القط، ولكن هذا هو واحد منهم.

وأنا لست الرجل أوراكل، ولكن هنا فكرة التي يجب أن تعمل، إذا كنت تستطيع تضمين عمود محسوب في فهرس في أوراكل.

إضافة عمود إضافي إلى الجدول الخاص بك (وفهرس فريد بك) التي يتم حسابها على النحو التالي: انها فارغة إذا كان كل من a و b غير NULL، وانها المفتاح الأساسي للجدول خلاف ذلك. وأنا أسمي هذا العمود "nullbuster" إضافية لأسباب واضحة.

alter table sandbox add nullbuster as 
  case when a is null or b is null then pk else null end;
create unique index sandbox_idx on sandbox(a,b,pk);

وأعطى هذا المثال عددا من المرات حوالي العام 2002 أو نحو ذلك في microsoft.public.sqlserver.programming مجموعة Usenet. يمكنك العثور على مناقشات إذا كنت تبحث groups.google.com عن كلمة "nullbuster". حقيقة أن كنت تستخدم أوراكل لا ينبغي أن يهم كثيرا.

.

<القوي> P.S في SQL Server، يتم إلى حد ما محل هذا الحل كثيرا الفهارس التي تمت تصفيتها:

create unique index sandbox_idx on sandbox(a,b)
(where a is not null and b is not null);

والخيط الذي أشرت إليه تشير إلى أن أوراكل لا يوفر لك هذا الخيار. هل أيضا ليس لديهم إمكانية عرض مفهرس، وهو بديل آخر؟

create view sandbox_for_unique as
select a, b from sandbox
where a is not null and b is not null;

create index sandbox_for_unique_idx on sandbox_for_unique(a,b);

واعتقد انك تستطيع بعد ذلك.

وفقط للسجل على الرغم من أنني أترك الفقرة جهدي لشرح لماذا يتصرف أوراكل من هذا القبيل إذا كان لديك فهرس فريد بسيط على عمودين:

وأوراكل لن نقبل أبدا اثنين (1، فارغة) أزواج إذا المفهرسة الأعمدة بشكل فريد.

وزوج من 1 ويعتبر لاغيا، وهو "فهرسة" زوج. زوج من اثنين بلا قيم لا يمكن فهرستها، وهذا هو السبب في أنه يتيح لك إدراج العديد من لاغية، وأزواج فارغة كما تريد.

و(1، فارغة) يحصل على فهرسة بسبب 1 يمكن فهرستها. في المرة القادمة التي تحاول إدراج (1، لاغية) مرة أخرى (1)، والتقطت تلاه مؤشر ويتم انتهاك قيد فريد.

و(خالية، خالية) لم تتم فهرسة لأنه لا يوجد قيمة ليتم فهرستها. هذا هو السبب في أنها لا تنتهك قيد فريد.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top