2011-04-05 15 views
9

La mia dichiarazione UPDATE va lungo le linee di:SQL - Aggiornamento con un'istruzione CASE, devo ripetere lo stesso CASE più volte?

UPDATE customer 
SET forenames=ot.forenames, 
    surname = 

CASE WHEN ot.safeplace IS NULL 
THEN 'test SAFEPLACE IS NULL' 
ELSE 'test Safeplace IS NOT NULL' 
END, 

    middlename = 

CASE WHEN ot.safeplace IS NULL 
THEN 'test2 SAFEPLACE IS NULL' 
ELSE 'test2 Safeplace IS NOT NULL' 
END, 

FROM order_transaction ot 

WHERE customer.custid = ot.custid 
AND ot.trans_orderid = 5678 
AND customer.custid = 1234 

Le opere di cui sopra. In pratica controlla se un campo in un'altra tabella è NULL o no, e quindi aggiorna il "cognome" del cliente e il "nome-chiave" di conseguenza. Come puoi vedere sopra, ho ripetuto la stessa dichiarazione CASE due volte. La mia domanda è - esiste un modo per specificare una volta l'istruzione CASE?

Il punto è che, se dico di voler aggiornare 10 campi in base a una determinata condizione, devo includere 10 condizioni CASE simili? Oppure il SQL può essere migliorato per avere un solo CASE e 10 aggiornamenti sul campo all'interno delle clausole WHEN/ELSE?

(Sto utilizzando un database Postgresql 8.2 ma credo che quanto sopra sia standard SQL).

Molte grazie, Rishi

risposta

3

Se si voleva eseguire l'CASE sullo stesso livello di query, si avrebbe bisogno di ripetere il caso, proprio come si farebbe ripetere una colonna calcolata in un gruppo dalla clausola.

vostra query di esempio non rivela affatto quello che si vuole fare, sono davvero aggiornando tutti record sullo stesso valore (testo fisso), così come tutte le colonne per record. Se hai aggiornato per rendere la domanda più pertinente, probabilmente c'è una risposta migliore.


Ma per il momento, per la vostra query specifica, si può usare qualcosa di simile

UPDATE customer 
SET forenames=ot.forenames, 
    surname = fixedText, 
    middlename = fixedText  
FROM (select o.*, CASE 
     WHEN safeplace IS NULL 
     THEN 'test2 SAFEPLACE IS NULL' 
     ELSE 'test2 Safeplace IS NOT NULL' 
     END fixedText 
     from order_transaction o) ot 
WHERE customer.custid = ot.custid 
AND ot.trans_orderid = 5678 
AND customer.custid = 1234 
+0

Non proprio la soluzione migliore Richard.Come prima selezioni, esplora la tabella e aggiunge il risultato e successivamente lo filtra. –

+1

@Dumitrescu Bogdan/Non credo che lo faccia. Poiché PostgreSQL srotolerà la query per applicare i filtri nella sottoquery, ma conserverà comunque la possibilità di utilizzare la colonna definita (calcolata) – RichardTheKiwi

+0

La sintassi dell'OP non è SQL standard (si noti inoltre che lo standard SQL è internazionale e la "A" in "ANSI" sta per "americano", quindi "SQL conforme all'ISO" sarebbe più appropriato qui :) – onedaywhen

0

Se è necessario copiare il caso esatto più volte (molto più allora 2) è possibile utilizzare la query successiva. Ma devi davvero copiare il caso, non con test e test2 (che non è esattamente lo stesso). Evidentemente se hai bisogno di concatenare un testo come test/test 2 o qualsiasi cosa a un risultato, puoi farlo nell'istruzione select. ex: surname = 'test' + st.result quindi ci sono alcune possibilità per fare alcuni 'hack'.

UPDATE customer 
SET forenames=ot.forenames, 
    surname = st.result, 
    middlename = st.result 

FROM order_transaction ot 
JOIN (select 1 as ID,'test SAFEPLACE IS NULL' as result 
     union 
     select 2,'test SAFEPLACE IS NULL') st on case when ot.safeplace is null then 1 else 2 end = st.id 

WHERE customer.custid = ot.custid 
AND ot.trans_orderid = 5678 
AND customer.custid = 1234 
7

Credo che quanto sopra è SQL standard

In realtà, non lo è. SQL standard non ha una sintassi UPDATE..FROM. Piuttosto, è necessario utilizzare una sottoquery scalare per ogni clausola SET più un'altra per EXISTS, quindi la sintassi Standard è ancora più ripetitiva, ad es.

UPDATE customer 
    SET forenames = (
        SELECT ot.forenames 
         FROM order_transaction AS ot 
        WHERE customer.custid = ot.custid 
          AND ot.trans_orderid = 5678 
        ), 
     surname = (
        SELECT CASE 
          WHEN ot.safeplace IS NULL 
           THEN 'test SAFEPLACE IS NULL' 
          ELSE 'test Safeplace IS NOT NULL' 
         END 
        FROM order_transaction AS ot 
        WHERE customer.custid = ot.custid 
         AND ot.trans_orderid = 5678 
       ), 
     middlename = (
        SELECT CASE 
           WHEN ot.safeplace IS NULL 
            THEN 'test SAFEPLACE IS NULL' 
           ELSE 'test Safeplace IS NOT NULL' 
          END 
         FROM order_transaction AS ot 
         WHERE customer.custid = ot.custid 
          AND ot.trans_orderid = 5678 
        ) 
WHERE customer.custid = 1234 
     AND EXISTS (
        SELECT * 
        FROM order_transaction AS ot 
        WHERE customer.custid = ot.custid 
          AND ot.trans_orderid = 5678 
       ); 

Mentre la sintassi è ripetitivo, un buon ottimizzatore dovrebbe essere in grado di riconoscere la ripetizione e ottimizzare di conseguenza. Indipendentemente dal fatto che la versione attuale del tuo prodotto SQL svolga effettivamente un buon lavoro di ottimizzazione di questo nella pratica, è ovviamente un'altra questione. Ma considera questo: se il tuo prodotto SQL di scelta supporta la sintassi Standard ma in realtà non lo ottimizza correttamente, il "supporto" vale qualcosa?

Se stai cercando di utilizzare standard SQL (come in effetti dovrebbe IMO :) e vogliono una sintassi più "compatto", allora dare un'occhiata a MERGE o MERGE (SQL) esempio potrebbe essere più simile a questa:

MERGE INTO customer 
    USING (
      SELECT ot.custid, ot.forenames, 
       CASE 
        WHEN ot.safeplace IS NULL 
         THEN 'test SAFEPLACE IS NULL' 
        ELSE 'test Safeplace IS NOT NULL' 
        END 
      FROM order_transaction AS ot 
      WHERE ot.trans_orderid = 5678 
     ) AS source (custid, forenames, safeplace_narrative) 
    ON customer.custid = source.custid 
     AND customer.custid = 1234 
WHEN MATCHED THEN 
    UPDATE 
     SET forenames = source.forenames, 
      surname = source.safeplace_narrative, 
      middlename = source.safeplace_narrative; 
+0

@Richard aka cyberkiwi: risposta aggiornata per aggiungere un esempio MERGE per mostrare che è più compatto pur rimanendo standard SQL. – onedaywhen