মাইএসকিউএল বিদেশী কী বাধা, ক্যাসকেড মোছা


158

আমি সততা বজায় রাখতে এবং এতিমদের এড়াতে বিদেশী কীগুলি ব্যবহার করতে চাই (আমি ইতিমধ্যে নির্দোষ ডিবি ব্যবহার করেছি)।

আমি কীভাবে একটি এসকিউএল স্টেটমেন্ট করব যা ক্যাসকেডে মুছে ফেলা হয়?

আমি যদি কোনও বিভাগ মুছে ফেলি তবে আমি কীভাবে নিশ্চিত করব যে এটি অন্যান্য বিভাগগুলির সাথে সম্পর্কিত এমন পণ্যগুলি মুছে ফেলবে না।

পিভট টেবিল "বিভাগ_প্রোডাক্টগুলি" অন্য দুটি সারণীর মধ্যে একাধিক-বহু সম্পর্ক তৈরি করে।

categories
- id (INT)
- name (VARCHAR 255)

products
- id
- name
- price

categories_products
- categories_id
- products_id

হাই - আপনি প্রশ্নের শিরোনামটি সংশোধন করতে চাইতে পারেন, এটি ক্যাসকেড মুছে ফেলার বিষয়ে, বিশেষত পিভট টেবিলগুলি নয়।
প্যাডিস্ল্যাকার

উত্তর:


386

যদি আপনার ক্যাসকেডিং কোনও পণ্যটিকে মুছে দেয় কারণ এটি যে কোনও বিভাগের সদস্য নিহত হয়েছিল, তবে আপনি আপনার বিদেশী কীগুলি ভুলভাবে সেট আপ করেছেন। আপনার উদাহরণ সারণী দেওয়া, আপনার নিম্নলিখিত টেবিল সেটআপ করা উচিত:

CREATE TABLE categories (
    id int unsigned not null primary key,
    name VARCHAR(255) default null
)Engine=InnoDB;

CREATE TABLE products (
    id int unsigned not null primary key,
    name VARCHAR(255) default null
)Engine=InnoDB;

CREATE TABLE categories_products (
    category_id int unsigned not null,
    product_id int unsigned not null,
    PRIMARY KEY (category_id, product_id),
    KEY pkey (product_id),
    FOREIGN KEY (category_id) REFERENCES categories (id)
       ON DELETE CASCADE
       ON UPDATE CASCADE,
    FOREIGN KEY (product_id) REFERENCES products (id)
       ON DELETE CASCADE
       ON UPDATE CASCADE
)Engine=InnoDB;

এইভাবে, আপনি কোনও পণ্য বা একটি বিভাগ মুছতে পারেন, এবং কেবল শ্রেণি_র প্রোডাক্টগুলিতে যুক্ত সম্পর্কিত রেকর্ডগুলি পাশাপাশি মারা যাবে। ক্যাসকেড গাছের উপরে আরও ভ্রমণ করবে না এবং প্যারেন্ট পণ্য / বিভাগের সারণি মোছা হবে।

যেমন

products: boots, mittens, hats, coats
categories: red, green, blue, white, black

prod/cats: red boots, green mittens, red coats, black hats

আপনি যদি 'লাল' বিভাগটি মুছে ফেলেন তবে বিভাগ বিভাগে কেবলমাত্র 'লাল' প্রবেশের সাথে সাথে 'লাল রেট' এবং 'লাল রঙের' কোট দুটি প্রোডাক্ট / বিড়ালের পাশাপাশি মারা যাবে।

মোছাটি আরও দূরে ক্যাসকেড করবে না এবং 'বুট' এবং 'কোট' বিভাগগুলি গ্রহণ করবে না।

মন্তব্য অনুসরণ:

আপনি এখনও ভুল বোঝাবুঝি করছেন যে ক্যাসকেড কীভাবে কাজ মুছে দেয়। তারা কেবলমাত্র সেই টেবিলগুলিকেই প্রভাবিত করে যেখানে "মুছে ফেলা ক্যাসকেড" সংজ্ঞায়িত করা হয়েছে। এই ক্ষেত্রে, ক্যাসকেডটি "বিভাগগুলি_প্রডাক্টগুলি" সারণীতে সেট করা আছে। আপনি 'লাল' বিভাগ মুছে ফেলেন, তাহলে শুধুমাত্র রেকর্ডগুলি categories_products মোছার CASCADE হবে ঐ কোথায় আছেন category_id = red। এটি 'রেকর্ডিং_আইডি = নীল' এমন কোনও রেকর্ড স্পর্শ করবে না এবং এটি "পণ্যগুলি" টেবিলের দিকে ভ্রমণ করবে না, কারণ সেই টেবিলটিতে কোনও বিদেশী কী সংজ্ঞায়িত হয়নি।

আরও দৃ concrete় উদাহরণ এখানে:

categories:     products:
+----+------+   +----+---------+
| id | name |   | id | name    |
+----+------+   +----+---------+
| 1  | red  |   | 1  | mittens |
| 2  | blue |   | 2  | boots   |
+---++------+   +----+---------+

products_categories:
+------------+-------------+
| product_id | category_id |
+------------+-------------+
| 1          | 1           | // red mittens
| 1          | 2           | // blue mittens
| 2          | 1           | // red boots
| 2          | 2           | // blue boots
+------------+-------------+

ধরা যাক আপনি # 2 বিভাগ (নীল) মুছুন:

DELETE FROM categories WHERE (id = 2);

ডিবিএমএস সমস্ত টেবিলগুলিতে নজর রাখবে যেখানে 'বিভাগ' টেবিলের দিকে ইঙ্গিত করে একটি বিদেশী কী রয়েছে এবং ম্যাচিং আইডিটি যেখানে রয়েছে সেগুলি রেকর্ডগুলি মুছে ফেলবে, যেহেতু আমরা কেবলমাত্র বিদেশী কী সম্পর্কটিকে সংজ্ঞায়িত করেছি products_categories, আপনি একবার এই টেবিলটি দিয়ে শেষ করবেন মুছুন সম্পূর্ণ:

+------------+-------------+
| product_id | category_id |
+------------+-------------+
| 1          | 1           | // red mittens
| 2          | 1           | // red boots
+------------+-------------+

productsসারণীতে কোনও বিদেশী কী সংজ্ঞায়িত করা নেই , সুতরাং ক্যাসকেড সেখানে কাজ করবে না, সুতরাং আপনি বুট এবং মিটেনগুলি তালিকাভুক্ত পেয়েছেন। এখানে কেবল 'নীল বুট' নেই এবং 'নীল রঙের মিটেনস' নেই।


আমার মনে হয় আমি আমার প্রশ্নটি ভুলভাবে লিখেছি। আমি যদি কোনও বিভাগ মুছে ফেলি তবে আমি কীভাবে নিশ্চিত করব যে এটি অন্যান্য বিভাগগুলির সাথে সম্পর্কিত এমন পণ্যগুলি মুছে ফেলবে না।
চুডোস

36
এটি সত্যিই দুর্দান্ত, অত্যন্ত প্ররোচিত এবং আশ্চর্যজনকভাবে চিত্রিত উত্তর। সব লিখতে সময় দেওয়ার জন্য ধন্যবাদ।
স্কটব

2
টেবিলগুলি তৈরি করার সময়, আপনাকে InnoDB বা অন্য কোনও MySQL ইঞ্জিন নির্দিষ্ট করতে হবে যা CASCADEঅপারেশন করতে সক্ষম । অন্যথায় মাইএসকিউএল ডিফল্ট, মাইআইএসএএম, ব্যবহৃত হবে এবং মাইআইএসএএম CASCADEঅপারেশনগুলিকে সমর্থন করে না । এটি করতে, ENGINE InnoDBশেষের আগে কেবল যুক্ত করুন ;
প্যাট্রিক

11

আমি এই প্রশ্নের উত্তরে বিভ্রান্ত হয়ে পড়েছি, তাই আমি মাইএসকিউএলে একটি পরীক্ষার কেস তৈরি করেছি, আশা করি এটি সাহায্য করবে

-- Schema
CREATE TABLE T1 (
    `ID` int not null auto_increment,
    `Label` varchar(50),
    primary key (`ID`)
);

CREATE TABLE T2 (
    `ID` int not null auto_increment,
    `Label` varchar(50),
    primary key (`ID`)
);

CREATE TABLE TT (
    `IDT1` int not null,
    `IDT2` int not null,
    primary key (`IDT1`,`IDT2`)
);

ALTER TABLE `TT`
    ADD CONSTRAINT `fk_tt_t1` FOREIGN KEY (`IDT1`) REFERENCES `T1`(`ID`) ON DELETE CASCADE,
    ADD CONSTRAINT `fk_tt_t2` FOREIGN KEY (`IDT2`) REFERENCES `T2`(`ID`) ON DELETE CASCADE;

-- Data
INSERT INTO `T1` (`Label`) VALUES ('T1V1'),('T1V2'),('T1V3'),('T1V4');
INSERT INTO `T2` (`Label`) VALUES ('T2V1'),('T2V2'),('T2V3'),('T2V4');
INSERT INTO `TT` (`IDT1`,`IDT2`) VALUES
(1,1),(1,2),(1,3),(1,4),
(2,1),(2,2),(2,3),(2,4),
(3,1),(3,2),(3,3),(3,4),
(4,1),(4,2),(4,3),(4,4);

-- Delete
DELETE FROM `T2` WHERE `ID`=4; -- Delete one field, all the associated fields on tt, will be deleted, no change in T1
TRUNCATE `T2`; -- Can't truncate a table with a referenced field
DELETE FROM `T2`; -- This will do the job, delete all fields from T2, and all associations from TT, no change in T1

8

আমি মনে করি (আমি নিশ্চিত নই) যে বিদেশী কী সীমাবদ্ধতাগুলি আপনি আপনার টেবিলের নকশা দিয়েছিলেন তা ঠিক তেমনভাবে করবে না। সম্ভবত সর্বোত্তম কাজটি হ'ল কোনও সঞ্চিত প্রক্রিয়াটি সংজ্ঞায়িত করা যা কোনও বিভাগ যেমন আপনি চান সেইভাবে মুছে ফেলবে এবং তারপরে আপনি যখনই কোনও বিভাগ মুছতে চান সেই পদ্ধতিটি কল করুন।

CREATE PROCEDURE `DeleteCategory` (IN category_ID INT)
LANGUAGE SQL
NOT DETERMINISTIC
MODIFIES SQL DATA
SQL SECURITY DEFINER
BEGIN

DELETE FROM
    `products`
WHERE
    `id` IN (
        SELECT `products_id`
        FROM `categories_products`
        WHERE `categories_id` = category_ID
    )
;

DELETE FROM `categories`
WHERE `id` = category_ID;

END

লিঙ্কিং টেবিলে আপনাকে নিম্নলিখিত বিদেশী কী বাধাও যুক্ত করতে হবে:

ALTER TABLE `categories_products` ADD
    CONSTRAINT `Constr_categoriesproducts_categories_fk`
    FOREIGN KEY `categories_fk` (`categories_id`) REFERENCES `categories` (`id`)
    ON DELETE CASCADE ON UPDATE CASCADE,
    CONSTRAINT `Constr_categoriesproducts_products_fk`
    FOREIGN KEY `products_fk` (`products_id`) REFERENCES `products` (`id`)
    ON DELETE CASCADE ON UPDATE CASCADE

চুক্তি শৃঙ্খলা অবশ্যই, তৈরি টেবিল বিবৃতিতে উপস্থিত হতে পারে।

এই স্কিমা অবজেক্ট তৈরি করার পরে, আপনি একটি বিভাগ মুছে ফেলতে পারেন এবং ইস্যু করে আপনি CALL DeleteCategory(category_ID)যেখানে চান এমন আচরণটি পেতে পারেন (যেখানে বিভাগ_ID বিভাগটি মুছতে হবে), এবং এটি আপনার পছন্দমতো আচরণ করবে। তবে কোনও সাধারণ ইস্যু করবেন নাDELETE FROMতবে আপনি যদি আরও স্ট্যান্ডার্ড আচরণ না চান (তবে কেবল লিঙ্কিং টেবিল থেকে মুছুন এবং productsটেবিলটি একা রেখে দিন ) তবে ক্যোয়ারি ।


আমার মনে হয় আমি আমার প্রশ্নটি ভুলভাবে লিখেছি। আমি যদি কোনও বিভাগ মুছে ফেলি তবে আমি কীভাবে নিশ্চিত করব যে এটি অন্যান্য বিভাগগুলির সাথে সম্পর্কিত এমন পণ্যগুলি মুছে ফেলবে না।
চুডোস

ঠিক আছে, আমি মনে করি মার্ক বি এর উত্তর আপনি যা চান তা করে does
হামারাইট

হ্যালো @ হ্যামারাইট, আপনি দয়া করে আমাকে বলতে পারবেন যে গৃহীত উত্তরে KEY pkey (product_id),তৃতীয় CREATE TABLEক্যোয়ারির অর্থ কী ?
সিরাজ আলম
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.