উত্তর:
আপনার যা প্রয়োজন তা অবৈধ বয়স শর্তটি ধরার জন্য দুটি ট্রিগার
মাইএসকিউএল ট্র্যাগারদের জন্য মাইএসকিউএল স্টোরার্ড প্রসেসার প্রোগ্রামিং বইয়ের পৃষ্ঠা 254-256 থেকে 'ট্রিগারদের সাথে বৈধকরণের ডেটা' শীর্ষক শিরোনামের অধীনে মাইএসকিউএল ট্রিগারদের জন্য জেরি-রগযুক্ত ত্রুটি ট্র্যাপিং পদ্ধতির উপর ভিত্তি করে :
drop table mytable;
create table mytable (
id smallint unsigned AUTO_INCREMENT,
age tinyint not null,
primary key(id)
);
DELIMITER $$
CREATE TRIGGER checkage_bi BEFORE INSERT ON mytable FOR EACH ROW
BEGIN
DECLARE dummy,baddata INT;
SET baddata = 0;
IF NEW.age > 20 THEN
SET baddata = 1;
END IF;
IF NEW.age < 1 THEN
SET baddata = 1;
END IF;
IF baddata = 1 THEN
SELECT CONCAT('Cannot Insert This Because Age ',NEW.age,' is Invalid')
INTO dummy FROM information_schema.tables;
END IF;
END; $$
CREATE TRIGGER checkage_bu BEFORE UPDATE ON mytable FOR EACH ROW
BEGIN
DECLARE dummy,baddata INT;
SET baddata = 0;
IF NEW.age > 20 THEN
SET baddata = 1;
END IF;
IF NEW.age < 1 THEN
SET baddata = 1;
END IF;
IF baddata = 1 THEN
SELECT CONCAT('Cannot Update This Because Age ',NEW.age,' is Invalid')
INTO dummy FROM information_schema.tables;
END IF;
END; $$
DELIMITER ;
insert into mytable (age) values (10);
insert into mytable (age) values (15);
insert into mytable (age) values (20);
insert into mytable (age) values (25);
insert into mytable (age) values (35);
select * from mytable;
insert into mytable (age) values (5);
select * from mytable;
ফলাফল এখানে:
mysql> drop table mytable;
Query OK, 0 rows affected (0.03 sec)
mysql> create table mytable (
-> id smallint unsigned AUTO_INCREMENT,
-> age tinyint not null,
-> primary key(id)
-> );
Query OK, 0 rows affected (0.06 sec)
mysql> DELIMITER $$
mysql> CREATE TRIGGER checkage_bi BEFORE INSERT ON mytable FOR EACH ROW
-> BEGIN
-> DECLARE dummy,baddata INT;
-> SET baddata = 0;
-> IF NEW.age > 20 THEN
-> SET baddata = 1;
-> END IF;
-> IF NEW.age < 1 THEN
-> SET baddata = 1;
-> END IF;
-> IF baddata = 1 THEN
-> SELECT CONCAT('Cannot Insert This Because Age ',NEW.age,' is Invalid')
-> INTO dummy FROM information_schema.tables;
-> END IF;
-> END; $$
Query OK, 0 rows affected (0.08 sec)
mysql> CREATE TRIGGER checkage_bu BEFORE UPDATE ON mytable FOR EACH ROW
-> BEGIN
-> DECLARE dummy,baddata INT;
-> SET baddata = 0;
-> IF NEW.age > 20 THEN
-> SET baddata = 1;
-> END IF;
-> IF NEW.age < 1 THEN
-> SET baddata = 1;
-> END IF;
-> IF baddata = 1 THEN
-> SELECT CONCAT('Cannot Update This Because Age ',NEW.age,' is Invalid')
-> INTO dummy FROM information_schema.tables;
-> END IF;
-> END; $$
Query OK, 0 rows affected (0.07 sec)
mysql> DELIMITER ;
mysql> insert into mytable (age) values (10);
Query OK, 1 row affected (0.06 sec)
mysql> insert into mytable (age) values (15);
Query OK, 1 row affected (0.05 sec)
mysql> insert into mytable (age) values (20);
Query OK, 1 row affected (0.04 sec)
mysql> insert into mytable (age) values (25);
ERROR 1172 (42000): Result consisted of more than one row
mysql> insert into mytable (age) values (35);
ERROR 1172 (42000): Result consisted of more than one row
mysql> select * from mytable;
+----+-----+
| id | age |
+----+-----+
| 1 | 10 |
| 2 | 15 |
| 3 | 20 |
+----+-----+
3 rows in set (0.00 sec)
mysql> insert into mytable (age) values (5);
Query OK, 1 row affected (0.07 sec)
mysql> select * from mytable;
+----+-----+
| id | age |
+----+-----+
| 1 | 10 |
| 2 | 15 |
| 3 | 20 |
| 4 | 5 |
+----+-----+
4 rows in set (0.00 sec)
mysql>
দয়া করে এটিও লক্ষ্য করুন যে অটো বর্ধিত মানগুলি নষ্ট হয় না বা হারিয়ে যায় না।
একবার চেষ্টা করে দেখো !!!
মাইএসকিউএলে চেক সীমাবদ্ধতা প্রয়োগ করা হয় না। তৈরি টেবিল থেকে
CHECK ধারাটি পার্স করা হয়েছে তবে সমস্ত স্টোরেজ ইঞ্জিন এড়িয়ে চলেছে। বিভাগ 12.1.17, "টেবিল সিনট্যাক্স তৈরি করুন" দেখুন। বাক্য সংজ্ঞাটি গ্রহণ করার বা উপেক্ষা করার কারণটি অন্যান্য এসকিউএল সার্ভারের থেকে পোর্ট কোড করা সহজতর করা, এবং অ্যাপ্লিকেশনগুলি চালিত করা উচিত যা রেফারেন্স সহ সারণী তৈরি করে। বিভাগ 1.8.5, "স্ট্যান্ডার্ড এসকিউএল থেকে মাইএসকিউএল পার্থক্য" দেখুন।
এটি প্রায় 8 বছর ধরে রিপোর্ট করা বাগ ...
@ রোল্যান্ডোর চমৎকার ট্রিগার সমাধান ছাড়াও মাইএসকিউএলে এই সমস্যাটির আরও একটি সমাধান রয়েছে (যতক্ষণ না CHECK
সীমাবদ্ধতা প্রয়োগ করা হয়)।
CHECK
মাইএসকিউএল-তে কিছু সীমাবদ্ধতা কীভাবে অনুকরণ করা যায়
সুতরাং, আপনি যদি রেফারেন্সিয়াল অখণ্ডতা বাধা পছন্দ করেন এবং ট্রিগারগুলি এড়াতে চান (মাইএসকিউএল সংক্রান্ত সমস্যাগুলির কারণে যখন আপনার টেবিলে উভয় থাকে) তবে আপনি অন্য একটি ছোট রেফারেন্স টেবিল ব্যবহার করতে পারেন:
CREATE TABLE age_allowed
( age TINYINT UNSIGNED NOT NULL
, PRIMARY KEY (age)
) ENGINE = InnoDB ;
এটি 20 সারি দিয়ে পূরণ করুন:
INSERT INTO age_allowed
(age)
VALUES
(0), (1), (2), (3), ..., (19) ;
তারপরে আপনার টেবিলটি হ'ল:
CREATE TABLE test
( id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT
, age TINYINT UNSIGNED NOT NULL
, PRIMARY KEY (id)
, CONSTRAINT age_allowed__in__test
FOREIGN KEY (age)
REFERENCES age_allowed (age)
) ENGINE = InnoDB ;
age_allowed
দুর্ঘটনাক্রমে যুক্ত হওয়া বা সারিগুলি সরাতে এড়াতে আপনাকে সারণিতে লেখার অ্যাক্সেস সরিয়ে ফেলতে হবে ।
FLOAT
দুর্ভাগ্যক্রমে ( 0.0
এবং এর মধ্যে খুব বেশি মানের 20.0
) এই কৌশলটি ডেটাটাইপ কলামগুলির সাথে কাজ করবে না ।
CHECK
মাইএসকিউএল (5.7) এবং মারিয়াডিবিতে স্বেচ্ছাসেবী সীমাবদ্ধতাগুলি কীভাবে অনুকরণ করা যায় (5.2 থেকে 10.1 পর্যন্ত)
যেহেতু মারিয়াডিবি তাদের 5.2 সংস্করণে (জিএ রিলিজ: 2010-11-10 ) এবং মাইএসকিউএল 5.7 (জিএ প্রকাশ: 2015-10-21 ) - তে তারা গণনা করেছে VIRTUAL
এবং এটি GENERATED
যথাক্রমে - যা স্থায়ী হতে পারে, যেমন টেবিল - তারা তাদের কল করে PERSISTENT
এবং STORED
যথাক্রমে - আমরা উপরের সমাধানটি আরও সহজতর করতে এবং আরও ভাল, নির্বিচারে CHECK
সীমাবদ্ধতাগুলি অনুকরণ / প্রয়োগ করতে এটি প্রসারিত করতে পারি ):
উপরের হিসাবে, আমাদের একটি সহায়তা টেবিলের প্রয়োজন হবে তবে এই বারে একটি একক সারিতে এটি "অ্যাঙ্কর" টেবিল হিসাবে অভিনয় করবে। আরও ভাল, এই টেবিলটি যে কোনও সংখ্যক CHECK
বাধার জন্য ব্যবহার করা যেতে পারে ।
তারপরে আমরা একটি গণিত কলাম যুক্ত করব যা একেবারে TRUE
/ FALSE
/ UNKNOWN
হিসাবে মূল্যায়ন করে ঠিক CHECK
হ'ল বাধা হিসাবে - তবে এই কলামটি FOREIGN KEY
আমাদের অ্যাঙ্কর টেবিলের প্রতিবন্ধকতা রয়েছে। যদি শর্ত / কলামটি FALSE
কয়েকটি সারিটির জন্য মূল্যায়ন করে তবে সিরকগুলি FK- এর কারণে প্রত্যাখ্যান করা হয়।
যদি শর্ত / কলামটি এর ( TRUE
বা ) মূল্যায়ন করে তবে সীমাগুলি যেমন প্রত্যাখ্যানের সাথে ঘটেছিল ঠিক তেমনটি প্রত্যাখ্যান করা হবে না :UNKNOWN
NULL
CHECK
CREATE TABLE truth
( t BIT NOT NULL,
PRIMARY KEY (t)
) ENGINE = InnoDB ;
-- Put a single row:
INSERT INTO truth (t)
VALUES (TRUE) ;
-- Then your table would be:
-- (notice the change to `FLOAT`, to prove that we don't need)
-- (to restrict the solution to a small type)
CREATE TABLE test
( id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
age FLOAT NOT NULL,
age_is_allowed BIT -- GENERATED ALWAYS
AS (age >= 0 AND age < 20) -- our CHECK constraint
STORED,
PRIMARY KEY (id),
CONSTRAINT check_age_must_be_non_negative_and_less_than_20
FOREIGN KEY (age_is_allowed)
REFERENCES truth (t)
) ENGINE = InnoDB ;
উদাহরণটি মাইএসকিউএল 5.7 সংস্করণের জন্য। মারিয়াডিবিতে (10.1 অবধি সংস্করণ 5.2+), আমাদের কেবল বাক্য গঠনটি সংশোধন করতে হবে এবং এর PERSISTENT
পরিবর্তে কলামটি ঘোষণা করতে হবে STORED
। সংস্করণ 10.2 এ STORED
কীওয়ার্ডটিও যুক্ত করা হয়েছিল, সুতরাং উপরের উদাহরণটি সর্বশেষ সংস্করণগুলির জন্য উভয় স্বাদে (মাইএসকিউএল এবং মারিয়াডিবি) কাজ করে।
আমরা যদি অনেকগুলি CHECK
প্রতিবন্ধকতা প্রয়োগ করতে চাই (যা অনেকগুলি ডিজাইনে সাধারণ), আমরা কেবল তাদের প্রত্যেকটির জন্য একটি গণিত কলাম এবং একটি বিদেশী কী যুক্ত করতে হবে। আমাদের কেবল truth
ডাটাবেসে একটি টেবিলের প্রয়োজন । এটিতে একটি সারি sertedোকানো উচিত এবং তারপরে সমস্ত লেখার অ্যাক্সেস সরানো উচিত।
তবে সর্বশেষতম মারিয়াডিবি-তে, আমাদের আর এই সমস্ত অ্যাক্রোব্যাটিকস আর সম্পাদন করতে হবে না, কারণ CHECK
সীমাবদ্ধতাগুলি 10.2.1 সংস্করণে প্রয়োগ করা হয়েছে (আলফা প্রকাশ: 2016-জুলাই -04)!
বর্তমান 10.2.2 সংস্করণটি এখনও বিটা সংস্করণ তবে এটি মনে হয় যে বৈশিষ্ট্যটি মারিয়াডিবি 10.2 সিরিজের প্রথম স্থিতিশীল প্রকাশে উপলব্ধ হবে।
আমি যেমন এই নিবন্ধে ব্যাখ্যা করেছি , সংস্করণ 8.0.16 দিয়ে শুরু করে, মাইএসকিউএল কাস্টম চেক সীমাবদ্ধতার জন্য সমর্থন যোগ করেছে:
ALTER TABLE topic
ADD CONSTRAINT post_content_check
CHECK (
CASE
WHEN DTYPE = 'Post'
THEN
CASE
WHEN content IS NOT NULL
THEN 1
ELSE 0
END
ELSE 1
END = 1
);
ALTER TABLE topic
ADD CONSTRAINT announcement_validUntil_check
CHECK (
CASE
WHEN DTYPE = 'Announcement'
THEN
CASE
WHEN validUntil IS NOT NULL
THEN 1
ELSE 0
END
ELSE 1
END = 1
);
পূর্বে, এটি কেবল আগে প্রবেশের আগে এবং আপডেটের আগে ট্রিগারগুলি ব্যবহার করে উপলভ্য ছিল:
CREATE
TRIGGER post_content_check BEFORE INSERT
ON topic
FOR EACH ROW
BEGIN
IF NEW.DTYPE = 'Post'
THEN
IF NEW.content IS NULL
THEN
signal sqlstate '45000'
set message_text = 'Post content cannot be NULL';
END IF;
END IF;
END;
CREATE
TRIGGER post_content_update_check BEFORE UPDATE
ON topic
FOR EACH ROW
BEGIN
IF NEW.DTYPE = 'Post'
THEN
IF NEW.content IS NULL
THEN
signal sqlstate '45000'
set message_text = 'Post content cannot be NULL';
END IF;
END IF;
END;
CREATE
TRIGGER announcement_validUntil_check BEFORE INSERT
ON topic
FOR EACH ROW
BEGIN
IF NEW.DTYPE = 'Announcement'
THEN
IF NEW.validUntil IS NULL
THEN
signal sqlstate '45000'
set message_text = 'Announcement validUntil cannot be NULL';
END IF;
END IF;
END;
CREATE
TRIGGER announcement_validUntil_update_check BEFORE UPDATE
ON topic
FOR EACH ROW
BEGIN
IF NEW.DTYPE = 'Announcement'
THEN
IF NEW.validUntil IS NULL
THEN
signal sqlstate '45000'
set message_text = 'Announcement validUntil cannot be NULL';
END IF;
END IF;
END;
8.0.16 এর পূর্বে মাইএসকিউএল সংস্করণগুলির জন্য ডাটাবেস ট্রিগারগুলি ব্যবহার করে চেক সীমাবদ্ধতাগুলি সম্পর্কে আরও বিশদের জন্য, তারপরে এই নিবন্ধটি দেখুন ।