Domanda

Non faccio un sacco di SQL, e la maggior parte del tempo, sto facendo operazioni CRUD. Di tanto in tanto vado a prendere qualcosa di un po 'più complicato. Quindi, questa domanda può essere una domanda newbie, ma io sono pronto. Ho appena cercato di capire questo fuori per ore, ed è stato inutile.

Quindi, Immaginate la seguente struttura della tabella:

> | ID | Col1 | Col2 | Col3 | .. | Col8 |

voglio selezionare ID e una colonna calcolata. La colonna calcolata ha una gamma di 0-8 e contiene il numero di partite alla query. Voglio anche per limitare il set di risultati per includere solo le righe che hanno un certo numero di partite.

Quindi, da questi dati di esempio:

> | 1 | 'a' | 'b' | 1 | 2 |  
> | 2 | 'b' | 'c' | 1 | 2 |  
> | 3 | 'b' | 'c' | 4 | 5 |  
> | 4 | 'x' | 'x' | 9 | 9 |  

Voglio interrogare sulla Col1 = 'A' o Col2 = 'C' o Col3 = 1 o Col4 = 5 dove il risultato calcolato> 1 e avere il set aspetto risultato come:

> | ID | Cal |
> | 1  |  2  |
> | 2  |  2  |
> | 3  |  2  |

Sto utilizzando T-SQL e SQL Server 2005, se è importante, e non posso cambiare il DB Schema.

Mi piacerebbe anche preferisco tenerlo come una query autonomo e non c'è bisogno di creare una stored procedure o una tabella temporanea.

È stato utile?

Soluzione

Questa risposta funzionerà con SQL 2005, utilizzando un CTE per ripulire la tabella derivata un po '.

WITH Matches AS
(
    SELECT ID, CASE WHEN Col1 = 'a' THEN 1 ELSE 0 END + 
                CASE WHEN Col2 = 'c' THEN 1 ELSE 0 END +
                CASE WHEN Col3 = 1  THEN 1 ELSE 0 END +
                CASE WHEN Col4 = 5  THEN 1 ELSE 0 END AS Result
    FROM Table1
    WHERE Col1 = 'a' OR Col2 = 'c' OR Col3 = 1 OR Col4 = 5 
)
SELECT ID, Result
FROM Matches
WHERE Result > 1 

Altri suggerimenti

Ecco una soluzione che sfrutta il fatto che un confronto booleana restituisce i numeri interi 1 o 0:

SELECT * FROM (
  SELECT ID, (Col1='a') + (Col2='c') + (Col3=1) + (Col4=5) AS calculated
  FROM MyTable
) q
WHERE calculated > 1; 

Si noti che si deve mettere tra parentesi i confronti booleane perché + ha precedenza maggiore rispetto =. Inoltre, bisogna mettere tutto in una sottoquery, perché normalmente non è possibile utilizzare un alias di colonna in una clausola WHERE della stessa query.

Potrebbe sembrare si dovrebbe anche usare una clausola WHERE nella subquery per limitare le sue file, ma con ogni probabilità si sta andando a finire con un tavolo pieno scansione comunque, quindi probabilmente non è una grande vittoria. D'altra parte, se si prevede che tale restrizione sarebbe molto di ridurre il numero di righe nel risultato subquery, quindi sarebbe utile.


Il commento di Re Quassnoi, se non è possibile trattare le espressioni booleane come valori interi, ci dovrebbe essere un modo per mappare le condizioni booleane a numeri interi, anche se è un po 'prolisso. Ad esempio:

SELECT * FROM (
  SELECT ID, 
      CASE WHEN Col1='a' THEN 1 ELSE 0 END
    + CASE WHEN Col2='c' THEN 1 ELSE 0 END 
    + CASE WHEN Col3=1   THEN 1 ELSE 0 END
    + CASE WHEN Col4=5   THEN 1 ELSE 0 END AS calculated
  FROM MyTable
) q
WHERE calculated > 1;

Questa query è più indice di amichevole:

SELECT  id, SUM(match)
FROM    (
        SELECT  id, 1 AS match
        FROM    mytable
        WHERE   col1 = 'a'
        UNION ALL
        SELECT  id, 1 AS match
        FROM    mytable
        WHERE   col2 = 'c'
        UNION ALL
        SELECT  id, 1 AS match
        FROM    mytable
        WHERE   col3 = 1
        UNION ALL
        SELECT  id, 1 AS match
        FROM    mytable
        WHERE   col4 = 5
        ) q
GROUP BY
        id
HAVING  SUM(match) > 1

Questo sarà solo efficace se tutti le colonne che si sta cercando per sono, in primo luogo, indicizzato e, dall'altro, hanno un alto cardinalità (molti valori distinti).

Si veda questo articolo nel mio blog per i dettagli delle prestazioni:

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top