MySQL INSERT Использование подзапроса с COUNT () для той же таблицы - PullRequest
5 голосов
/ 27 мая 2011

У меня проблемы с получением INSERT запроса для правильного выполнения, и я не могу найти ничего в Google или Stack Overflow, которое решает эту конкретную проблему.

Я пытаюсь создатьпростая таблица для избранных записей, где entry_id сохраняется в таблице вместе с ее текущим порядком.

Мой желаемый вывод такой:

Если таблица featured в настоящее время имеет этитри записи:

featured_id    entry_id    featured_order
1              27          0
2              54          1
4              23          2

Я хочу сохранить следующую запись с featured_order = 3.

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

INSERT INTO `featured`
(
    `entry_id`, `featured_order`
)
VALUES
(
    200,
    (SELECT COUNT(*) AS `the_count` FROM `featured`)
)

Ошибка, которую я получаю: You can't specify target table 'featured' for update in FROM clause.

Может ли кто-нибудь помочь с решением, которое получает счет, не вызывая ошибки?

Заранее спасибо!

Ответы [ 5 ]

14 голосов
/ 27 мая 2011

Вот классная вещь: MySQL INSERT . . . SELECT:

INSERT INTO `featured`
(
    `entry_id`, `featured_order`
)
SELECT 200, COUNT(*) + 1
FROM `featured`

Никаких подзапросов не требуется.


@ Богемский имеет хороший момент:

Лучше использовать max (featured_order) + 1, если вы используете этот подход

Так что лучшим запросом, вероятно, будет:

INSERT INTO `featured`
(
    `entry_id`, `featured_order`
)
SELECT 200, MAX(`featured_order`) + 1
FROM `featured`

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


Потенциальная проблема с запросом 1 состоит в том, что если вы когда-нибудь удалите строку, ранг будет отброшен, и вы получитедубликат в featured_order.Со вторым запросом это не проблема, но у вас будут пробелы, как если бы вы использовали столбец с автоинкрементом.

Если вам абсолютно необходим заказ без пробелов, лучшее из известных мне решенийдля запуска этой серии запросов:

SET @pos:=0;

DROP TABLE IF EXISTS temp1;

CREATE TEMPORARY TABLE temp1 LIKE featured;

ALTER TABLE featured ORDER BY featured_order ASC;

INSERT INTO temp1 (featured_id, entry_id, featured_order) 
SELECT featured_id, entry_id, @pos:=@pos+1 FROM words;

UPDATE featured 
JOIN temp1 ON featured.featured_id = temp1.featured_id 
SET featured.rank = temp1.rank;

DROP TABLE temp1;

Всякий раз, когда вы удаляете строку

2 голосов
/ 19 октября 2016
INSERT INTO `featured`
(
    `entry_id`, `featured_order`
)
VALUES
(
    200,
    (SELECT COUNT(*) AS `the_count` FROM `featured` F1)
)

Исправление - это просто добавление псевдонима таблицы "F1". (Как предложено красавицей Надар чуть выше)

Это должно быть лучшим решением в среде с несколькими базами данных, поскольку тот же синтаксис отлично работает на mysql + oracle + db2


Я также предлагаю улучшение по сравнению с:

  • ВЫБЕРИТЕ СЧЕТЧИК (*) +1 (Проблема: при удалении строки вы получаете ошибку)

  • SELECT MAX (featured_order) +1 (проблема: самая первая ошибка строки)

SELECT (COALESCE (MAX (featured_order), 0) +1) (без проблем)

2 голосов
/ 27 мая 2011

Использовать триггер:

drop trigger if exists featured_insert_trigger; 

delimiter //
create trigger featured_insert_trigger before insert on featured
for each row
begin
  set new.featured_order = ifnull((select max(featured_order) from featured), -1) + 1;
end; //
delimiter ;

Теперь ваши вставки выглядят так:

insert into featured (entry_id) values (200);

featured_order будет установлено на самое высокое значение featured_order плюс один. Это обслуживает строки, которые удаляются / обновляются и всегда гарантируют уникальность.

ifnull есть, если в таблице нет строк, и в этом случае первое значение будет равно нулю.

Этот код был протестирован и работает правильно.

1 голос
/ 27 мая 2011

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

INSERT INTO `featured`
(
    `entry_id`, `featured_order`
)
VALUES
(
    200,
    (SELECT COUNT(*) AS `the_count` FROM `featured` as f1)
)
0 голосов
/ 27 мая 2011

Из руководства MySQL относительно подзапросов:

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

Возможно, псевдоним или объединение (иначе бесполезное) в подзапросе помогло бы здесь.

РЕДАКТИРОВАТЬ: Оказывается, есть обходной путь. Обходной путь описан http://www.xaprb.com/blog/2006/06/23/how-to-select-from-an-update-target-in-mysql/.

...