«Подзапрос возвращает более 1 строки» при использовании `SET`

0
select tf.id from text_fields as tf WHERE tf.study_id NOT IN (select id from studies)

Я использую это, чтобы найти осиротевшие записи, и он отлично работает.

Однако, когда я пытаюсь присвоить результат var, используя SET, я получаю ошибку "Subquery возвращает более 1 строки".

SET @text_field_ids := (select tf.id from text_fields as tf WHERE tf.study_id NOT IN (select id from studies))

Для контекста я хочу использовать записи var, а затем text_fields, например

DELETE from text_fields WHERE id IN @text_field_ids

Кстати, я попытался передать подзапрос непосредственно DELETE, например:

DELETE from text_fields WHERE id IN (select id from text_fields as tf WHERE tf.study_id NOT IN (select id from studies))

Но это дает ошибку. You can't specify target table 'text_fields' for update in FROM clause потому что, по-видимому, вы не можете использовать You can't specify target table 'text_fields' for update in FROM clause таблицу из предложения WHERE.

  • 0
    Вы добавляете «предел»
  • 0
    почему бы НЕ DELETE from text_fields WHERE id IN (select tf.id from text_fields as tf WHERE tf.study_id NOT IN (select id from studies))
Показать ещё 2 комментария
Теги:

3 ответа

1

Обычный способ обхода ERROR 1093 (HY000): таблица "ПОЛЬЗОВАТЕЛИ" указана дважды, как в качестве цели для "DELETE", так и в качестве отдельного источника для ошибки данных - нажать немного более глубже, например, увидеть второе удаление [CN10 ]

MariaDB [sandbox]> SELECT ID FROM USERS;
+----+
| ID |
+----+
|  1 |
|  2 |
|  3 |
|  6 |
|  7 |
|  8 |
| 10 |
| 12 |
| 14 |
| 15 |
| 16 |
| 17 |
| 18 |
| 19 |
+----+
14 rows in set (0.00 sec)

MariaDB [sandbox]>
MariaDB [sandbox]> DELETE FROM USERS
    -> WHERE ID IN (SELECT ID FROM USERS WHERE ID IN (18,19))
    -> ;
ERROR 1093 (HY000): Table 'USERS' is specified twice, both as a target for 'DELETE' and as a separate source for data
MariaDB [sandbox]>
MariaDB [sandbox]> DELETE FROM USERS
    -> WHERE ID IN (SELECT ID FROM (SELECT ID FROM USERS WHERE ID IN (18,19)) U )
    -> ;
Query OK, 2 rows affected (0.11 sec)

MariaDB [sandbox]>
MariaDB [sandbox]> SELECT ID FROM USERS;
+----+
| ID |
+----+
|  1 |
|  2 |
|  3 |
|  6 |
|  7 |
|  8 |
| 10 |
| 12 |
| 14 |
| 15 |
| 16 |
| 17 |
+----+
12 rows in set (0.00 sec)
  • 0
    Это хороший хак, imho немного страдает от производительности, но, тем не менее, хороший.
  • 0
    Возможно, но некоторые сайты не позволяют создавать временные таблицы.
Показать ещё 1 комментарий
1

Вы можете использовать временную таблицу:

create temporary table if not exists mytmptable select tf.id as id from text_fields as tf WHERE tf.study_id NOT IN (select id from studies)

и затем вы можете использовать его в delete:

DELETE from text_fields WHERE id IN (select Id from mytmptable)
  • 0
    Это работает, спасибо. Но это было на удивление медленно, не очень большая проблема в моем случае, так как мне нужно было удалить только несколько тысяч строк.
  • 0
    Рад, что помогло
Показать ещё 1 комментарий
0

Поскольку запрос

select tf.id from text_fields as tf WHERE tf.study_id NOT IN (select id from studies)

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

select 'tf'.'id' from 'text_fields' as tf WHERE 'tf'.'study_id' NOT IN
(select 'id' from 'studies') into @text_field_ids;

или же

SELECT @text_field_ids := 'tf'.'id' from 'text_fields' as tf WHERE 'tf'.'study_id' NOT IN 
(select 'id' from 'studies');

подробнее об этом здесь

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

CREATE TEMPORARY TABLE IF NOT EXISTS temp_table ( INDEX('id') ) 
ENGINE=Memory 
AS (
    select 'tf'.'id' from 'text_fields' as 'tf' WHERE 'tf'.'study_id' NOT IN (select 'id' from 'studies')
);

# and remove the records with
delete from 'text_fields' where id in (select 'id' from 'temp_table')
  • 0
    Таким образом, переменная может содержать только одну строку ... хорошо, это объясняет, спасибо. Я пробовал выше, но Result consisted of more than one row :)
  • 0
    необязательно, использование `SET foo: =` `требует одного значения.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню