Frage

Ich habe eine Tabelle mit einer Varchar-Spalte, und ich möchte Werte finden, die eine bestimmte Anzahl entsprechen. So kann sagen, dass Spalte enthält die folgenden Einträge (außer mit Millionen von Zeilen im wirklichen Leben):

123456789012
2345678
3456
23 45
713?2
00123456789012

Also ich entscheide ich möchte, dass alle Zeilen, die eine Aussage numerisch 123456789012 schreiben sind, dass in etwa so aussieht:

SELECT * FROM MyTable WHERE CAST(MyColumn as bigint) = 123456789012

Es sollte die erste und letzte Zeile zurückgeben, sondern die gesamte Abfrage sprengt, weil es nicht umwandeln kann das „23 45“ und „713? 2“ bis Bigint.

Gibt es einen anderen Weg, um die Konvertierung zu tun, die NULL für Werte zurück, die nicht konvertieren kann?

War es hilfreich?

Lösung

SQL Server garantiert NICHT Booleschen Operator Kurzschluss finden Sie unter Auf SQL Server booleschen Operator Kurzschluss . Also alles Lösung ISNUMERIC(...) AND CAST(...) mit grundlegenden Mängeln behaftet sind (sie können arbeiten, aber hey kann beliebig später scheitern auf dem erzeugten Plan dependiong). Eine bessere Lösung ist mit CASE, wie Thomas schlägt vor: CASE ISNUMERIC(...) WHEN 1 THEN CAST(...) ELSE NULL END. Aber, wie gbn wies darauf hin, ist ISNUMERIC notorisch heikel bei der Identifizierung, was numerisch "bedeutet und viele Fälle, in denen man erwarten würde, es 0 zurück kehrt 1. So im Fall der LIKE Mischen:

CASE WHEN MyRow NOT LIKE '%[^0-9]%' THEN CAST(MyRow as bigint) ELSE NULL END

Aber das eigentliche Problem ist, dass, wenn Sie Millionen von Zeilen und Sie haben sie wie folgt suchen, werden Sie immer End-to-End-Scan am Ende, da der Ausdruck nicht SARG-fähig ist (egal, wie wir umschreiben es). Das eigentliche Problem hier ist, Daten Reinheit und soll auf der entsprechenden Ebene angegangen werden, wobei die Daten gefüllt wird. Eine andere Sache zu prüfen ist, wenn möglich, eine beharrte berechnete Spalte mit diesem Ausdruck zu erstellen und einen gefilterten Index auf sie, die eliminiert NULL (dh. Nicht-numerisch) erstellen. Das würde die Dinge ein wenig beschleunigen.

Andere Tipps

Wenn Sie SQL Server 2012 verwenden, können Sie die 2 neuen Methoden verwenden:

Beide Methoden sind gleichwertig. Sie geben einen Wert zurück Guss in den angegebenen Datentyp, wenn die Umwandlung erfolgreich ist; andernfalls wird NULL zurückgegeben. Der einzige Unterschied besteht darin, dass CONVERT SQL Server spezifisch ist, CAST ist ANSI. mit CAST wird Ihr Code mehr tragbar (wenn auch nicht sicher, ob alle anderen Datenbankanbieter implementiert TRY_CAST)

machen

ISNUMERIC akzeptieren leere Zeichenkette und Werte wie 1,23 oder 5E-04 so unzuverlässig sein könnte.

Und Sie wissen nicht, was die Dinge, um in ausgewertet werden, so könnte es immer noch nicht (SQL ist deklarative, nicht prozedural so die WHERE-Klausel wird wahrscheinlich nicht links nach rechts ausgewertet werden)

So:

  • Sie Wert zu übernehmen, die aus nur der Zeichen 0-9
  • Sie müssen die „Nummer“ Filter materialisieren, so dass es vor CAST angewendet wird

So etwas wie:

SELECT 
*
FROM
   (
   SELECT TOP 2000000000 *
   FROM MyTable
   WHERE MyColumn NOT LIKE '%[^0-9]%'  --double negative rejects anything except 0-9
   ORDER BY MyColumn 
   ) foo
WHERE 
    CAST(MyColumn as bigint) = 123456789012 --applied after number check

Edit:. Kurzes Beispiel, das nicht

CREATE TABLE #foo (bigintstring varchar(100))
INSERT #foo (bigintstring )VALUES ('1.23')
INSERT #foo (bigintstring )VALUES ('1 23')
INSERT #foo (bigintstring )VALUES ('123')

SELECT * FROM #foo
WHERE
   ISNUMERIC(bigintstring) = 1 
   AND 
   CAST(bigintstring AS bigint) = 123
SELECT * 
    FROM MyTable 
    WHERE ISNUMERIC(MyRow) = 1
        AND CAST(MyRow as float) = 123456789012

Die ISNUMERIC () Funktion sollten Sie geben, was Sie brauchen.

SELECT * FROM MyTable
WHERE ISNUMERIC(MyRow) = 1
AND CAST(MyRow as bigint) = 123456789012

Und eine Case-Anweisung hinzufügen, wie Thomas vorgeschlagen:

SELECT * FROM MyTable
WHERE CASE(ISNUMERIC(MyRow)
        WHEN 1 THEN CAST(MyRow as bigint)
        ELSE NULL
      END = 123456789012

http://msdn.microsoft.com/en-us/library/ ms186272.aspx

SELECT *
FROM MyTable
WHERE (ISNUMERIC(MyColumn) = 1) AND (CAST(MyColumn as bigint) = 123456789012)

Zusätzlich können Sie eine CASE-Anweisung verwenden, um NULL-Werte zu erhalten.

SELECT 
    CASE
        WHEN (ISNUMERIC(MyColumn) = 1) THEN CAST(MyColumn as bigint)
        ELSE NULL
    END AS 'MyColumnAsBigInt'
FROM tableName

Wenn Sie eine zusätzliche Filterung erforderlich, für Numerik, die nicht gültig sind Bigint gegossen werden, können Sie die statt ISNUMERIC folgenden verwenden:

PATINDEX ( '% [^ 0-9]%', MyColumn)) = 0

Wenn Sie anstelle von ganzen Zahlen Dezimalzahlen müssen, um gegossene schwebt statt und ändern Sie die Regex ‚% [^ 0-9.]%‘

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