PDA

View Full Version : [SQL] Chiedo aiuto per una query su SQL Server 2008


VegetaSSJ5
09-09-2009, 11:00
Salve a tutti.
Devo implementare una query di ricerca in un'applicazione web i cui dati si trovano su un db SQL Server 2008.

La query in realtà già esiste e funziona bene, però deve essere modificata.
Partiamo da un esempio dal basso. La query è del tipo:
SELECT col1, col2, col3
FROM tab1 (join.....)
WHERE condizione
AND (col1 LIKE '%valore%' OR col2 LIKE '%valore%' OR col3 LIKE '%valore%')
Poichè bisogna gestire la paginazione la query diventa:
SELECT * FROM (

SELECT col1, col2, col3, ROWNUM() OVER (ORDER BY col1 ASC) AS ROWNUM
FROM tab1 (join...)
WHERE condizione
AND (col1 LIKE '%valore%' OR col2 LIKE '%valore%' OR col3 LIKE '%valore%')

) AS result WHERE result.ROWNUM BETWEEN 1 AND 15
In questo modo vengono restituiti solo i valori dalla posizione 1 alla 15.

Fin qui tutto bene, la query funziona perfettamente.

Ora però andrebbe modificata in questo modo: nel risultato devono comparire prima i record dove il LIKE è stato trovato nel campo col2, poi i record dove il LIKE è stato trovato negli altri campi. Mi è venuto in mente di fare una union in questo modo:
SELECT * FROM (

SELECT col1, col2, col3, ROWNUM() OVER (ORDER BY col1 ASC) AS ROWNUM
FROM tab1 (join...)
WHERE condizione
AND (col2 LIKE '%valore%')

UNION

SELECT col1, col2, col3, ROWNUM() OVER (ORDER BY col1 ASC) AS ROWNUM
FROM tab1 (join...)
WHERE condizione
AND (col1 LIKE '%valore%' OR col3 LIKE '%valore%')

) AS result WHERE result.ROWNUM BETWEEN 1 AND 15
Sarebbe una buona soluzione in quanto effettivamente vengono restituiti prima tutti i record in cui il like è stato trovato nel campo col2 e poi gli altri, però in questo modo i campi ROWNUM delle 2 query si duplicano creando problemi quindi con la paginazione.

Sapete suggerirmi qualcosa per risolvere il problema?
Grazie! :)

john_revelator
09-09-2009, 20:15
Non ho sql server a portata di mano e lo conosco poco. In mysql farei così, ma suppongo sia la stessa cosa anche col tuo rdbms.


select *,if(col2 like "%pippo%",1,0) as ordine
from tabella
where col1 like "%pippo%" or col2 like "%pippo%" or col3 like "%pippo%"
order by ordine desc

VegetaSSJ5
09-09-2009, 20:59
Non ho sql server a portata di mano e lo conosco poco. In mysql farei così, ma suppongo sia la stessa cosa anche col tuo rdbms.


select *,if(col2 like "%pippo%",1,0) as ordine
from tabella
where col1 like "%pippo%" or col2 like "%pippo%" or col3 like "%pippo%"
order by ordine desc

grazie! :)
ho capito l'idea ma non saprei come riprodurre in sql server questo: if(col2 like "%pippo%",1,0)

john_revelator
09-09-2009, 23:07
Adesso mi è stato possibile testare la cosa.


select *,
case
when col2 like '%pippo%' then 1 else 0 end
as ordine
from tabella
where col1 like '%pippo%' or col2 like '%pippo%' or col3 like '%pippo%'
order by ordine desc


In effetti usando l'if non funzionava. So che in questo forum gli esperti di sql server non mancano. Sicuramente qualcuno ci dirà se è possibile risolvere anche con l'if. ;)

edit. Ho fatto una rapida gugolata e mi pare di capire che non esista proprio il costrutto if ma che sia sempre necessario ricorrere al case.

EnricoHU
10-09-2009, 08:54
in teoria, potresti usare un'istruzione del genere:

SELECT * FROM (

SELECT col1, col2, col3, ROWNUM() OVER (ORDER BY col1 ASC) AS ROWNUM
FROM tab1 (join...)
WHERE condizione
AND (col2 LIKE '%valore%')

UNION

SELECT col1, col2, col3, 10000 + ROWNUM() OVER (ORDER BY col1 ASC) AS ROWNUM
FROM tab1 (join...)
WHERE condizione
AND (col1 LIKE '%valore%' OR col3 LIKE '%valore%')

) AS result WHERE result.ROWNUM BETWEEN 1 AND 15 or result.ROWNUM BETWEEN 10001 AND 10015

in questo modo dovresti ottenere le prime 15 righe della prima e le prime 15 della seconda

VegetaSSJ5
10-09-2009, 10:26
in teoria, potresti usare un'istruzione del genere:

SELECT * FROM (

SELECT col1, col2, col3, ROWNUM() OVER (ORDER BY col1 ASC) AS ROWNUM
FROM tab1 (join...)
WHERE condizione
AND (col2 LIKE '%valore%')

UNION

SELECT col1, col2, col3, 10000 + ROWNUM() OVER (ORDER BY col1 ASC) AS ROWNUM
FROM tab1 (join...)
WHERE condizione
AND (col1 LIKE '%valore%' OR col3 LIKE '%valore%')

) AS result WHERE result.ROWNUM BETWEEN 1 AND 15 or result.ROWNUM BETWEEN 10001 AND 10015

in questo modo dovresti ottenere le prime 15 righe della prima e le prime 15 della seconda
ci ho provato ma mettendo il 10000 dopo, cioè ... ROWNUM() OVER (...) + 10000 AS ROWNUM...

ma non funziona, cioè la query viene eseguita correttamente ma non viene aggiunto il valore 10000...

EnricoHU
10-09-2009, 14:06
strano

purtoppo non ho modo di testare, però ho trovato quest'altro comando che potrebbe fare al caso tuo

SELECT TOP 15 ROW_NUMBER() OVER (ORDER BY Date DESC) AS Row

VegetaSSJ5
10-09-2009, 16:04
strano

purtoppo non ho modo di testare, però ho trovato quest'altro comando che potrebbe fare al caso tuo

SELECT TOP 15 ROW_NUMBER() OVER (ORDER BY Date DESC) AS Row
il fatto è che quel rownumber mi serve per gestire la paginazione, ed è quindi dinamico... quindi in questo esempio prende i valori tra 1 e 15, ma in una ipotetica pagina 5 prende i valori tra 76 e 90.