Podzapytanie to potężny sposób na znalezienie danych, których chcesz użyć w innym zapytaniu. Są one często używane w instrukcjach SELECT i UPDATE, aby uczynić te zapytania bardziej wydajnymi i łatwiejszymi w utrzymaniu.
Istnieje kilka różnych sposobów używania podzapytań w instrukcjach UPDATE. Przyjrzyjmy się każdemu z nich.
USTAW i podzapytanie
Pierwszą metodą, której się przyjrzymy, jest użycie podzapytania w klauzuli SET instrukcji UPDATE.
Załóżmy, że mieliśmy tabelę produktów, która wyglądała tak:
[identyfikator tabeli=29 /]
Przechowuje kilka informacji o różnych produktach sprzedawanych przez firmę.
Załóżmy, że firma zdecydowała się podnieść cenę produktu „Kanapa” (identyfikator produktu 1). Jednak zamiast ustalać konkretną cenę, chcą, aby była ona o 20% wyższa niż najdroższy produkt, jaki mają.
W tym celu możemy użyć podzapytania w klauzuli SET. Moglibyśmy użyć osobnych instrukcji, ale łatwiej jest utrzymać je przy użyciu jednej instrukcji.
Nasze oświadczenie wyglądałoby tak:
UPDATE product SET price = ( SELECT MAX(price) * 1.2 FROM product ) WHERE product_id = 1;
Widać, że klauzula SET zawiera podzapytanie, które znajduje wartość MAX kolumny ceny w tabeli produktów i mnoży ją przez 1,2, aby dodać 20%. Na koniec klauzula WHERE znajduje się poza podzapytaniem, aby zaktualizować tylko identyfikator produktu równy 1, ponieważ dotyczy on raczej UPDATE niż podzapytania.
Spowoduje to następującą zmianę:
[identyfikator tabeli=30 /]
SET i skorelowane podzapytanie
Innym sposobem użycia podzapytania w instrukcji UPDATE jest użycie skorelowanego podzapytania.
Działa podobnie jak w poprzednim przykładzie. Jednak skorelowane podzapytanie to podzapytanie, które odwołuje się do instrukcji zewnętrznej i może być częścią instrukcji UPDATE.
Korzystając z danych z poprzedniego przykładu (tabela produktów) firma chce dezaktywować wszystkie produkty, na które nie zostało złożone zamówienie. Dane do tego są przechowywane w tabeli order_line.
Jeśli napisaliśmy to jako skorelowane podzapytanie, zapytanie będzie wyglądało tak:
UPDATE product p SET active = ( SELECT CASE WHEN COUNT(*) > 0 THEN 'Y' ELSE 'N' END FROM order_line o WHERE o.product_id = p.product_id );
Podzapytanie wykona funkcję ILE.LICZB przy użyciu instrukcji CASE w celu określenia, czy zwróconą wartością jest Y czy N, w zależności od wartości ILE.LICZB. Jest obliczany dla każdego identyfikatora produktu i pasuje do zapytania zewnętrznego.
Spowoduje to aktywną kolumnę dla niektórych produktów ustawionych na Y, a innych na N:
[identyfikator tabeli=31 /]
GDZIE Większe niż podzapytanie
Możliwe jest również użycie podzapytania w klauzuli WHERE. Podobnie jak w poprzednich przykładach, można to zrobić, aby usunąć oddzielny krok polegający na znalezieniu wartości do aktualizacji, a następnie uruchomieniu zapytania w celu jej aktualizacji.
Możemy kontynuować pracę z naszym przykładem z poprzednich kroków. Załóżmy, że firma chce aktywować produkty, których cena jest powyżej średniej. Aby to zrobić, możemy dodać podzapytanie do klauzuli WHERE.
Najpierw dezaktywuj wszystkie produkty.
UPDATE product SET active = ’N’;
Następnie zaktualizuj tabelę za pomocą naszego podzapytania.
UPDATE product SET active = 'Y' WHERE price > ( SELECT AVG(price) FROM product );
Spowoduje to ustawienie aktywnej wartości na Y dla wszystkich rekordów, których cena jest powyżej średniej.
Tabela wygląda teraz tak:
[identyfikator tabeli=32 /]
Pokazuje 2 rekordy z aktywną wartością Y, ponieważ są powyżej średniej.
Ten rodzaj zapytania można również uruchomić z innymi operatorami, które zezwalają na pojedynczą wartość, na przykład
GDZIE W podzapytanie
Możemy również użyć podzapytania z operatorem IN w klauzuli WHERE.
Jest to podobne do poprzedniego przykładu, w którym użyto operatora większego niż dla pojedynczej wartości. Operator IN może być zastosowany do wielu wartości.
Załóżmy, że firma chciała zaktualizować ceny niektórych produktów, które były jedyną pozycją w kategorii. Ceny musiałyby zostać obniżone o połowę.
Nasze zapytanie może wyglądać tak:
UPDATE product SET price = price / 2 WHERE category_id IN ( SELECT category_id FROM product GROUP BY category_id HAVING COUNT(*) = 1 );
Podzapytanie znajduje wszystkie wartości id_kategorii, gdzie LICZBA wynosi 1. Nie musimy mieć LICZBA w części SELECT podzapytania, jednak jeśli to zrobimy, zapytanie wyświetli błąd.
Polecenie UPDATE zaktualizuje cenę, przy której kategoria spełnia kryteria podzapytania.
Nasze wyniki będą wtedy wyglądać tak:
[identyfikator tabeli=33 /]
Dane wyglądają bardzo podobnie. Jednak produkt o identyfikatorze kategorii 1 został zaktualizowany do połowy pierwotnego kosztu, ponieważ jest to jedyny produkt w swojej kategorii.
AKTUALIZUJ podzapytanie
Na koniec możesz użyć podzapytania w instrukcji UPDATE, aby zaktualizować tabelę.
W poprzednich przykładach użyliśmy właśnie tabeli produktów. Możesz jednak użyć podzapytania zamiast tabeli produktów, która zwróci zestaw wyników, który można zaktualizować.
Zestaw wyników musi być aktualizowalny, podobnie jak w przypadku tworzenia obiektu VIEW i próby jego aktualizacji. Musi być prosty i mieć klucz podstawowy.
W związku z tym, korzystając z naszych poprzednich przykładów, załóżmy, że firma chce zmienić kategorię dla wszystkich produktów z kategorii 4 na kategorię 5.
Nasze zapytanie może wyglądać tak:
UPDATE ( SELECT product_id, category_id FROM product) SET category_id = 5 WHERE category_id = 4;
To prosty przykład, który demonstruje tę koncepcję. Tabela została zastąpiona instrukcją SELECT, która pokazuje tylko dwie kolumny tabeli.
Wynikiem tego zapytania byłyby:
[identyfikator tabeli=34 /]
Ten sam wynik można uzyskać, przenosząc klauzulę WHERE do instrukcji UPDATE:
UPDATE ( SELECT product_id, category_id FROM product WHERE category_id = 4) SET category_id = 5;
Wniosek
Używanie podzapytania w instrukcji UPDATE może być dobrym sposobem na poprawę łatwości utrzymania zapytań. Może również zmniejszyć liczbę kroków wymaganych do aktualizacji danych, kompresując dwa lub więcej zapytań w jedno zapytanie.