Podzapytania w INSERT
Taki typowy problem: tabela zawierająca pole, pozwalające użytkownikowi na dowolne ustalanie kolejności rekordów. Prawie każda aplikacja ma coś tego typu. W jednej z moich aplikacji była to płaska lista kategorii:
-
CREATE TABLE kategorie (
-
id INT NOT NULL AUTO_INCREMENT,
-
nazwa VARCHAR(255),
-
position INT,
-
PRIMARY KEY(id));
Dodanie rekordu do tej tablicy ma domyślnie umieścić go na końcu listy. Często spotykanym (i bardzo kiepskim) rozwiązaniem jest użycie dwóch zapytań: SELECT, który odczytuje aktualną wartość pola position oraz INSERT, który dodaje nowy rekord. A czy da się to zrobić jednym zapytaniem? Pierwszy pomysł jest następujący:
-
INSERT INTO kategorie(nazwa, position) VALUES (
-
:nazwa, (SELECT IFNULL(MAX(position) + 1, 1) FROM kategorie)
-
)
Fajny pomysł, prawda? Ma tylko tą drobną wadę, że nie działa.. próba jego uruchomienia skończy się komunikatem:
#1093 - You can't specify target table 'kategorie' for update in FROM clause
Jak to obejść? Najlepiej podzapytaniem:
-
INSERT INTO kategorie(nazwa, position) VALUES (
-
:nazwa, (
-
SELECT IFNULL(x, 1) FROM (SELECT MAX(position)+1 AS x FROM kategorie) AS subQuery
-
))
Ładnie, prawda? Opakowanie podzapytania w następne podzapytanie rozwiązuje zadanie. Niestety - tylko dla MySQL w wersji 5.0+. Użycie go na serwerze 4.1 kończy się tym samym komunikatem, co poprzednie… Szczerze mówiąc - nie chciało mi się kombinować. Spłodziłem coś takiego:
-
INSERT INTO kategorie(nazwa, position) VALUES (:nazwa, 0);
-
UPDATE kategorie
-
INNER JOIN (SELECT MAX(position)+1 AS x FROM kategorie) AS subQuery
-
SET position = x
-
WHERE position = 0;
Proste? Proste.
Komentarze (0)