SQLinfo.ru - Все о MySQL Webew.ru: теория и практика веб-технологий

Форум пользователей MySQL

Задавайте вопросы, мы ответим

Вы не зашли.

#1 03.06.2013 19:50:13

igrok
Участник
Зарегистрирован: 28.01.2012
Сообщений: 9

Вложенные запросы с UPDATE

У себя на сайте я использовал следующий запрос:

UPDATE sys_pages
SET sys_pages.del = 'yes'
WHERE sys_pages.id_main IN (
    SELECT sys_pages.id_main
    FROM sys_pages LEFT JOIN groups_new
    ON sys_pages.kod = groups_new.kod
    WHERE (sys_pages.export='yes') and (groups_new.kod  IS NULL)
)

Запрос выдает ошибку:
[Err] 1093 - You can't specify target table 'sys_pages' for update in FROM clause

Вложенный запрос самостоятельно работает без ошибок.
Конструкция внешнего запроса вроде бы корректная.

В чем я напортачил? И как исправить положение?
Помогите, плиз, написать правильный запрос!

Отредактированно igrok (03.06.2013 19:51:57)

Неактивен

 

#2 03.06.2013 20:12:05

Neval
Гуру
Откуда: Киев
Зарегистрирован: 11.03.2008
Сообщений: 449

Re: Вложенные запросы с UPDATE

Вы пытаетесь сделать выборку из обновляемой таблицы, так делать нельзя. В Вашем случае без проблем можно обойтись без подзапроса, почитайте про многотабличные апдейты.


Человек без чувства юмора - не серьёзный человек wink

Неактивен

 

#3 04.06.2013 00:26:46

igrok
Участник
Зарегистрирован: 28.01.2012
Сообщений: 9

Re: Вложенные запросы с UPDATE

Скажем так, у меня есть две таблицы с товарами: "A" и "B",

Вариант задачи 1: Из таблицы A нужно удалить товары, которых нет в таблице B.
Вариант задачи 2: В таблице A нужно отметить товары, которых нет в таблице B (отметить в графе del, задав значение "yes").

Задачу можно разбить на 2 логических действия:
1. Выбираем в таблице A те строки с товарами, которых нет в B. (товары сравниваем по графе "kod").
2. Выбранные строки удаляем (вар.1) или помечаем (вар.2)

Самый обычный способ найти строки в таблице А, которых нет в таблице B - это сделать SELECT с левосторонней связью по коду товара, отобрав строки, в которых B.kod = NULL. А затем пометить или удалить эти стоки из A.
SELECT A.id
FROM A LEFT JOIN B
ON A.kod = B.kod
WHERE B.kod IS NULL

Как далее, используя отобранные A.id, (вар.1) удалить их из таблицы A или (вар.2) пометить в графе A.del ? Как сделать это в одном запросе?

Неактивен

 

#4 04.06.2013 01:14:52

Neval
Гуру
Откуда: Киев
Зарегистрирован: 11.03.2008
Сообщений: 449

Re: Вложенные запросы с UPDATE

UPDATE  a
LEFT JOIN b ON b.kod = a.kod
SET     a.del = 'newvalue'
WHERE   b.id IS NULL

Как-то так... запрос не тестировал, но принцип, думаю, понятен. По такой же аналогии можно удалять записи:

DELETE  a
LEFT JOIN b ON b.kod = a.kod
WHERE   b.id IS NULL


Человек без чувства юмора - не серьёзный человек wink

Неактивен

 

#5 04.06.2013 08:03:30

vasya
Архат
MySQL Authorized Developer
Откуда: Орел
Зарегистрирован: 07.03.2007
Сообщений: 5842

Re: Вложенные запросы с UPDATE

igrok написал:

Запрос выдает ошибку:
[Err] 1093 - You can't specify target table 'sys_pages' for update in FROM clause

Вложенный запрос самостоятельно работает без ошибок.
Конструкция внешнего запроса вроде бы корректная.

В чем я напортачил? И как исправить положение?
Помогите, плиз, написать правильный запрос!

Ни в чем не напортачили. Просто в MySQL есть пока ограничение, запрещающее изменять данные и одновременно делать выборку из той же таблицы.
Обойти можно используя вложенный подзапрос:

UPDATE sys_pages
SET sys_pages.del = 'yes'
WHERE sys_pages.id_main IN (select * from (
    SELECT sys_pages.id_main
    FROM sys_pages LEFT JOIN groups_new
    ON sys_pages.kod = groups_new.kod
    WHERE (sys_pages.export='yes') and (groups_new.kod  IS NULL)
)t );

При этом подзапрос оказывается в части FROM и материализуется во временную таблицу в процессе выполнения запроса.

Но в вашем случае проще будет использовать многотабличный update, как подсказал Neval

P.S. Или можно перейти на MariaDB. С версии 5.3 у них оптимизирована работа подзапросов.

Неактивен

 

#6 04.06.2013 16:44:21

igrok
Участник
Зарегистрирован: 28.01.2012
Сообщений: 9

Re: Вложенные запросы с UPDATE

to Neval:

Виноват пробел в образовании smile
Не знал, что можно совмещать UPDATE и таблицы table1 и table2 не через запятую, а сразу с JOIN в одном простом запросе.
Большое спасибо за науку!


to vasya:

И Вам большое спасибо!

vasya написал:

...and (groups_new.kod  IS NULL)
)t );

Подскажите, пожалуйста, что за t стоит в конце цитируемого кода?
Где про это "t" можно почитать?

Неактивен

 

#7 04.06.2013 16:58:19

Neval
Гуру
Откуда: Киев
Зарегистрирован: 11.03.2008
Сообщений: 449

Re: Вложенные запросы с UPDATE

Это алиас/синоним/имя таблицы, чтобы можно было как-то обращаться к её полям по t.field_name.


Человек без чувства юмора - не серьёзный человек wink

Неактивен

 

#8 06.06.2013 12:28:12

igrok
Участник
Зарегистрирован: 28.01.2012
Сообщений: 9

Re: Вложенные запросы с UPDATE

to Neval:

Я правильно понял, что алиас "t" пишется после скобок, в которых заключен запрос с выборкой?
В данном случае:

(SELECT sys_pages.id_main .........IS NULL) t

Неактивен

 

#9 06.06.2013 12:52:21

vasya
Архат
MySQL Authorized Developer
Откуда: Орел
Зарегистрирован: 07.03.2007
Сообщений: 5842

Re: Вложенные запросы с UPDATE

Да

Неактивен

 

#10 12.06.2013 13:15:37

igrok
Участник
Зарегистрирован: 28.01.2012
Сообщений: 9

Re: Вложенные запросы с UPDATE

Спасибо всем!

Неактивен

 

#11 10.06.2014 23:46:11

nistelroi
Участник
Зарегистрирован: 10.06.2014
Сообщений: 1

Re: Вложенные запросы с UPDATE

Ошибка 1093 давно известная, и обойти можно двумя способами.
Вот так должно работать. И выглядит на порядок понятнее чем с вложенным SELECT FROM SELECT.

UPDATE sys_pages
    LEFT JOIN groups_new
        ON sys_pages.kod = groups_new.kod
    SET sys_pages.del = 'yes'
    WHERE sys_pages.export='yes' AND groups_new.kod IS NULL

Отредактированно nistelroi (19.07.2014 00:47:00)

Неактивен

 

Board footer

Работает на PunBB
© Copyright 2002–2008 Rickard Andersson