Jak wstawić klauzulę „if” do ciągu SQL?

190

Oto, co chcę zrobić na mojej bazie danych MySQL .

Chciałbym zrobić:

SELECT *
    FROM itemsOrdered
    WHERE purchaseOrder_ID = '@purchaseOrdered_ID'
        AND status = 'PENDING'

Jeśli to nie zwróci żadnych wierszy, co jest możliwe if(dr.HasRows == false), utworzę teraz UPDATEw purchaseOrderbazie danych:

UPDATE purchaseOrder
    SET purchaseOrder_status = 'COMPLETED'
    WHERE purchaseOrder_ID = '@purchaseOrder_ID'

Jak mogę sprawić, by ten proces był nieco krótszy?

John Ernest Guadalupe
źródło
4
baza danych itemsOrders ma unikalny identyfikator o nazwie itemsOrdered_IDi ma powtarzające się purchaseOrder_IDwartości
John Ernest Guadalupe
1
z purchaseorderdrugiej strony baza danych ma unikalny identyfikatorpurchaseOrder_ID
John Ernest Guadalupe,

Odpowiedzi:

410

W przypadku konkretnego zapytania możesz wykonać:

UPDATE purchaseOrder
    SET purchaseOrder_status = 'COMPLETED'
    WHERE purchaseOrder_ID = '@purchaseOrder_ID' and
          not exists (SELECT *
                      FROM itemsOrdered WHERE purchaseOrder_ID = '@purchaseOrdered_ID' AND status = 'PENDING'
                     )

Mogę jednak zgadywać, że zapętlasz się na wyższym poziomie. Aby ustawić wszystkie takie wartości, spróbuj tego:

UPDATE purchaseOrder
    SET purchaseOrder_status = 'COMPLETED'
    WHERE not exists (SELECT 1
                      FROM itemsOrdered
                      WHERE itemsOrdered.purchaseOrder_ID = purchaseOrder.purchaseOrdered_ID AND
                            status = 'PENDING'
                      limit 1
                     )
Gordon Linoff
źródło
26
W rzeczywistości w MySQL skorelowane podzapytanie powinno być jednym z najbardziej wydajnych podejść, zakładając, że istnieje indeks pozycji itemsOrders.purchaseOrder_ID.
Gordon Linoff,
8
@eggyal. . . Zgadzam się, że bez indeksu skorelowana wersja jest być może mniej wydajna niż łączenie (zależy od różnych czynników, takich jak mnożenie wierszy). Jednak z indeksem powinno być lepsze niż łączenie, ponieważ powinno zatrzymać skanowanie indeksu przy pierwszym dopasowaniu. Sprawdź dev.mysql.com/doc/refman/5.5/en/… .
Gordon Linoff,
53

Możesz użyć UPDATEskładni wielostołowej, aby uzyskać efekt ANTI-JOINmiędzy purchaseOrderi itemsOrdered:

UPDATE purchaseOrder p LEFT JOIN itemsOrdered i
    ON p.purchaseOrder_ID = i.purchaseOrder_ID
   AND i.status = 'PENDING'
SET    p.purchaseOrder_status = 'COMPLETED'
WHERE  p.purchaseOrder_ID = '@purchaseOrder_ID'
   AND i.purchaseOrder_ID IS NULL
Eggyal
źródło
47

Ponieważ MySQL nie obsługuje if exists(*Your condition*) (*Write your query*), możesz uzyskać klauzulę „if”, pisząc w ten sposób:

(*Write your insert or update query*) where not exists (*Your condition*)
Ranjit Singh
źródło
27

Możesz również użyć następującego zapytania, aby sprawdzić, czy rekord istnieje, a następnie go zaktualizować:

if not exists(select top 1 fromFROM itemsOrdered
    WHERE purchaseOrder_ID = '@purchaseOrdered_ID'
        AND status = 'PENDING' )
Begin

UPDATE purchaseOrder 
    SET purchaseOrder_status = 'COMPLETED'
    WHERE purchaseOrder_ID = '@purchaseOrder_ID

End
Santosh Shirkar
źródło
22
Select FROM t1
    WHERE s11 > ANY
        (SELECT col1,col2 FROM t2
            WHERE NOT EXISTS
                (SELECT * FROM t3
                    WHERE ROW(5*t2.s1,77)=
                        (SELECT 50,11*s1 FROM t4 UNION SELECT 50,77 FROM
                            (SELECT * FROM t5) AS t5)));
sikandar bakht syed
źródło
4
Próbuję zobaczyć, jak to w ogóle odpowiada na pytanie?
Mayer
1
@ theMayer Me też, ale to całkiem niezła odpowiedź
Gabriel
2
Gratulacje, Twój kod został wybrany jako kod zaciemniony.
Vishwanath Dalvi
1
Sądzę, że jest to przykład tego, co jeszcze możemy zrobićSQL
Top-Master
13
if not exists(select top 1 fromFROM itemsOrdered
    WHERE purchaseOrder_ID = '@purchaseOrdered_ID'
        AND status = 'PENDING' )
Begin

UPDATE purchaseOrder 
    SET purchaseOrder_status = 'COMPLETED'
    WHERE purchaseOrder_ID = '@purchaseOrder_ID

End
CH Hamza Ahmad
źródło
7
świetnie będzie, jeśli wyjaśnisz również odpowiedź, tylko odpowiedzi na kod nie są pomocne dla przyszłych użytkowników
Kumar Saurabh
9

po SQL Server 2008 zapewnia Mergeoperację wstawiania, aktualizowania i usuwania na podstawie instrukcji pojedynczego dopasowania, która również umożliwia dołączanie. poniższy przykład może ci pomóc.

MERGE Target AS T
USING Source AS S
ON (T.EmployeeID = S.EmployeeID) 
WHEN NOT MATCHED BY TARGET AND S.EmployeeName LIKE 'S%' 
    THEN INSERT(EmployeeID, EmployeeName) VALUES(S.EmployeeID, S.EmployeeName)
WHEN MATCHED 
    THEN UPDATE SET T.EmployeeName = S.EmployeeName
WHEN NOT MATCHED BY SOURCE AND T.EmployeeName LIKE 'S%'
    THEN DELETE 
OUTPUT $action, inserted.*, deleted.*;

w ten sposób możesz wstawiać, aktualizować i usuwać w jednym zestawieniu.

a więcej informacji można znaleźć w oficjalnych dokumentach na https://technet.microsoft.com/en-us/library/bb522522(v=sql.105).aspx

Lalji Dhameliya
źródło
7

Jeśli tabela zawiera miliony rekordów, następujące zapytanie będzie działać szybko.

UPDATE PO
SET PO.purchaseOrder_status = 'COMPLETED'
FROM purchaseOrder PO
LEFT OUTER JOIN itemsOrdered IOD ON IOD.purchaseOrder_ID = PO.purchaseOrdered_ID and IOD.status = 'PENDING'
WHERE IOD.purchaseOrder_ID IS NULL
Amit Prajapati
źródło
1

Możesz zadeklarować zmienną zawierającą liczbę zwróconych wyników przy wybranym zapytaniu. Następnie można uruchomić instrukcję aktualizacji, jeśli ta zmienna jest większa niż 0

    Declare @ResultCount int
    SELECT @ResultCount = count(*) FROM itemsOrdered WHERE purchaseOrder_ID = '@purchaseOrdered_ID' AND status = 'PENDING'        
    If @ResultCount > 0
UPDATE purchaseOrder SET purchaseOrder_status = 'COMPLETED' WHERE purchaseOrder_ID = '@purchaseOrder_ID'        
Alireza
źródło