خطأ MySQL 1093 - لا يمكن تحديد الجدول الهدف للتحديث في جملة FROM

StackOverflow https://stackoverflow.com/questions/45494

سؤال

لدي طاولة 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 - لا يمكنك تحديد الجدول المستهدف "story_category" للتحديث في جملة FROM

كيف يمكنني التغلب على هذا؟

هل كانت مفيدة؟

المحلول

تحديث:تغطي هذه الإجابة تصنيف الخطأ العام.للحصول على إجابة أكثر تحديدًا حول كيفية التعامل بشكل أفضل مع استعلام OP الدقيق، يرجى الاطلاع على الإجابات الأخرى لهذا السؤال

في MySQL، لا يمكنك تعديل نفس الجدول الذي تستخدمه في جزء SELECT.
تم توثيق هذا السلوك في: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 بإنشاء الجدول المؤقت الضمني, ، لذلك لا يعتبر نفس الجدول الذي تقوم بتحديثه.

...ولكن احترس من محسن الاستعلام

ومع ذلك، احذر من ذلك ماي إس كيو إل 5.7.6 وما بعده، قد يقوم المُحسِّن بتحسين الاستعلام الفرعي، ويظل يعطيك الخطأ.لحسن الحظ، optimizer_switch يمكن استخدام المتغير لإيقاف هذا السلوك؛على الرغم من أنني لا أستطيع أن أوصي بالقيام بهذا باعتباره أكثر من مجرد إصلاح قصير المدى، أو لمهام صغيرة لمرة واحدة.

SET optimizer_switch = 'derived_merge=off';

شكرا ل بيتر ف.مورش لهذه النصيحة في التعليقات.

تقنية المثال كانت من بارون شوارتز، نشرت أصلا في نابل, ، أعيد صياغتها وتوسيعها هنا.

نصائح أخرى

نيكسوسريكس قدمت أ حل جيد جدا للحذف مع الانضمام من نفس الجدول.

إذا قمت بذلك:

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
)

من شأنه أن يفعل الشيء الصحيح!

توضيح: يقوم مُحسِّن الاستعلام بـ تحسين الدمج المشتق للاستعلام الأول (مما يؤدي إلى فشله بسبب الخطأ)، ولكن الاستعلام الثاني غير مؤهل للاستعلام تحسين الدمج المشتق.ومن ثم يضطر المحسن إلى تنفيذ الاستعلام الفرعي أولاً.

ال 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);

اضطررت مؤخرًا إلى تحديث السجلات في نفس الجدول كما فعلت أدناه:

UPDATE skills AS s, (SELECT id  FROM skills WHERE type = 'Programming') AS p
SET s.type = 'Development' 
WHERE s.id = p.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
)

إذا كنت لا تستطيع أن تفعل

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)

[تحديث أو حذف أو أيا كان]

هذا ما فعلته لتحديث قيمة عمود الأولوية بمقدار 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);

أعلم أنه قبيح بعض الشيء لكنه يعمل بشكل جيد.

يمكنك إدراج معرفات الصفوف المطلوبة في جدول مؤقت ثم حذف كافة الصفوف الموجودة في هذا الجدول.

وهو ما قد يكون ما قصدته @Cheekysoft من خلال القيام بذلك في خطوتين.

وفق بناء جملة تحديث Mysql تم ربطه بواسطة @CheekySoft، وهو مكتوب في الأسفل مباشرةً.

حاليًا، لا يمكنك تحديث جدول والاختيار من نفس الجدول في استعلام فرعي.

أعتقد أنك تقوم بالحذف من store_category بينما لا تزال تختار منه في الاتحاد.

إذا لم ينجح شيء ما، عند المرور من الباب الأمامي، اتبع الباب الخلفي:

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;

إنه سريع.كلما كانت البيانات أكبر، كلما كان ذلك أفضل.

إن أبسط طريقة للقيام بذلك هي استخدام الاسم المستعار للجدول عندما تقوم بإحالة جدول الاستعلام الأصلي داخل الاستعلام الفرعي.

مثال :

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));

جرب هذا

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

حاول حفظ نتيجة عبارة التحديد في متغير منفصل ثم استخدمها لاستعلام الحذف.

ماذا عن هذا الاستعلام آمل أن يساعد

DELETE FROM story_category LEFT JOIN (SELECT category.id FROM category) cat ON story_category.id = cat.id WHERE cat.id IS NULL
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top