Principale utente con più risposte
Split e ciclo in una sp

Domanda
-
Salve a tutti,
sulla tabella "Clienti" ho un campo che si chiama codice che contiene dei codici separati da SPAZIO.
Leggo i dati di questa tabella con una sp a cui tra le altre cose passo il parametro CodiceDaCercare che può contenere uno o più codici separati da SPAZIO.
Quello che dovrei ottenere è spacchettare i singoli codici contenuti nel parametro e metterli nella clausola Where della query con tutti i valori passati in OR.
Quindi diciamo per esempio che nel parametro passo una cosa del tipo "AAA BBB CCC", la query SELECT che la SP deve creare sarà del tipo:
SELECT * from Clienti where Codice like '%AAA%' or Codice like '%BBB%' or Codice like '%CCC%'
Qualcuno ha suggerimenti? Penso mi serverebbe qualcosa tipo la funzione SPLIT e un ciclo
Diego Riccardi
Risposte
-
Ciao Diego,
Credo che tu non possa che ricorrere all'SQL Dinamico, quindi andresti a generare la tua query SQL on-the-fly per poi mandarla in esecuzione con una EXEC ().
Potendo fare a meno del LIKE (che comunque ti porterebbe ad avere una query poco performante se la tabella da interrogare contiene molti record), questa è un'alternativa:
1. Usa una funzione che converte la tua stringa in input in una tabella (ad esempio: http://ole.michelsen.dk/blog/split-string-to-table-using-transact-sql/)
2. Modifica la tua query in questo modo:
SELECT * from Clienti c inner join dbo.Split(@Criteria, ' ') crit on c.Codice = crit.Data
Dove @Criteria è la tua stringa di input con i codici separati da spazi, e dbo.Split() è la funzione di cui sopra.
Con un indice sul campo "Codice" della tabella Clienti, la query dovrebbe essere abbastanza efficiente.
HTH,
Alberto Dallagiacoma
My Italian Blog: http://blogs.ugidotnet.org/alby
Twitter: http://twitter.com/albertodall
DotDotNet - User Group .NET Emilia Romagna: http://www.dotdotnet.org- Modificato Alberto Dallagiacoma lunedì 7 ottobre 2013 14:59
- Contrassegnato come risposta Diego Riccardi giovedì 10 ottobre 2013 09:12
-
Usando SQL dinamico, la SQL Injection è sempre in agguato. :) Avendo la libertà di specificare i parametri di filtro in input, bisogna sempre avere un occhio di riguardo. Consiglio questo sempre attuale articolo: http://www.sommarskog.se/dynamic_sql.html
Per quanto riguarda il tuo esempio, non capisco come mai ripeti l'"order by", la where condition e metti un "where 1 = 1".
HTH
Alberto Dallagiacoma
My Italian Blog: http://blogs.ugidotnet.org/alby
Twitter: http://twitter.com/albertodall
DotDotNet - User Group .NET Emilia Romagna: http://www.dotdotnet.org- Modificato Alberto Dallagiacoma mercoledì 9 ottobre 2013 15:02
- Contrassegnato come risposta Diego Riccardi giovedì 10 ottobre 2013 09:12
Tutte le risposte
-
Ciao Diego,
Credo che tu non possa che ricorrere all'SQL Dinamico, quindi andresti a generare la tua query SQL on-the-fly per poi mandarla in esecuzione con una EXEC ().
Potendo fare a meno del LIKE (che comunque ti porterebbe ad avere una query poco performante se la tabella da interrogare contiene molti record), questa è un'alternativa:
1. Usa una funzione che converte la tua stringa in input in una tabella (ad esempio: http://ole.michelsen.dk/blog/split-string-to-table-using-transact-sql/)
2. Modifica la tua query in questo modo:
SELECT * from Clienti c inner join dbo.Split(@Criteria, ' ') crit on c.Codice = crit.Data
Dove @Criteria è la tua stringa di input con i codici separati da spazi, e dbo.Split() è la funzione di cui sopra.
Con un indice sul campo "Codice" della tabella Clienti, la query dovrebbe essere abbastanza efficiente.
HTH,
Alberto Dallagiacoma
My Italian Blog: http://blogs.ugidotnet.org/alby
Twitter: http://twitter.com/albertodall
DotDotNet - User Group .NET Emilia Romagna: http://www.dotdotnet.org- Modificato Alberto Dallagiacoma lunedì 7 ottobre 2013 14:59
- Contrassegnato come risposta Diego Riccardi giovedì 10 ottobre 2013 09:12
-
Grazie per la risposta, ho provato e funziona!
Solo una cosa se un record della tabella Clienti contiene 2 o più dei criteri impostati, mi ritrovo il record duplicato o triplicato perchè logicamente la JOIN è soddisfatta per più valori e quindi i risultati vengono duplicati.
Quindi avevo pensato di agire direttamente nella mia sp, io imposto il filtro così:
IF @Codice <> '' Begin SELECT @filtro = @filtro + ' AND c.Codice LIKE ''%'' + @xCodice + ''%''' select @campi = @campi + ', c.Codice' End
che ho modificato in:
IF @Codice <> '' Begin SELECT @Codice = '''' + replace(@Codice,' ','%'' OR Codice Like ''%') + '''' SELECT @filtro = @filtro + ' AND (c.Codice LIKE ''%'' + @xCodice + ''%'')' select @campi = @campi + ', c.Codice' End
Ma la query non restituisce più nessun record.
Diego Riccardi
-
Dal codice che hai postato, non riesco a capire dove tu abbia la join...
Alberto Dallagiacoma
My Italian Blog: http://blogs.ugidotnet.org/alby
Twitter: http://twitter.com/albertodall
DotDotNet - User Group .NET Emilia Romagna: http://www.dotdotnet.org -
Intendevo dire che usando il sistema che mi consigliavi tu con la JOIN mi si duplicano (o triplicano etc...) i risultati quando più condizioni della JOIN sono soddisfatti sullo stesso record della tabella clienti.
Quindi avevo optato per modificare la mia SP che non utilizza JOIN, ma crea la clausola Where al momento, con il sistema che ho scritto sopra.
In entrambi i casi non riesco a ottenere il risultato che mi interessa, perchè se nel primo c'è una duplicazione dei risultati, nel secondo caso non mi ritorna nessun record.
Grazie ancora
Diego Riccardi
-
Ah, ok.
Infatti la strada della funzione Split() è valida se puoi fare a meno del "LIKE", quindi avere uno ed uno solo record della tabella Clienti per ogni criterio di ricerca passato in ingresso.
Per il secondo caso (nessun record ritornato), ti suggerisco di farti mandare in output il codice SQL generato (es.: PRINT @sqlStmt), e poi eseguire il comando generato in una finestra di query separata, così da poter vedere meglio cosa non quadra.
HTH,
Alberto Dallagiacoma
My Italian Blog: http://blogs.ugidotnet.org/alby
Twitter: http://twitter.com/albertodall
DotDotNet - User Group .NET Emilia Romagna: http://www.dotdotnet.org -
ci avevo già provato e a me non sembrano esserci errori.
Questo è l'output
'OG1%' OR Ult_cat_Class Like '%OG2%' OR Ult_cat_Class Like '%OG3' SELECT c.IdCliente, c.RagSoc, c.Citta, c.Codice FROM ( SELECT ROW_NUMBER() OVER(ORDER BY IdCliente) AS rowNumber, c.IdCliente, c.RagSoc, c.Citta, c.Codice FROM dbo.qry_SP_CercaClienti c where 1 = 1 AND (c.Codice LIKE '%' + @xCodice + '%') ) AS c WHERE (rowNumber >= 1 AND rowNumber < 101) AND (c.Codice LIKE '%' + @xCodice + '%') ORDER BY IdCliente
Dove il primo rigo è il contenuto della variabile @Codice (print @Codice) e dopo c'è la query completa che eseguo con:
SELECT @paramlist = '@xCodice nvarchar(100) = NULL' EXEC sp_executesql @sql, @paramlist, @Codice
Eseguendo la query mostrata in output in una nuova finestra e sostituendo a @xCodice il contenuto del primo rigo, la query viene eseguita correttamente restituendo i record esatti.
Grazie ancora per l'aiuto
Diego Riccardi
-
Dopo numerose prove forse ho trovato una soluzione anche se non so se convincente al 100%. Ho modificato così:
SELECT @Codice = replace(@Codice,' ','%'' OR Codice Like ''%') SELECT @filtro = @filtro + ' AND (c.Codice LIKE ''%' + @Codice + '%'')'
Quindi "sparo" direttamente la variabile @Codice nella where senza passare per la @xCodice che poi passo alla EXEC come mostrato sopra.
In questo modo funziona, ma non è che potrei avere problemi di SQL Injection?
Diego Riccardi
-
Usando SQL dinamico, la SQL Injection è sempre in agguato. :) Avendo la libertà di specificare i parametri di filtro in input, bisogna sempre avere un occhio di riguardo. Consiglio questo sempre attuale articolo: http://www.sommarskog.se/dynamic_sql.html
Per quanto riguarda il tuo esempio, non capisco come mai ripeti l'"order by", la where condition e metti un "where 1 = 1".
HTH
Alberto Dallagiacoma
My Italian Blog: http://blogs.ugidotnet.org/alby
Twitter: http://twitter.com/albertodall
DotDotNet - User Group .NET Emilia Romagna: http://www.dotdotnet.org- Modificato Alberto Dallagiacoma mercoledì 9 ottobre 2013 15:02
- Contrassegnato come risposta Diego Riccardi giovedì 10 ottobre 2013 09:12
-