[ Поиск ] - [ Пользователи ] - [ Календарь ]
Полная Версия: простой, но сложный UPDATE
QuadMan
Помогите, пожалуйста составить правильный UPDATE.
Нужно, чтобы поле ONTOP стало равно '1' у элемента с ID=36 и у всех элементов таблицы с таким же полем DOCNAME. smile.gif
Вроде не очень сложно, но не получается...

Код
UPDATE `DOCUMENTS` SET `ONTOP` = 1 WHERE `ID` = '36' AND `DOCNAME` = (SELECT `DOCNAME` FROM `DOCUMENTS` WHERE `ID` = '36')


Спасибо!



Спустя 19 минут, 14 секунд (31.07.2008 - 14:55) jetistyum написал(а):
Цитата(QuadMan @ 31.7.2008, 14:36) [snapback]44911[/snapback]
Помогите, пожалуйста составить правильный UPDATE.
Нужно, чтобы поле ONTOP стало равно '1' у элемента с ID=36 и у всех элементов таблицы с таким же полем DOCNAME. smile.gif
Вроде не очень сложно, но не получается...

Код
UPDATE `DOCUMENTS` SET `ONTOP` = 1 WHERE `ID` = '36' AND `DOCNAME` = (SELECT `DOCNAME` FROM `DOCUMENTS` WHERE `ID` = '36')


Спасибо!


UPDATE
`DOCUMENTS`
SET
`ONTOP` = 1
WHERE
`ID` = '36' OR
`DOCNAME` = (SELECT `DOCNAME` FROM `DOCUMENTS` WHERE `ID` = '36')


Вот вроде как-то так ! smile.gif

Спустя 2 минуты, 23 секунды (31.07.2008 - 14:58) jetistyum написал(а):
Цитата(jetistyum @ 31.7.2008, 14:55) [snapback]44913[/snapback]
Цитата(QuadMan @ 31.7.2008, 14:36) [snapback]44911[/snapback]
Помогите, пожалуйста составить правильный UPDATE.
Нужно, чтобы поле ONTOP стало равно '1' у элемента с ID=36 и у всех элементов таблицы с таким же полем DOCNAME. smile.gif
Вроде не очень сложно, но не получается...

Код
UPDATE `DOCUMENTS` SET `ONTOP` = 1 WHERE `ID` = '36' AND `DOCNAME` = (SELECT `DOCNAME` FROM `DOCUMENTS` WHERE `ID` = '36')


Спасибо!


UPDATE
`DOCUMENTS`
SET
`ONTOP` = 1
WHERE
`ID` = '36' OR
`DOCNAME` = (SELECT `DOCNAME` FROM `DOCUMENTS` WHERE `ID` = '36')


Вот вроде как-то так ! smile.gif



а вообще, лучше даже так

UPDATE
`DOCUMENTS`
SET
`ONTOP` = 1
WHERE
`DOCNAME` = (SELECT `DOCNAME` FROM `DOCUMENTS` WHERE `ID` = '36')

ведь и ID =36 тоже попадёт под это правило smile.gif

Спустя 1 минута (31.07.2008 - 14:59) QuadMan написал(а):
Цитата(jetistyum @ 31.7.2008, 11:55) [snapback]44913[/snapback]
UPDATE
`DOCUMENTS`
SET
`ONTOP` = 1
WHERE
`ID` = '36' OR
`DOCNAME` = (SELECT `DOCNAME` FROM `DOCUMENTS` WHERE `ID` = '36')


Вот вроде как-то так ! smile.gif

SQL на это ругается - #1093 - You can't specify target table 'DOCUMENTS' for update in FROM clause

мне кажется, тут дело в синтаксисе запроса UPDATE... как-то по-другому его описать нужно...

Спустя 3 секунды (31.07.2008 - 14:59) jetistyum написал(а):
Цитата(jetistyum @ 31.7.2008, 14:55) [snapback]44913[/snapback]
Цитата(QuadMan @ 31.7.2008, 14:36) [snapback]44911[/snapback]
Помогите, пожалуйста составить правильный UPDATE.
Нужно, чтобы поле ONTOP стало равно '1' у элемента с ID=36 и у всех элементов таблицы с таким же полем DOCNAME. smile.gif
Вроде не очень сложно, но не получается...

Код
UPDATE `DOCUMENTS` SET `ONTOP` = 1 WHERE `ID` = '36' AND `DOCNAME` = (SELECT `DOCNAME` FROM `DOCUMENTS` WHERE `ID` = '36')


Спасибо!


UPDATE
`DOCUMENTS`
SET
`ONTOP` = 1
WHERE
`ID` = '36' OR
`DOCNAME` = (SELECT `DOCNAME` FROM `DOCUMENTS` WHERE `ID` = '36')


Вот вроде как-то так ! smile.gif



а вообще, лучше даже так

UPDATE
`DOCUMENTS`
SET
`ONTOP` = 1
WHERE
`DOCNAME` = (SELECT `DOCNAME` FROM `DOCUMENTS` WHERE `ID` = '36')

ведь и ID =36 тоже попадёт под это правило smile.gif

Спустя 8 минут, 45 секунд (31.07.2008 - 15:07) QuadMan написал(а):
Цитата(jetistyum @ 31.7.2008, 11:59) [snapback]44916[/snapback]
а вообще, лучше даже так

UPDATE
`DOCUMENTS`
SET
`ONTOP` = 1
WHERE
`DOCNAME` = (SELECT `DOCNAME` FROM `DOCUMENTS` WHERE `ID` = '36')

ведь и ID =36 тоже попадёт под это правило smile.gif


Как я понимаю, SQL не позволяет использовать в подзапросе таблицу, которую собираешься изменять... как от этого избавится - неясно...

Спустя 42 минуты, 35 секунд (31.07.2008 - 15:50) jetistyum написал(а):
Цитата(QuadMan @ 31.7.2008, 15:07) [snapback]44919[/snapback]
Цитата(jetistyum @ 31.7.2008, 11:59) [snapback]44916[/snapback]
а вообще, лучше даже так

UPDATE
`DOCUMENTS`
SET
`ONTOP` = 1
WHERE
`DOCNAME` = (SELECT `DOCNAME` FROM `DOCUMENTS` WHERE `ID` = '36')

ведь и ID =36 тоже попадёт под это правило smile.gif


Как я понимаю, SQL не позволяет использовать в подзапросе таблицу, которую собираешься изменять... как от этого избавится - неясно...


ХМ.. точно..
тогда два запроса..
1. SELECT `DOCNAME` FROM `DOCUMENTS` WHERE `ID` = '36'
2. UPDATE....

Спустя 5 минут, 21 секунда (31.07.2008 - 15:55) sergeiss написал(а):
Мне так сдается, что надо написать условие немного по-другому:
WHERE
`DOCNAME` IN (SELECT `DOCNAME` FROM `DOCUMENTS` WHERE `ID` = '36')

Спустя 1 час, 5 минут, 56 секунд (31.07.2008 - 17:01) QuadMan написал(а):
Цитата(sergeiss @ 31.7.2008, 12:55) [snapback]44923[/snapback]
Мне так сдается, что надо написать условие немного по-другому:
WHERE
`DOCNAME` IN (SELECT `DOCNAME` FROM `DOCUMENTS` WHERE `ID` = '36')

Ничего не помогает.. не хочет MySQL в подзапросе использовать таблицу, которая обновляется... sad.gif

Спустя 1 час, 40 минут, 43 секунды (31.07.2008 - 18:42) sergeiss написал(а):
Посидел я тут, помедитировал, глядя на запрос... И переписал свой ответ.

Тут получается интересный момент smile.gif Почему бы не написать
Код
UPDATE
`DOCUMENTS`
SET
`ONTOP` = 1
WHERE `ID`=36

Зачем приплетать сюда еще одно поле??? Про указанном подзапросе предполагается, что надо изменить нечто в таблице, в которой имя документа такое, что ему соответствует идентификатор номер 36... А это как раз и есть, что просто идентификатор равен 36. DOCNAME тут лишний.

Спустя 44 минуты, 4 секунды (31.07.2008 - 19:26) QuadMan написал(а):
Цитата(sergeiss @ 31.7.2008, 15:42) [snapback]44932[/snapback]
Посидел я тут, помедитировал, глядя на запрос... И переписал свой ответ.

Тут получается интересный момент smile.gif Почему бы не написать
Код
UPDATE
`DOCUMENTS`
SET
`ONTOP` = 1
WHERE `ID`=36

Зачем приплетать сюда еще одно поле??? Про указанном подзапросе предполагается, что надо изменить нечто в таблице, в которой имя документа такое, что ему соответствует идентификатор номер 36... А это как раз и есть, что просто идентификатор равен 36. DOCNAME тут лишний.


Нет, не лишний. smile.gif Может быть много документов с одинаковым именем, но разными ID smile.gif В этом вся загвоздка...

Спустя 12 секунд (31.07.2008 - 19:26) Professor написал(а):
Цитата
Тут получается интересный момент Почему бы не написать

Ты не совсем понял.
Человеку надо что бы ONTOP изменился у всех,у кого DOCNAME такой же как и у 36 го номера.

я тоже помедитировал,но по ходу только2мя запросами.

Спустя 13 часов, 32 минуты, 55 секунд (1.08.2008 - 08:59) sergeiss написал(а):
Тогда ХЗ...
На самом деле, я использую PostgreSQL. А MySQL удалил после недели упорной борьбы с его "особенностями".

В PostgreSQL я проверил, всё работает "как часы".
Код
---
Создал базу с такой струкутурой:
CREATE TABLE docs
(
  id serial NOT NULL,
  docname text,
  id_sub integer
)
поле id - целое с автоувеличением

---
Накидал в таблицу произвольные данные:
select * from docs order by id:

id;docname;id_sub
1;"Doc 1";1
2;"Doc 1";4
3;"Doc 7";4
4;"Doc 7";3
5;"Doc 3";3
6;"Doc 1";33
7;"Doc 5";3
8;"Doc 6";2
9;"Doc 1";2

---
Проверил подвыборку:
select *
from docs
where docname in (select docname from docs where id=4)

3;"Doc 7";4
4;"Doc 7";3

---
Запустил основной запрос на изменение
update docs
set id_sub=120
where docname in (select docname from docs where id=4)

---
Проверил, что получилось в итоге
select * from docs order by id:
1;"Doc 1";1
2;"Doc 1";4
3;"Doc 7";120
4;"Doc 7";120
5;"Doc 3";3
6;"Doc 1";33
7;"Doc 5";3
8;"Doc 6";2
9;"Doc 1";2


Возможно, какие-то специфические настройки есть в MySQL?

Либо, попробовать использовать нечто типа INSERT INTO .... SELECT .... ON DUPLICATE KEY UPDATE .....?

Спустя 1 час, 15 минут (1.08.2008 - 10:14) QuadMan написал(а):
Цитата(sergeiss @ 1.8.2008, 5:59) [snapback]44975[/snapback]
Тогда ХЗ...
На самом деле, я использую PostgreSQL. А MySQL удалил после недели упорной борьбы с его "особенностями".

В PostgreSQL я проверил, всё работает "как часы".
Код
---
Создал базу с такой струкутурой:
CREATE TABLE docs
(
  id serial NOT NULL,
  docname text,
  id_sub integer
)
поле id - целое с автоувеличением

---
Накидал в таблицу произвольные данные:
select * from docs order by id:

id;docname;id_sub
1;"Doc 1";1
2;"Doc 1";4
3;"Doc 7";4
4;"Doc 7";3
5;"Doc 3";3
6;"Doc 1";33
7;"Doc 5";3
8;"Doc 6";2
9;"Doc 1";2

---
Проверил подвыборку:
select *
from docs
where docname in (select docname from docs where id=4)

3;"Doc 7";4
4;"Doc 7";3

---
Запустил основной запрос на изменение
update docs
set id_sub=120
where docname in (select docname from docs where id=4)

---
Проверил, что получилось в итоге
select * from docs order by id:
1;"Doc 1";1
2;"Doc 1";4
3;"Doc 7";120
4;"Doc 7";120
5;"Doc 3";3
6;"Doc 1";33
7;"Doc 5";3
8;"Doc 6";2
9;"Doc 1";2


Возможно, какие-то специфические настройки есть в MySQL?

Либо, попробовать использовать нечто типа INSERT INTO .... SELECT .... ON DUPLICATE KEY UPDATE .....?


Спасибо! Значит, скорее всего, это действительно, особенность MySQL sad.gif((

Спустя 3 часа, 9 минут, 3 секунды (1.08.2008 - 13:23) Alchemist написал(а):
Долго медитировал глядя на этот топик...

Дети мои, запомните ! Для успешной медитации необходимо курить мануалы !

Цитата(MySQL Manual)
In general, you cannot modify a table and select from the same table in a subquery. For example, this limitation applies to statements of the following forms:

Код
DELETE FROM t WHERE ... (SELECT ... FROM t ...);
UPDATE t ... WHERE col = (SELECT ... FROM t ...);
{INSERT|REPLACE} INTO t (SELECT ... FROM t ...);

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

Там же в мануале вам предлагается решение:
Цитата(MySQL Manual)
Exception: The preceding prohibition does not apply if you are using a subquery for the modified table in the FROM clause. Example:

Код
UPDATE t ... WHERE col = (SELECT * FROM (SELECT ... FROM t...) AS _t ...);

Here the prohibition does not apply because the result from a subquery in the FROM clause is stored as a temporary table, so the relevant rows in t have already been selected by the time the update to t takes place.

Основная мысль - подзапросы расположеные в FROM всегда выполняются только один раз и сохраняются во временной таблице. Тогда ничего не мешает обращаться к ней опять и опять, её-то мы не изменяем...

Ладно, покурили и будя... Назад к нашим... гм... проблемам.
Можно, конечно, переписать запрос добавив внутри подзапроса еще один подзапрос, как это описано в мануале. Но мне кажется более простым будет вариант:

Код
UPDATE `DOCUMENTS` AS `changing`
      INNER JOIN `DOCUMENTS` AS `selector` USING(`DOCNAME`)
SET `changing`.`ONTOP` = 1
WHERE `selector`.`ID` = '36'


Всех благ !

PS: http://dev.mysql.com/doc/refman/5.0/en/sub...strictions.html

Спустя 1 час, 40 минут, 35 секунд (1.08.2008 - 15:04) QuadMan написал(а):
Alchemist
Огромное спасибо за разъяснения!!!! smile.gif Теперь буду еще лучше курить мануалы smile.gif)

А вот все-таки одну вещь я не понял... smile.gif
Цитата
Это происходит потому, что подзапросы расположеные в WHERE при определенных условиях могут выполняться для каждой строки внешнего запроса. А поскольку вы в процессе меняете таблицу из которой берете данные, то результат такого изменения становится непредсказуем.


но ведь в моем подзапросе не изменялись колонки, которые обновлялись в UPDATE... UPDATE затрагивает только ONTOP, а подселект выбирает DOCNAME по ID. smile.gif Вроде бы ничего непредсказуемого не происходит в таком случае...

Спустя 1 час, 17 минут, 12 секунд (1.08.2008 - 16:21) Alchemist написал(а):
Цитата(QuadMan @ 1.8.2008, 15:04) [snapback]45016[/snapback]
но ведь в моем подзапросе не изменялись колонки, которые обновлялись в UPDATE... UPDATE затрагивает только ONTOP, а подселект выбирает DOCNAME по ID. smile.gif Вроде бы ничего непредсказуемого не происходит в таком случае...

Ты прав, в твоем случае не происходит. Но это всего лишь частный (и весьма простой) случай общего правила. Ведь подзапрос в свою очередь может быть довольно сложным запросом со своими позапросами и разветвлениями. А если мы еще учтем, что подзапросы могут обращаться и использовать поля таблиц из внешних запросов... Вобщем без поллитры не всегда разберешься.

На самом деле, теоретически, всё это можно проверить и разделить на случаи "можно" и "нельзя". Но это теоретически, а практически создатели MySQL, по-видимому, еще не нашли эффективного механизма для этого. Но они продолжают искать smile.gif
Цитата(MySQL Manual)
...Another restriction is that currently you cannot modify a table and select from the same table in a subquery.

Спустя 2 часа, 58 минут, 22 секунды (1.08.2008 - 19:19) sergeiss написал(а):
Но тогда получается, что создатели PostgreSQL нашли этот механизм?

Спустя 9 часов, 32 минуты, 23 секунды (2.08.2008 - 04:52) Alchemist написал(а):
Цитата(sergeiss @ 1.8.2008, 19:19) [snapback]45046[/snapback]
Но тогда получается, что создатели PostgreSQL нашли этот механизм?

Возможно...
Или они не разрешают делать что-то другое в запросах, что MySQL позволяет (например нельзя делать зависимые подзапросы)...
Или у них другой алгоритм обработки запроса/подзапроса...
Или другой алгоритм изменения данных (например внутренние транзакции)...
Или они просто предполагают, что юзер сам должен думать что он делает...

Вобщем тут много причин может быть. Я, увы, не копенгаген в постгре, чтобы конкретно указать на нее...


_____________
Быстрый ответ:

 Графические смайлики |  Показывать подпись
Здесь расположена полная версия этой страницы.
Invision Power Board © 2001-2024 Invision Power Services, Inc.