Riceviamo un elenco di ordini e convalidiamo che inizi con determinati prefissi, ad esempio se OrderNumber non inizia con ABC, quindi viene visualizzato elenco dellordine allutente come errore. Usiamo exist, per cercare la prima esistenza, non vogliamo consumare molto tempo per le prestazioni. Se non esiste, possiamo iniziare a condurre altre attività nel codice.
Cè comunque in sql di cui sbarazzarsi il codice ripetitivo? Abbiamo molti controlli come questo su più tabelle, cercando di rendere il codice più efficiente.
if exists ( select * from dbo.OrdersImport where left(OrderNumber,3) <> "ABC" ) begin select OrderNumber as OrderErrorList from dbo.OrdersImport where left(OrderNumber,3) <> "ABC" end else
Risposta
Sfortunatamente temo che, tentando di impedire la ripetizione del codice, potresti finire per scrivere più codice e rendere la query meno leggibile. Ma credo che questo possa essere vantaggioso per te: tieni conto delle situazioni in cui nel test dovresti cercare solo in una o due tabelle, dove per recuperare tutti i dettagli dovrai unirti a molte altre. In queste situazioni puoi semplificare la query di prova rendendola così anche più veloce da eseguire.
E già che ci siamo, potresti anche considerare di cambiare la tua istruzione WHERE. Lutilizzo di funzioni nel predicato le rende non SARGable e impedisce lutilizzo di indici in questi casi. Un approccio migliore in questo esempio sarebbe controllare
WHERE OrderNumber LIKE "ABC%"
poiché lottimizzatore eseguirà la conversione in qualcosa sulla falsariga di
OrderNumber >= "ABC" AND OrderNumber < "ABD"
che supporta luso degli indici. Quindi questo sarebbe Index Scan (utilizzando left ()) e Index Seek (utilizzando LIKE).
Answer
Sfortunatamente, per una serie di motivi (non solo legacy) SQL non ha quasi tutte le opzioni e le funzionalità di riutilizzo del codice che hanno la maggior parte dei linguaggi client e alcuni di essi (come le UDF scalari) hanno problemi significativi. Quindi, in larga misura, se vuoi essere un programmatore SQL efficace, devi rassegnarti a fare molto più riutilizzo del codice taglia e incolla di quanto potresti mai considerare in un linguaggio client come C #, VB. Net o Java.
Detto questo, puoi eliminare la ridondanza nel tuo esempio, tuttavia, che sia effettivamente migliore o meno, dovrai decidere.
Declare @OrderErrorList Table(OrderNumber varchar(32)); Insert into @OrderErrorList select OrderNumber as OrderErrorList from dbo.OrdersImport where left(OrderNumber,3) <> "ABC"; if exists ( select * from @OrderErrorList ) begin select * from @OrderErrorList end else
Commenti
- Potresti semplificarlo ulteriormente selezionando @@ ROWCOUNT invece che esistente?
- @mathewb Sì, ma deve essere fatto immediatamente dopo INSERT..SELECT. Se aggiungi unaltra affermazione, improvvisamente smette di funzionare correttamente e cerco di evitare mine terrestri come quella nelle mie risposte. La soluzione alternativa sarebbe salvare @@ ROWCOUNT in una variabile, ma in tal caso non sarebbe significativamente migliore di quello che ho sopra.
Risposta
Esiste comunque sql per sbarazzarsi del codice ripetitivo?
Non proprio, no. Puoi riformulare la query in questo modo, senza listruzione IF, ma non è molto diversa da quella che hai:
SELECT * FROM dbo.OrdersImport o WHERE LEFT(OrderNumber, 3) <> "ABC" AND EXISTS ( SELECT * FROM dbo.OrdersImport WHERE LEFT(OrderNumber,3) <> "ABC" AND ID = o.ID )