সীমাবদ্ধ - একটি বুলিয়ান সারি সত্য, অন্য সমস্ত সারিটি মিথ্যা


13

আমার একটি কলাম রয়েছে: standard BOOLEAN NOT NULL

আমি এক সারি সত্য এবং অন্য সমস্ত মিথ্যা প্রয়োগ করতে চাই। এই সীমাবদ্ধতার উপর নির্ভর করে কোনও এফকে বা অন্য কিছু নেই। আমি জানি যে আমি এটি পিএলপি.এস.এস.এল. দিয়ে সম্পাদন করতে পারি তবে এটি স্লেজহ্যামারের মতো মনে হয়। আমি বাধা CHECKবা UNIQUEসীমাবদ্ধতার মতো কিছু পছন্দ করব । আরও সহজতর।

একটি সারি অবশ্যই সত্য হতে হবে, সেগুলি সমস্ত মিথ্যা হতে পারে না (সুতরাং প্রথম সারিটি rowোকানো সত্য হতে হবে)।

সারিটি আপডেট করা দরকার, যার অর্থ আপডেটগুলি হওয়া পর্যন্ত আমাকে বাধাগুলি পরীক্ষা করতে অপেক্ষা করতে হবে, কারণ সমস্ত সারিটি প্রথমে মিথ্যা এবং এক সারিটি সত্যই পরে সেট করা যেতে পারে।

তার মাঝে একটি এফ কে হয় products.tax_rate_idএবং tax_rate.id, কিন্তু এটা ডিফল্ট বা মানক ট্যাক্স হার, যা নতুন পণ্য তৈরি আরাম ব্যবহারকারী নির্বাচনযোগ্য সঙ্গে কিছুই করার আছে ..

পোস্টগ্র্রেএসকিউএল 9.5 এটি বিবেচনা করে।

পটভূমি

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

উপরের "ডিফল্ট" দ্বারা, আমি উপস্থাপনা স্তর (ইউআই) এর অর্থ। ডিফল্ট করের হার পরিবর্তন করার জন্য একটি ব্যবহারকারীর বিকল্প রয়েছে। GUI / ব্যবহারকারী কর_রেট_আইডিকে NULL এ সেট করার চেষ্টা করে না, বা কেবলমাত্র একটি ডিফল্ট করের হার সেট করে তা নিশ্চিত করার জন্য আমাকে অতিরিক্ত চেক যোগ করতে হবে।


তাহলে আপনার কি আপনার উত্তর আছে?
এরউইন ব্র্যান্ডস্টেটার

হ্যাঁ আমার কাছে আমার উত্তর আছে, আপনার ইনপুটটির জন্য অনেক ধন্যবাদ, @ ইরভিন ব্র্যান্ডসেটেটার। আমি আপাতত একটি ট্রিগার দিকে ঝুঁকছি। এটি আমার নিজের সময়ে একটি ওপেন সোর্স প্রকল্প। আমি যখন এটি বাস্তবায়ন করি তখন আমি যে উত্তরটি ব্যবহার করি তা চিহ্নিত করব mark
দ্য জিটিকনার্ড

উত্তর:


15

বৈকল্পিক ঘ

যেহেতু আপনার যা দরকার তা হ'ল একক কলাম যার সাথে standard = trueসমস্ত অন্যান্য সারিগুলিতে নুলকে মান সেট করুন। তারপরে একটি সরল UNIQUEসীমাবদ্ধতা কাজ করে, যেহেতু NULL মানগুলি লঙ্ঘন করে না:

CREATE TABLE taxrate (
   taxrate int PRIMARY KEY
 , standard bool DEFAULT true
 , CONSTRAINT standard_true_or_null CHECK (standard) -- yes, that's the whole constraint
 , CONSTRAINT standard_only_1_true UNIQUE (standard)
);

DEFAULTএকটি rowচ্ছিক অনুস্মারক যা প্রথম সারিটি প্রবেশ করানো ডিফল্ট হয়ে যায়। এটি কিছুই প্রয়োগ করছে না । আপনি এতে একাধিক সারি সেট করতে পারবেন না standard = true, আপনি এখনও সমস্ত সারিটি নাল সেট করতে পারেন। একক টেবিলের মধ্যে কেবল বাধা দিয়ে এটিকে প্রতিরোধের কোনও পরিষ্কার উপায় নেই । CHECKসীমাবদ্ধতাগুলি অন্য সারিগুলি বিবেচনা করে না (নোংরা কৌশল ছাড়া)।

সম্পর্কিত:

আপডেট:

BEGIN;
UPDATE taxrate SET standard = NULL WHERE standard;
UPDATE taxrate SET standard = TRUE WHERE taxrate = 2;
COMMIT;

কোনও কমান্ডের অনুমতি দেওয়ার জন্য (যেখানে সীমাবদ্ধতা কেবলমাত্র বিবৃতিটির শেষে সন্তুষ্ট হয়):

WITH kingdead AS (
   UPDATE taxrate
   SET standard = NULL
   WHERE standard
   )
UPDATE taxrate
SET standard = TRUE
WHERE taxrate = 1;

.. UNIQUEসীমাবদ্ধতা হতে হবে DEFERRABLE। দেখা:

এখানে ডিবিফিডল

বৈকল্পিক 2

একটি আছে দ্বিতীয় টেবিল মত একটি একক সারি সঙ্গে

এটি সুপারভাইজার হিসাবে তৈরি করুন:

CREATE TABLE taxrate (
   taxrate int PRIMARY KEY
);

CREATE TABLE taxrate_standard (
   taxrate int PRIMARY KEY REFERENCES taxrate
);

CREATE UNIQUE INDEX taxrate_standard_singleton ON taxrate_standard ((true));  -- singleton

REVOKE DELETE ON TABLE taxrate_standard FROM public;  -- can't delete

INSERT INTO taxrate (taxrate) VALUES (42);
INSERT INTO taxrate_standard (taxrate) VALUES (42);

এখন সর্বদা একটি একক সারি স্ট্যান্ডার্ডের দিকে নির্দেশ করে থাকে (এই সাধারণ ক্ষেত্রে এছাড়াও স্ট্যান্ডার্ড হারকে সরাসরি উপস্থাপন করে)। কেবলমাত্র কোনও সুপারইসার এটি ভেঙে দিতে পারে। আপনি এটি একটি ট্রিগার সহও অস্বীকার করতে পারেন BEFORE DELETE

এখানে ডিবিফিডল

সম্পর্কিত:

আপনি বৈকল্পিক 1 এরVIEW মতো দেখতে একটি যুক্ত করতে পারেন :

CREATE VIEW taxrate_combined AS
SELECT t.*, (ts.taxrate = t.taxrate) AS standard
FROM   taxrate t
LEFT   JOIN taxrate_standard ts USING (taxrate);

অনুসন্ধানগুলিতে যেখানে আপনি যা চান তা হ'ল স্ট্যান্ডার্ড রেট, taxrate_standard.taxrateসরাসরি (কেবল) ব্যবহার করুন ।


আপনি পরে যোগ করেছেন:

products.tax_rate_idএবং এর মধ্যে একটি এফকে রয়েছেtax_rate.id

কোনও দরিদ্র ব্যক্তির বৈকল্পিক 2 বাস্তবায়ন হ'ল productsস্ট্যান্ডার্ড ট্যাক্স হারের দিকে ইঙ্গিত করে কেবল (বা কোনও অনুরূপ টেবিল) একটি সারি যুক্ত করা হবে ; একটি ডামি পণ্য আপনি "স্ট্যান্ডার্ড ট্যাক্স রেট" কল করতে পারেন - যদি আপনার সেটআপ এটির অনুমতি দেয়।

এফকে সীমাবদ্ধতাগুলি রেফারেনশিয়াল অখণ্ডতা প্রয়োগ করে। এটি সম্পূর্ণ করতে, tax_rate_id IS NOT NULLসারিটির জন্য কার্যকর করুন (যদি কলামের ক্ষেত্রে এটি সাধারণভাবে না হয়)। এবং এটি মুছে ফেলার অনুমতি দিন। উভয় ট্রিগার মধ্যে রাখা যেতে পারে। কোনও অতিরিক্ত টেবিল নয়, তবে কম মার্জিত এবং নির্ভরযোগ্য নয়।


2
দুটি টেবিল পদ্ধতির উচ্চভাবে সুপারিশ করুন। আমি সেই পরিবর্তনের সাথে উদাহরণ কোয়েরি যুক্ত করার পরামর্শ দিই যাতে ওপি দেখতে পাবে যে CROSS JOINস্ট্যান্ডার্ডের LEFT JOINসাথে কীভাবে নির্দিষ্ট, এবং তারপরে COALESCEদু'জনের মধ্যে কীভাবে করা যায়।
jpmc26

2
+1, অতিরিক্ত টেবিল সম্পর্কে আমার একই ধারণা ছিল তবে সঠিকভাবে উত্তর লেখার কোনও সময় নেই। প্রথম টেবিল এবং তার সম্পর্কে CONSTRAINT standard_only_1_true UNIQUE (standard): আমি মনে করি যে টেবিলটি বড় হবে না তাই এটি খুব বেশি গুরুত্ব দেয় না তবে যেহেতু প্রতিবন্ধকতা পুরো টেবিলটিতে একটি সূচককে সংজ্ঞায়িত করবে, তাই কি WHERE (standard)কম স্থানের ব্যবহারের সাথে আংশিক অনন্য সূচকটি তৈরি হবে না ?
ypercubeᵀᴹ

@ ইয়পারক्यूबᵀᴹ: হ্যাঁ, পুরো টেবিলের সূচকটি বড়, এটি এই বৈকল্পিকের জন্য একটি অপূর্ণতা। তবে আপনি যেমন বলেছেন: এটি অবশ্যই একটি ছোট্ট টেবিল, সুতরাং এটি খুব কমই গুরুত্বপূর্ণ। আমি কেবল সীমাবদ্ধতার সাথে সিম্পল স্ট্যান্ডার্ড সমাধানের লক্ষ্যে ছিলাম। ধারণার প্রমাণ. ব্যক্তিগতভাবে, আমি jpmc26 এর সাথে আছি এবং দৃ var়রূপে বৈকল্পিক 2 এর পক্ষে আছি favor
এরউইন ব্র্যান্ডসেটেটার

9

আপনি একটি ফিল্টারড সূচক ব্যবহার করতে পারেন

create table test
(
    id int primary key,
    foo bool
);
CREATE UNIQUE INDEX only_one_row_with_column_true_uix 
    ON test (foo) WHERE (foo);  --> where foo is true
insert into test values (1, false);
insert into test values (2, true);
insert into test values (3, false);
insert into test values (4, false);
insert into test values (5, true);
ত্রুটি: সদৃশ কী মানটি অনন্য সীমাবদ্ধতা লঙ্ঘন করে "কেবল_আপনি_আর_পথ_কলাম_তুই_উইকস"
বিশদ: কী (foo) = (টি) ইতিমধ্যে বিদ্যমান।

এখানে ডিবিফিডল


তবে যেমনটি আপনি বলেছেন, প্রথম সারিতে অবশ্যই সত্য হওয়া উচিত, তারপরে আপনি একটি চেক সীমাবদ্ধতা ব্যবহার করতে পারেন, তবে এমনকি কোনও ফাংশন ব্যবহার করে আপনি প্রথম সারিটি পরে মুছতে পারেন।

create function check_one_true(new_foo bool)
returns int as
$$
begin
    return 
    (
        select count(*) + (case new_foo when true then 1 else 0 end)
        from test 
        where foo = true
    );
end
$$
language plpgsql stable;
alter table test 
    add constraint ck_one_true check(check_one_true(foo) = 1); 
insert into test values (1, true);
insert into test values (2, false);
insert into test values (3, false);
insert into test values (4, false);
insert into test values (5, true);
ত্রুটি: সম্পর্কের জন্য নতুন সারি "পরীক্ষা" চেক সীমাবদ্ধতা লঙ্ঘন করে "ck_one_true"
বিবরণ: ব্যর্থ সারিতে (5, টি) রয়েছে।

select * from test;
আইডি | foo বিন্যাস
-: | : -
 1 | টি  
 2 | চ  
 3 | চ  
 4 | চ  
delete from test where id = 1;

এখানে ডিবিফিডল


প্রথম সারি (foo সত্য) কখনও মুছে ফেলা না হয় তা নিশ্চিত করার জন্য আপনি বিফোর ডিলিট ট্রিগার যোগ করে এটি সমাধান করতে পারেন।

create function dont_delete_foo_true()
returns trigger as
$x$
begin
    if old.foo then
        raise exception 'Can''t delete row where foo is true.';
    end if;
    return old;
end;
$x$ language plpgsql;
create trigger trg_test_delete
before delete on test
for each row 
execute procedure dont_delete_foo_true();
delete from test where id = 1;

ত্রুটি: foo সত্য যেখানে সারি মুছতে পারে না।

এখানে ডিবিফিডল

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.