मैं मौजूदा SQLite तालिका में एक विदेशी कुंजी कैसे जोड़ूं?


128

मेरे पास निम्न तालिका है:

CREATE TABLE child( 
  id INTEGER PRIMARY KEY, 
  parent_id INTEGER, 
  description TEXT);

मैं एक विदेशी कुंजी बाधा कैसे जोड़ूं parent_id? मान लें कि विदेशी कुंजियाँ सक्षम हैं।

अधिकांश उदाहरण मान लेते हैं कि आप तालिका बना रहे हैं - मैं एक मौजूदा में बाधा जोड़ना चाहूंगा।


SQLite ALTER कमांड केवल "नाम बदलें तालिका" और "कॉलम जोड़ें" का समर्थन करता है। हालाँकि, हम संचालन के सरल अनुक्रम का उपयोग करके तालिका के प्रारूप में अन्य मनमाने बदलाव कर सकते हैं। चेक मेरा उत्तर
situee

जवाबों:


198

आप नहीं कर सकते।

यद्यपि आपकी तालिका में एक विदेशी कुंजी जोड़ने के लिए SQL-92 सिंटैक्स निम्नानुसार होगा:

ALTER TABLE child ADD CONSTRAINT fk_child_parent
                  FOREIGN KEY (parent_id) 
                  REFERENCES parent(id);

SQLite कमांड के ADD CONSTRAINTसंस्करण का समर्थन नहीं करता हैALTER TABLE ( sqlite.org: SQL विशेषताएँ जो SQLite लागू नहीं करता है )।

इसलिए, एक विदेशी कुंजी को sqlite 3.6.1 में जोड़ने का एकमात्र तरीका CREATE TABLEनिम्नानुसार है:

CREATE TABLE child ( 
    id           INTEGER PRIMARY KEY, 
    parent_id    INTEGER, 
    description  TEXT,
    FOREIGN KEY (parent_id) REFERENCES parent(id)
);

दुर्भाग्य से आपको मौजूदा डेटा को एक अस्थायी तालिका में सहेजना होगा, पुरानी तालिका को छोड़ना होगा, नई तालिका को FK बाधा के साथ बनाना होगा, फिर अस्थायी तालिका से डेटा को वापस कॉपी करना होगा। ( sqlite.org - FAQ: Q11 )


28
मुझे लगता है कि पुरानी तालिका का नाम बदलना, नई तालिका बनाना और डेटा को वापस कॉपी करना आसान है। फिर आप पुरानी तालिका को छोड़ सकते हैं।
tuinstoel

हां, यह आसान है। मैं सिर्फ sqlite FAQ उद्धृत कर रहा था: sqlite.org/faq.html#q11 । वास्तव में, RENAME TOकुछ में से एक है ALTER TABLEवेरिएंट है कि वर्तमान में SQLite 3. में समर्थित है
डैनियल वसालो

3
क्या ऐसा नहीं होना चाहिए: FOREIGN KEY (parent_id) संदर्भ माता-पिता (id) सही, जोनाथन ने "मूल तालिका" का नाम नहीं दिया। वास्तव में, तालिका का नाम व्यक्ति होना चाहिए, लेकिन ...
igorludi

3
यह मुझे बहुत बड़ी समस्या लगती है। आमतौर पर जब आप किसी डेटाबेस को डंप करते हैं, तो आप पहले TATE कमांड बनाते हैं। फिर INSERT इनो कमांड्स और अंत में ADD CONSTRAINT कमांड्स। यदि आपके डेटा में परिपत्र (विदेशी कुंजी मूल्य) निर्भरता है, तो आप विदेशी कुंजी लागू होने पर अपना डेटा सम्मिलित नहीं कर सकते। लेकिन अगर आप बाद में विदेशी कुंजी बाधाओं को नहीं जोड़ सकते हैं, तो आप फंस गए हैं। निश्चित रूप से आस्थगित बाधाएं हैं, लेकिन यह बहुत ही अनाड़ी है।
नागालिज्स

9
अन्य तालिका में इस तालिका के संदर्भ होने पर पहली टिप्पणी में कहा गया है कि पुरानी तालिका का नाम नहीं बदलें! इस मामले में आपको इस सभी तालिकाओं को भी फिर से बनाना होगा।
रॉक ऑन

57

यदि आप तालिका में परिवर्तन करते हैं और बाधा का उपयोग करने वाले कॉलम को जोड़ सकते हैं, तो आप बाधा को जोड़ सकते हैं।

सबसे पहले, parent_id के बिना तालिका बनाएँ:

CREATE TABLE child( 
  id INTEGER PRIMARY KEY,  
  description TEXT);

फिर, तालिका बदलें:

ALTER TABLE child ADD COLUMN parent_id INTEGER REFERENCES parent(id);

2
इस क्रम में उपयोग करने के लिए अच्छा है, लेकिन यह वास्तविक सवाल का जवाब नहीं देता है: मैं मौजूदा एक में बाधा जोड़ना चाहता हूं।
वुल्फ

9

कृपया https://www.sqlite.org/lang_altertable.html#otheralter देखें

SQLite द्वारा सीधे समर्थित एकमात्र स्कीमा परिवर्तन कमांड "नाम बदलें" और ऊपर दिखाए गए "कॉलम जोड़ें" कमांड हैं। हालाँकि, अनुप्रयोग एक सरल अनुक्रम संचालन का उपयोग कर तालिका के स्वरूप में अन्य मनमाने ढंग से परिवर्तन कर सकते हैं। कुछ तालिका X के स्कीमा डिज़ाइन में मनमाने ढंग से परिवर्तन करने के चरण इस प्रकार हैं:

  1. यदि विदेशी कुंजी बाधाएं सक्षम हैं, तो उन्हें PRAGMA Foreign_keys = OFF का उपयोग करके अक्षम करें।
  2. एक लेनदेन शुरू करें।
  3. टेबल एक्स से जुड़े सभी इंडेक्स और ट्रिगर्स के प्रारूप को याद रखें। यह जानकारी नीचे चरण 8 में आवश्यक होगी। ऐसा करने का एक तरीका निम्नलिखित की तरह एक क्वेरी चलाना है: SELECT टाइप, sql FROM sqlite_master जहाँ tbl_name = 'X'।
  4. एक नया टेबल "new_X" बनाने के लिए क्रिएट टेबल का उपयोग करें जो टेबल एक्स के वांछित संशोधित प्रारूप में है। सुनिश्चित करें कि "new_X" नाम किसी भी मौजूदा टेबल नाम से नहीं टकराता है।
  5. X_ से कंटेंट को नए_X में ट्रांसफर करें जैसे कि स्टेटमेंट: INSERT INTO new_X SELECT ... FROM X से।
  6. पुरानी तालिका X को छोड़ें: DROP TABLE X।
  7. New_X का नाम बदलकर X करें: ALTER TABLE new_X RENAME TO X।
  8. तालिका X से जुड़े अनुक्रमित और ट्रिगर्स को फिर से बनाने के लिए CREATE INDEX और CREATE TRIGGER का उपयोग करें। शायद एक गाइड के रूप में ऊपर चरण 3 से सहेजे गए ट्रिगर्स और इंडेक्स के पुराने प्रारूप का उपयोग करें, परिवर्तन के लिए उपयुक्त बनाते हैं।
  9. यदि कोई दृश्य स्कीमा परिवर्तन से प्रभावित तरीके से टेबल एक्स को संदर्भित करता है, तो उन विचारों को डीआरओपी व्यू का उपयोग करके छोड़ दें और क्रिएट व्यू का उपयोग करके स्कीमा परिवर्तन को समायोजित करने के लिए जो भी आवश्यक हो, उन्हें फिर से बनाएं।
  10. यदि विदेशी कुंजी बाधाएं मूल रूप से सक्षम थीं, तो यह पुष्टि करने के लिए कि विदेशी परिवर्तन किसी भी विदेशी कुंजी बाधाओं को नहीं तोड़ते हैं, PRAGMA Foreign_key_check चलाएं।
  11. चरण 2 में शुरू किए गए लेनदेन को कमिट करें।
  12. यदि विदेशी कुंजी बाधाएं मूल रूप से सक्षम थीं, तो अब उन्हें फिर से लागू करें।

उपरोक्त प्रक्रिया पूरी तरह से सामान्य है और भले ही स्कीमा परिवर्तन तालिका में संग्रहीत जानकारी को बदलने का कारण बनता है, तब भी काम करेगा। तो ऊपर दी गई पूरी प्रक्रिया एक कॉलम को छोड़ने के लिए उपयुक्त है, कॉलम के क्रम को बदलना, एक UNIQUE बाधा या प्राथमिक कुंजी को जोड़ना या हटाना, CHECK या FOREIGN KEY या NOT NULL बाधाओं को जोड़ना, या किसी कॉलम के लिए डेटाटाइप को बदलना, उदाहरण के लिए।


4

हां, आप एक नया कॉलम जोड़ सकते हैं। डेटाबेस को भ्रष्ट करने से बचने के लिए आपको इसे सही तरीके से करने के लिए सावधान रहना होगा, इसलिए आपको ऐसा करने से पहले अपने डेटाबेस का पूरी तरह से बैकअप लेना चाहिए।

अपने विशिष्ट उदाहरण के लिए:

CREATE TABLE child(
  id INTEGER PRIMARY KEY,
  parent_id INTEGER,
  description TEXT
);

--- create the table we want to reference
create table parent(id integer not null primary key);

--- now we add the foreign key
pragma writable_schema=1;
update SQLITE_MASTER set sql = replace(sql, 'description TEXT)',
    'description TEXT, foreign key (parent_id) references parent(id))'
) where name = 'child' and type = 'table';

--- test the foreign key
pragma foreign_keys=on;
insert into parent values(1);
insert into child values(1, 1, 'hi'); --- works
insert into child values(2, 2, 'bye'); --- fails, foreign key violation

या अधिक आम तौर पर:

pragma writable_schema=1;

// replace the entire table's SQL definition, where new_sql_definition contains the foreign key clause you want to add
UPDATE SQLITE_MASTER SET SQL = new_sql_definition where name = 'child' and type = 'table';

// alternatively, you might find it easier to use replace, if you can match the exact end of the sql definition
// for example, if the last column was my_last_column integer not null:
UPDATE SQLITE_MASTER SET SQL = replace(sql, 'my_last_column integer not null', 'my_last_column integer not null, foreign key (col1, col2) references other_table(col1, col2)') where name = 'child' and type = 'table';

pragma writable_schema=0;

किसी भी तरह से, आप शायद यह देखना चाहेंगे कि कोई भी बदलाव करने से पहले SQL परिभाषा क्या है:

select sql from SQLITE_MASTER where name = 'child' and type = 'table';

यदि आप प्रतिस्थापित () दृष्टिकोण का उपयोग करते हैं, तो आप इसे निष्पादित करने से पहले, अपने रिप्लेसमेंट () कमांड को चलाने से पहले, मददगार हो सकते हैं:

select replace(sql, ...) from SQLITE_MASTER where name = 'child' and type = 'table';

3

यदि आप फ़ायरफ़ॉक्स ऐड-ऑन साइक्लाइट-मैनेजर का उपयोग कर रहे हैं, तो आप निम्न कार्य कर सकते हैं:

इसके बजाय तालिका को फिर से बनाने और बनाने के लिए कोई इसे इस तरह से संशोधित कर सकता है।

कॉलम टेक्स्ट बॉक्स में, संदर्भ मेनू लाने के लिए सूचीबद्ध अंतिम कॉलम नाम पर राइट क्लिक करें और कॉलम संपादित करें का चयन करें। ध्यान दें कि यदि TABLE की परिभाषा में अंतिम कॉलम PRIMARY KEY है तो पहले एक नया कॉलम जोड़ना आवश्यक होगा और फिर FOREIGN कुंजी को जोड़ने के लिए नए कॉलम के कॉलम प्रकार को संपादित करें। स्तंभ प्रकार बॉक्स के भीतर, एक अल्पविराम और जोड़ें

FOREIGN KEY (parent_id) REFERENCES parent(id)

डेटा प्रकार के बाद परिभाषा। चेंज बटन पर क्लिक करें और फिर डेंजरस ऑपरेशन डायलॉग बॉक्स पर हां बटन पर क्लिक करें।

संदर्भ: सकलाइट मैनेजर



-1

मूल रूप से आप नहीं कर सकते लेकिन आप स्थिति को दरकिनार कर सकते हैं।

मौजूदा मेज पर विदेशी कुंजी बाधा को जोड़ने का सही तरीका निम्नलिखित कमांड है।

db.execSQL("alter table child add column newCol integer REFERENCES parent(parent_Id)");

फिर कॉपी PARENT_ID करने के लिए डेटा newCol और फिर हटाना PARENT_ID स्तंभ। इसलिए, अस्थायी तालिका की कोई आवश्यकता नहीं है।


ऐसा लगता है कि आपने प्रश्न को ध्यान से नहीं पढ़ा। समस्या केवल एक विदेशी बाधा को जोड़ने के लिए थी, न कि बाधा के साथ एक स्तंभ जोड़ने के लिए।
वुल्फ

नहीं। यह पूछे गए प्रश्न का उत्तर नहीं देता है।
एमके

-4

पहले चाइल्ड टेबल में एक कॉलम जोड़ें Cidऔर intफिर alter tableनीचे दिए गए कोड के साथ। इस तरह आप विदेशी कुंजी Cidको पैरेंट टेबल की प्राथमिक कुंजी के रूप में जोड़ सकते हैं और चाइल्ड टेबल में विदेशी कुंजी के रूप में उपयोग कर सकते हैं ... आशा है कि यह आपकी मदद करेगा क्योंकि यह मेरे लिए अच्छा है:

ALTER TABLE [child] 
  ADD CONSTRAINT [CId] 
  FOREIGN KEY ([CId]) 
  REFERENCES [Parent]([CId]) 
  ON DELETE CASCADE ON UPDATE NO ACTION;
GO

1
यह SQLite में मान्य नहीं है। इसके अलावा यह MS SQL सिंटैक्स है।
स्टाइल्सक्रिस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.