MySQL Error 1093 - FROM क्लॉज में अपडेट के लिए लक्ष्य तालिका निर्दिष्ट नहीं कर सकते


592

story_categoryमेरे डेटाबेस में भ्रष्ट प्रविष्टियों के साथ एक तालिका है। अगली क्वेरी भ्रष्ट प्रविष्टियाँ लौटाती है:

SELECT * 
FROM  story_category 
WHERE category_id NOT IN (
    SELECT DISTINCT category.id 
    FROM category INNER JOIN 
       story_category ON category_id=category.id);

मैंने उन्हें निष्पादित करने की कोशिश की:

DELETE FROM story_category 
WHERE category_id NOT IN (
    SELECT DISTINCT category.id 
    FROM category 
      INNER JOIN story_category ON category_id=category.id);

लेकिन मुझे अगली त्रुटि मिलती है:

# 1093 - FROM क्लॉज में अपडेट के लिए आप लक्ष्य तालिका 'story_category' को निर्दिष्ट नहीं कर सकते

मैं इससे कैसे उबरूं?




जवाबों:


713

अद्यतन: यह उत्तर सामान्य त्रुटि वर्गीकरण को कवर करता है। ओपी की सटीक क्वेरी को सर्वश्रेष्ठ तरीके से कैसे प्रबंधित करें, इस बारे में अधिक विशिष्ट उत्तर के लिए, कृपया इस प्रश्न के अन्य उत्तर देखें

MySQL में, आप उसी तालिका को संशोधित नहीं कर सकते हैं जिसका आप चयन भाग में करते हैं।
इस व्यवहार का दस्तावेजीकरण किया जाता है: http://dev.mysql.com/doc/refman/5.6/en/update.html

हो सकता है कि आप सिर्फ तालिका में शामिल हो सकते हैं

यदि तर्क क्वेरी को फिर से आकार देने के लिए पर्याप्त सरल है, तो उचित चयन मानदंडों को नियोजित करते हुए, सबक्वेरी खो दें और तालिका में खुद को शामिल करें। इससे MySQL तालिका को दो अलग-अलग चीजों के रूप में देखेगा, जिससे विनाशकारी परिवर्तन आगे बढ़ सकते हैं।

UPDATE tbl AS a
INNER JOIN tbl AS b ON ....
SET a.col = b.col

वैकल्पिक रूप से, उपवाक्य को उपवाक्य से गहरे में घोंसला बनाने की कोशिश करें ...

यदि आपको पूरी तरह से सबक्वेरी की जरूरत है, तो वर्कअराउंड है, लेकिन यह प्रदर्शन सहित कई कारणों से बदसूरत है:

UPDATE tbl SET col = (
  SELECT ... FROM (SELECT.... FROM) AS x);

FROM क्लॉज में नेस्टेड सबक्विरी एक अंतर्निहित अस्थायी तालिका बनाता है , इसलिए यह उसी तालिका में गणना नहीं करता है जिसे आप अपडेट कर रहे हैं।

... लेकिन क्वेरी ऑप्टिमाइज़र के लिए देखें

हालाँकि, सावधान रहें कि MySQL 5.7.6 और उसके बाद, ऑप्टिमाइज़र सबक्वेरी को ऑप्टिमाइज़ कर सकता है, और फिर भी आपको त्रुटि दे सकता है। सौभाग्य से, optimizer_switchइस व्यवहार को बंद करने के लिए चर का उपयोग किया जा सकता है; हालाँकि मैं इसे शॉर्ट टर्म फिक्स या छोटे वन-ऑफ कार्यों से अधिक कुछ भी करने की सलाह नहीं दे सकता।

SET optimizer_switch = 'derived_merge=off';

टिप्पणी में इस सलाह के लिए पीटर वी। मॉरच को धन्यवाद ।

उदाहरण तकनीक बैरन श्वार्ट्ज से थी, जो मूल रूप से नाबले में प्रकाशित हुई थी , यहां पर चर्चा की गई थी और इसे बढ़ाया गया था।


1
इस जवाब को अपडाउन किया क्योंकि मुझे आइटम डिलीट करने थे और किसी दूसरी टेबल से जानकारी नहीं मिल सकती थी, उसी टेबल से सबकुछ करना पड़ा। चूंकि यह वही है जो मुझे मिली त्रुटि के लिए गुगली करते समय शीर्ष पर पॉप होता है, यह मेरे लिए सबसे अच्छा फिट जवाब होगा और एक ही तालिका से सबअर्बिंग करते समय अपडेट करने की कोशिश करने वाले बहुत से लोग।
HMR

2
@Cheekysoft, इसके बजाय वैरिएबल में मान क्यों नहीं बचाएं?
पैशियर

19
खबरदार, कि MySQL 5.7.6 से , ऑप्टिमाइज़र दूर-उप-क्वेरी को अनुकूलित कर सकता है और तब भी आपको त्रुटि देगा, जब तक कि आप SET optimizer_switch = 'derived_merge=off';:-(
पीटर वी। मॉर्क

1
@ PeterV.Mørch बाद mysqlserverteam.com/derived-tables-in-mysql-5-7 , मामले में निश्चित संचालनों किया जाता है, विलय नहीं हो सकता। उदाहरण के लिए व्युत्पन्न डमी तालिका को एक लिमिट (इनफिनिटी) के साथ प्रदान करें और त्रुटि कभी नहीं होगी। हालांकि यह बहुत ही हैकिश है और अभी भी यह जोखिम है कि MySQL के भविष्य के संस्करण सभी के बाद LIMIT के साथ विलय के प्रश्नों का समर्थन करेंगे।
user2180613

क्या आप कृपया इस वर्कअराउंड के बारे में एक पूर्ण उदाहरण प्रदान कर सकते हैं? अद्यतन tbl सेट col = (का चयन करें ... से (चयन .... से) के रूप में एक्स); मैं अभी भी गलतियाँ कर रहा हूँ
JoelBonetR

310

NexusRex ने उसी तालिका से जुड़ने के साथ हटाने के लिए एक बहुत अच्छा समाधान प्रदान किया ।

अगर तुम यह करते हो:

DELETE FROM story_category
WHERE category_id NOT IN (
        SELECT DISTINCT category.id AS cid FROM category 
        INNER JOIN story_category ON category_id=category.id
)

आपको एक त्रुटि मिलने वाली है।

लेकिन अगर आप शर्त को एक और चुन लेते हैं:

DELETE FROM story_category
WHERE category_id NOT IN (
    SELECT cid FROM (
        SELECT DISTINCT category.id AS cid FROM category 
        INNER JOIN story_category ON category_id=category.id
    ) AS c
)

यह सही काम करेगा !!

स्पष्टीकरण: क्वेरी ऑप्टिमाइज़र पहली क्वेरी के लिए व्युत्पन्न मर्ज ऑप्टिमाइज़ेशन करता है (जो इसे त्रुटि के साथ विफल होने का कारण बनता है), लेकिन दूसरी क्वेरी व्युत्पन्न मर्ज ऑप्टिमाइज़ेशन के लिए योग्य नहीं है । इसलिए ऑप्टिमाइज़र को पहले सबक्वेरी निष्पादित करने के लिए मजबूर किया जाता है।


6
शायद यह इसलिए है क्योंकि मैं आज एक बंधन में हूं, लेकिन यह सबसे आसान जवाब था, भले ही यह "सबसे अच्छा" न हो।
टायलर वी।

4
यह महान काम किया, धन्यवाद! तो यहाँ क्या तर्क है? यदि इसे एक और स्तर पर घोंसला बनाया जाता है तो इसे बाहरी हिस्से से पहले निष्पादित किया जाएगा? और अगर यह नेस्टेड नहीं है तो डिलीट टेबल पर लॉक होने के बाद mySQL इसे चलाने की कोशिश करता है?
फ्लैट कैट

43
इस त्रुटि और समाधान का कोई तार्किक अर्थ नहीं है ... लेकिन यह काम करता है। कभी-कभी मुझे आश्चर्य होता है कि MySQL
देवता

1
@ केरिन से सहमत .. यह पूरी तरह से बेतुका है, लेकिन यह काम करता है।
फास्टट्रैक

@ekonoval समाधान के लिए धन्यवाद, लेकिन यह मेरे लिए न्यूनतम अर्थ नहीं है, ऐसा लगता है कि आप MySQL को बेवकूफ बना रहे हैं और वह इसे स्वीकार करते हैं, योग्य
deFreitas

106

inner joinअपने उप क्वेरी में अनावश्यक है। ऐसा लगता है कि आप में प्रविष्टियों को नष्ट करना चाहते story_categoryहैं जहां category_idमें नहीं है categoryतालिका।

यह करो:

DELETE FROM story_category 
WHERE category_id NOT IN (
    SELECT DISTINCT category.id 
    FROM category);

उसके बदले में:

DELETE FROM story_category 
WHERE category_id NOT IN (
    SELECT DISTINCT category.id 
    FROM category INNER JOIN
         story_category ON category_id=category.id);

5
यह शीर्ष उत्तर होना चाहिए! शायद पहले "के बजाय" हटा दें।
होहॉय

1
मुझे लगता DISTINCTहै कि यहां अनावश्यक है - एक बेहतर प्रदर्शन के लिए;)।
shA.t

1
मैं पागल होना चाहिए। उत्तर वही है जो मूल में कहा गया था।
जेफ लोरी

मेरे लिए भी यही जवाब है। where inआईडी कॉलम पर न जाएं, इसलिए आपको प्राथमिक तालिका को अधीन करने की आवश्यकता नहीं है।
रिचर्ड

@JeffLowery - पहला कोड ब्लॉक यहाँ का जवाब है; इसका दूसरा कोड ब्लॉक है जो प्रश्न से है।
टूलमेकरसेव

95

हाल ही में मुझे उसी तालिका में रिकॉर्ड अपडेट करना पड़ा था जो मैंने नीचे की तरह किया था:

UPDATE skills AS s, (SELECT id  FROM skills WHERE type = 'Programming') AS p
SET s.type = 'Development' 
WHERE s.id = p.id;

11
क्या इसे केवल लिखा नहीं जा सकता UPDATE skills SET type='Development' WHERE type='Programming';? यह मूल प्रश्न का उत्तर नहीं देता है।
lilbyrdie

1
ओवरकिल की तरह लगता है, @lilbyrdie सही है - यह केवल हो सकता है UPDATE skills SET type='Development' WHERE type='Programming';। मुझे समझ में नहीं आता कि इतने सारे लोग इस बारे में क्यों नहीं सोच रहे हैं कि वे क्या करते हैं ...
shadyyx

1
यह यहाँ सबसे अच्छा जवाब है, IMHO। यह वाक्यविन्यास समझने में आसान है, आप अपने पिछले बयान का फिर से उपयोग कर सकते हैं और यह कुछ सुपर विशिष्ट मामले तक सीमित नहीं है।
स्टीफन विंकलर

2
भले ही उदाहरण मामला संदिग्ध हो, वास्तविक दुनिया के परिदृश्यों को समझने और तैनात करने के लिए सिद्धांत सबसे अच्छा है। दिखाया गया क्वेरी काम करता है क्योंकि अंतर्निहित तालिका सूची में शामिल होने से एक सबक्वेरी के लिए एक अस्थायी तालिका बन जाती है, इस प्रकार स्थिर परिणाम प्रदान करते हैं और उसी तालिका के पुनर्प्राप्ति और संशोधन के बीच टकराव से बचते हैं।
अरुणमान

1
ओवरकिल होने के बारे में कोई भी कुछ भी कह सकता है, फिर भी यह शीर्षक के संदर्भ में प्रश्न का उत्तर देता है। ओपी ने जिस त्रुटि का उल्लेख किया है वह तब भी सामने आई है जब किसी अद्यतन तालिका में नेस्टेड क्वेरी में एक ही तालिका का उपयोग करने का प्रयास किया गया है
smac89

35
DELETE FROM story_category
WHERE category_id NOT IN (
    SELECT cid FROM (
        SELECT DISTINCT category.id AS cid FROM category INNER JOIN story_category ON category_id=category.id
    ) AS c
)

3
क्या आप बता सकते हैं कि यह क्यों काम करता है, क्यों सिर्फ एक और स्तर के काम के लिए घोंसला बनाना? यह प्रश्न पहले से ही @ EkoNoval के प्रश्न के लिए एक टिप्पणी के रूप में पूछा गया है, लेकिन किसी ने जवाब नहीं दिया। शायद आप मदद कर सकते हैं।
अक्षय अरोरा

@AkshayArora, 'Cheekysoft' के उत्तर में 'शायद आप सिर्फ मेज पर ही शामिल हो सकते हैं' शीर्षक के तहत भाग से गुज़रें। उन्होंने कहा UPDATE tbl AS a INNER JOIN tbl AS b ON .... SET a.col = b.col- यह एक ही तालिका के लिए एक अलग उपनाम के रूप में काम करेगा यहाँ उपयोग किया जाता है। इसी प्रकार @ NexusRex के उत्तर में पहली SELECTक्वेरी एक व्युत्पन्न तालिका के रूप में कार्य करती story_categoryहै जिसमें दूसरी बार उपयोग किया जाता है। तो ओपी में उल्लिखित त्रुटि यहाँ नहीं होनी चाहिए, है ना?
इस्तियाक अहमद

31

अगर तुम नहीं कर सकते

UPDATE table SET a=value WHERE x IN
    (SELECT x FROM table WHERE condition);

क्योंकि यह एक ही तालिका है, आप इसे ट्रिक और कर सकते हैं:

UPDATE table SET a=value WHERE x IN
    (SELECT * FROM (SELECT x FROM table WHERE condition) as t)

[अद्यतन करें या हटाएं या जो भी]


उपरोक्त सभी उत्तरों में से सबसे अधिक समझने योग्य और तार्किक कार्यान्वयन। सरल और सटीक।
क्लेस्सिल्वा

यह अब मेरे वर्कफ़्लो का हिस्सा बन गया है। इस त्रुटि पर अटक जाएं, इस उत्तर पर जाएं और क्वेरी को सुधारें। धन्यवाद।
वैभव

13

यह है कि मैंने 1 से एक प्राथमिकता स्तंभ मान को अपडेट करने के लिए किया था यदि यह तालिका में> = 1 है और इसके WHERE क्लॉज में उसी तालिका पर एक उप-वर्ग का उपयोग करके यह सुनिश्चित करने के लिए कि कम से कम एक पंक्ति में प्रायोरिटी = 1 है (क्योंकि वह था अद्यतन करते समय जाँच की जाने वाली स्थिति):


UPDATE My_Table
SET Priority=Priority + 1
WHERE Priority >= 1
AND (SELECT TRUE FROM (SELECT * FROM My_Table WHERE Priority=1 LIMIT 1) as t);

मुझे पता है कि यह थोड़ा बदसूरत है लेकिन यह ठीक काम करता है।


1
@anonymous_reviewer: किसी की टिप्पणी के लिए [-1] या यहां तक ​​कि [+1] देने के मामले में भी उल्लेख करें कि आपने इसे क्यों दिया है। धन्यवाद!!!
संकटी

1
-1 क्योंकि यह गलत है। आप उसी तालिका को संशोधित नहीं कर सकते हैं, जिसका चयन आप सेलेक्ट स्टेटमेंट में करते हैं।
क्रिस

1
@ क्रिस ने इसे MySQL पर सत्यापित किया है और यह मेरे लिए ठीक काम करता है इसलिए मैं आपसे अनुरोध करूंगा कि कृपया इसे अपने अंत में सत्यापित करें और फिर इसे सही या गलत होने का दावा करें। धन्यवाद!!!
15

1
इस पृष्ठ के निचले भाग में लिखा है, 'वर्तमान में, आप किसी तालिका को अद्यतन नहीं कर सकते हैं और किसी उपश्रेणी में उसी तालिका से चयन कर सकते हैं।' - और मैंने कई मौकों पर इसे सच होने का अनुभव किया है। dev.mysql.com/doc/refman/5.0/en/update.html
क्रिस

19
@ क्रिस मैं जानता हूं कि, लेकिन उसके लिए एक वर्कअराउंड है और जो मैंने अपनी 'अद्यतन' क्वेरी के साथ दिखाने की कोशिश की है और मुझे विश्वास है कि यह ठीक काम करता है। मुझे नहीं लगता कि आपने वास्तव में मेरी क्वेरी को सत्यापित करने का प्रयास किया है।
sactiw

6

ऐसा करने का सबसे सरल तरीका एक तालिका उपनाम है जब आप उप क्वेरी के अंदर मूल क्वेरी तालिका का उल्लेख कर रहे हैं।

उदाहरण :

insert into xxx_tab (trans_id) values ((select max(trans_id)+1 from xxx_tab));

इसे इसमें बदलें:

insert into xxx_tab (trans_id) values ((select max(P.trans_id)+1 from xxx_tab P));

5

आप इच्छित पंक्तियों की आईडी को एक अस्थायी तालिका में सम्मिलित कर सकते हैं और फिर उस तालिका में पाई जाने वाली सभी पंक्तियों को हटा सकते हैं।

जो हो सकता है @Cheekysoft दो चरणों में करने से मतलब है।


3

@CheekySoft द्वारा लिंक किए गए मैसकल अपडेट सिंटेक्स के अनुसार , यह नीचे दाईं ओर कहता है।

वर्तमान में, आप किसी तालिका को अद्यतन नहीं कर सकते हैं और किसी उपश्रेणी में उसी तालिका से चुन सकते हैं।

मुझे लगता है कि आप अभी भी यूनियन में सेलेक्ट करते समय store_category से हटा रहे हैं।


3

विशिष्ट क्वेरी के लिए ओपी प्राप्त करने की कोशिश कर रहा है, ऐसा करने के लिए आदर्श और सबसे कुशल तरीका सबकुछ का उपयोग करना नहीं है।

यहाँ LEFT JOINओपी के दो प्रश्नों के संस्करण दिए गए हैं :

SELECT s.* 
FROM story_category s 
LEFT JOIN category c 
ON c.id=s.category_id 
WHERE c.id IS NULL;

नोट: DELETE sप्रतिबंधित कार्यों को story_categoryतालिका में हटा देता है ।
प्रलेखन

DELETE s 
FROM story_category s 
LEFT JOIN category c 
ON c.id=s.category_id 
WHERE c.id IS NULL;

1
हैरानी की बात यह है कि अधिक वोट नहीं है। यह भी ध्यान दिया जाना चाहिए कि मल्टी-टेबल सिंटैक्स भी UPDATEबयानों के साथ काम करता है और उप-प्रश्नों में शामिल होता है। कई उपयोग-मामलों में कार्यान्वयन को उपयोगी बनाने के LEFT JOIN ( SELECT ... )लिए आपको विरोध करने के लिए अनुमति देना WHERE IN( SELECT ... )
fyrye

2

यदि कुछ काम नहीं करता है, तो सामने वाले दरवाजे से आते हैं, तो पीछे के दरवाजे पर ले जाएं:

drop table if exists apples;
create table if not exists apples(variety char(10) primary key, price int);

insert into apples values('fuji', 5), ('gala', 6);

drop table if exists apples_new;
create table if not exists apples_new like apples;
insert into apples_new select * from apples;

update apples_new
    set price = (select price from apples where variety = 'gala')
    where variety = 'fuji';
rename table apples to apples_orig;
rename table apples_new to apples;
drop table apples_orig;

ये तेज़ है। जितना बड़ा डेटा, उतना अच्छा।


11
और आपने अपनी सभी विदेशी कुंजियाँ खो दी हैं, और हो सकता है कि आपके पास कुछ कैस्केडिंग डिलीट भी हो।
वॉलफ

2

अलग-अलग वेरिएबल में सेलेक्ट स्टेटमेंट के रिजल्ट को सेव करने की कोशिश करें और फिर डिलीट क्वेरी के लिए इसका इस्तेमाल करें।


2

इसे इस्तेमाल करे

DELETE FROM story_category 
WHERE category_id NOT IN (
SELECT DISTINCT category.id 
FROM (SELECT * FROM STORY_CATEGORY) sc;

1

इस क्वेरी के बारे में यह कैसे मदद करता है उम्मीद है

DELETE FROM story_category LEFT JOIN (SELECT category.id FROM category) cat ON story_category.id = cat.id WHERE cat.id IS NULL

परिणाम दिखाता है: '# 1064 - आपके SQL सिंटैक्स में एक त्रुटि है; 'LEFT JOIN (Select श्रेणियां.id FROM कैटेगरी) बिल्ली पर कहानी_category.id = बिल्ली' के पास उपयोग करने के लिए सही सिंटैक्स के लिए अपने MariaDB सर्वर संस्करण से मेल खाती पुस्तिका की जाँच करें। 1 लाइन पर '
इस्तियाक अहमद

मल्टी-टेबल डिलीट का उपयोग करते समय आपको प्रभावित तालिकाओं को निर्दिष्ट करना होगा। DELETE story_category FROM ...हालाँकि, इस संदर्भ LEFT JOIN category AS cat ON cat.id = story_category.category_id WHERE cat.id IS NULLमें story_category.id = cat.id
सम्मिलित

0

जहां तक ​​चिंता की बात है, आप उन पंक्तियों को हटाना चाहते story_categoryहैं जिनमें मौजूद नहीं हैं category

हटाने के लिए पंक्तियों की पहचान करने के लिए यहां आपकी मूल क्वेरी है:

SELECT * 
FROM  story_category 
WHERE category_id NOT IN (
    SELECT DISTINCT category.id 
    FROM category INNER JOIN 
       story_category ON category_id=category.id
);

NOT INएक उपश्रेणी के साथ संयोजन करना, JOINजो मूल तालिका है, अनावश्यक रूप से जटिल लगती है। इसे अधिक सीधे-सीधे तरीके से not existsऔर सहसंबंधित उपशम के साथ व्यक्त किया जा सकता है :

select sc.*
from story_category sc
where not exists (select 1 from category c where c.id = sc.category_id);

अब इसे deleteबयान में बदलना आसान है :

delete from story_category
where not exists (select 1 from category c where c.id = story_category.category_id);    

यह क्वेर किसी भी MySQL वर्जन पर चलेगा, साथ ही ज्यादातर अन्य डेटाबेस में जो मुझे पता है।

डीबी फ़िडल पर डेमो :

-- set-up
create table story_category(category_id int);
create table category (id int);
insert into story_category values (1), (2), (3), (4), (5);
insert into category values (4), (5), (6), (7);

-- your original query to identify offending rows
SELECT * 
FROM  story_category 
WHERE category_id NOT IN (
    SELECT DISTINCT category.id 
    FROM category INNER JOIN 
       story_category ON category_id=category.id);
| category_id |
| ----------: |
| 1 |
| 2 |
| 3 |
-- a functionally-equivalent, simpler query for this
select sc.*
from story_category sc
where not exists (select 1 from category c where c.id = sc.category_id)
| category_id |
| ----------: |
| 1 |
| 2 |
| 3 |
-- the delete query
delete from story_category
where not exists (select 1 from category c where c.id = story_category.category_id);

-- outcome
select * from story_category;
| category_id |
| ----------: |
| 4 |
| 5 |
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.