Frage

Ich mache nicht viel SQL und mache die meiste Zeit CRUD-Operationen.Gelegentlich erhalte ich etwas Komplizierteres.Diese Frage ist vielleicht eine Neulingsfrage, aber ich bin bereit.Ich habe stundenlang versucht, das herauszufinden, aber es hat keinen Zweck gehabt.

Stellen Sie sich also die folgende Tabellenstruktur vor:

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

Ich möchte eine ID und eine berechnete Spalte auswählen.Die berechnete Spalte hat einen Bereich von 0 bis 8 und enthält die Anzahl der Übereinstimmungen mit der Abfrage.Außerdem möchte ich die Ergebnismenge darauf beschränken, nur Zeilen einzuschließen, die eine bestimmte Anzahl von Übereinstimmungen aufweisen.

Also, aus diesen Beispieldaten:

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

Ich möchte Col1 = 'a' OR Col2 = 'c' OR Col3 = 1 OR Col4 = 5 abfragen, wobei das berechnete Ergebnis > 1 ist und die Ergebnismenge so aussehen soll:

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

Ich verwende T-SQL und SQL Server 2005, falls es darauf ankommt, und ich kann das DB-Schema nicht ändern.

Ich würde es auch lieber als eine eigenständige Abfrage behalten und keine gespeicherte Prozedur oder temporäre Tabelle erstellen müssen.

War es hilfreich?

Lösung

Diese Antwort wird mit SQL 2005 arbeiten, einen CTE mit der abgeleiteten Tabelle zu bereinigen, ein wenig.

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 

Andere Tipps

Hier ist eine Lösung, die die Tatsache nutzt, dass ein boolescher Vergleich die Ganzzahlen 1 oder 0 zurückgibt:

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

Beachten Sie, dass Sie die booleschen Vergleiche in Klammern setzen müssen, weil + hat höhere Priorität als =.Außerdem müssen Sie alles in eine Unterabfrage einfügen, da Sie normalerweise keinen Spaltenalias in einer verwenden können WHERE Klausel derselben Abfrage.

Es scheint, als ob Sie auch a verwenden sollten WHERE -Klausel in der Unterabfrage, um ihre Zeilen einzuschränken, aber aller Wahrscheinlichkeit nach werden Sie sowieso mit einem vollständigen Tabellenscan enden, also ist das wahrscheinlich kein großer Gewinn.Andererseits, wenn man davon ausgeht, dass eine solche Einschränkung erfolgen würde sehr Reduzieren Sie die Anzahl der Zeilen im Ergebnis der Unterabfrage, dann würde es sich lohnen.


Zu Quassnois Kommentar: Wenn Sie boolesche Ausdrücke nicht als ganzzahlige Werte behandeln können, sollte es eine Möglichkeit geben, boolesche Bedingungen ganzen Zahlen zuzuordnen, auch wenn dies etwas ausführlich ist.Zum Beispiel:

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;

Diese Abfrage ist mehr Index freundlich:

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

Dies wird nur dann effizient sein, wenn alle die Spalten Sie suchen, sind erstens, indiziert und zweitens haben hohe Mächtigkeit (viele unterschiedliche Werte).

Lesen Sie diesen Artikel in meinem Blog für Leistungsdetails:

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top