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:

  1. CREATE TABLE kategorie (
  2. id INT NOT NULL AUTO_INCREMENT,
  3. nazwa VARCHAR(255),
  4. position INT,
  5. 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:

  1. INSERT INTO kategorie(nazwa, position) VALUES (
  2. :nazwa, (SELECT IFNULL(MAX(position) + 1, 1) FROM kategorie)
  3. )

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:

  1. INSERT INTO kategorie(nazwa, position) VALUES (
  2. :nazwa, (
  3. SELECT IFNULL(x, 1) FROM (SELECT MAX(position)+1 AS x FROM kategorie) AS subQuery
  4. ))

Ł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:

  1. INSERT INTO kategorie(nazwa, position) VALUES (:nazwa, 0);
  2. UPDATE kategorie
  3. INNER JOIN (SELECT MAX(position)+1 AS x FROM kategorie) AS subQuery
  4. SET position = x
  5. WHERE position = 0;

Proste? Proste.

ColdFusion - utracone hasło

Zapisuję to sobie tutaj, bo za każdym razem muszę szukać w sieci ;)

Metoda

1. Lokalizujemy plik neo-security.xml (jeżeli mamy CF zainstalowane na domyślnej ścieżce, to będzie w c:\CFusionMX7\lib\)

2. Szukamy ciągu:

  1. <var name='admin.security.enabled'>
  2.     <boolean value='true'/>
  3. </var>

3. Zamieniamy wartość na ‘false’

4. Zapisujemy i restartujemy serwer CF

Voila!