web-dev-qa-db-ger.com

Zeilen suchen, die keine numerischen Daten in Oracle enthalten

Ich versuche, problematische Datensätze in einer sehr großen Oracle-Tabelle zu finden. Die Spalte sollte alle numerischen Daten enthalten, obwohl es sich um eine varchar2-Spalte handelt. Ich muss die Datensätze finden, die keine numerischen Daten enthalten (Die Funktion to_number (col_name) gibt einen Fehler aus, wenn ich versuche, sie in dieser Spalte aufzurufen).

15
Ben

Ich dachte, Sie könnten eine regexp_like-Bedingung verwenden und den regulären Ausdruck verwenden, um nicht-numerische Werte zu finden. Ich hoffe das hilft vielleicht ?!

SELECT * FROM table_with_column_to_search WHERE REGEXP_LIKE(varchar_col_with_non_numerics, '[^0-9]+');
18
SGB

Um einen Indikator zu erhalten:

DECODE( TRANSLATE(your_number,' 0123456789',' ')

z.B.

SQL> select DECODE( TRANSLATE('12345zzz_not_numberee',' 0123456789',' '), NULL, 'number','contains char')
 2 from dual
 3 /

"contains char"

und

SQL> select DECODE( TRANSLATE('12345',' 0123456789',' '), NULL, 'number','contains char')
 2 from dual
 3 /

"number"

und

SQL> select DECODE( TRANSLATE('123405',' 0123456789',' '), NULL, 'number','contains char')
 2 from dual
 3 /

"number"

Oracle 11g verfügt über reguläre Ausdrücke, sodass Sie diese verwenden können, um die tatsächliche Anzahl zu erhalten :

SQL> SELECT colA
  2  FROM t1
  3  WHERE REGEXP_LIKE(colA, '[[:digit:]]');

COL1
----------
47845
48543
12
...

Wenn es einen nicht-numerischen Wert wie '23g' gibt, wird er einfach ignoriert.

11
Michael Durrant

Im Gegensatz zur Antwort von SGB ziehe ich es vor, den regulären Ausdruck meiner Daten zu definieren und zu verneinen. Dies erlaubt mir, Werte wie $ DDD, DDD, DDD.DD .__ zu definieren. Im einfachen Szenario des OPs würde es so aussehen

SELECT * 
FROM table_with_column_to_search 
WHERE NOT REGEXP_LIKE(varchar_col_with_non_numerics, '^[0-9]+$');

was alle nicht positiven Ganzzahlen findet. Wenn Sie auch negative Ganzzahlen akzeptieren, ist dies eine einfache Änderung. Fügen Sie einfach ein optionales Minus hinzu.

SELECT * 
FROM table_with_column_to_search 
WHERE NOT REGEXP_LIKE(varchar_col_with_non_numerics, '^-?[0-9]+$');

floating-Punkte akzeptieren ...

SELECT * 
FROM table_with_column_to_search 
WHERE NOT REGEXP_LIKE(varchar_col_with_non_numerics, '^-?[0-9]+(\.[0-9]+)?$');

Dasselbe gilt für jedes Format. Grundsätzlich verfügen Sie im Allgemeinen bereits über die Formate zur Überprüfung der Eingabedaten. Wenn Sie also nach Daten suchen möchten, die diesem Format nicht entsprechen, ist es einfacher, dieses Format zu negieren, als mit einem anderen. was im Fall von SGBs Ansatz etwas schwierig sein könnte, wenn Sie mehr als nur positive ganze Zahlen wollen.

5
ciuly

Benutze das

SELECT * 
FROM TableToSearch 
WHERE NOT REGEXP_LIKE(ColumnToSearch, '^-?[0-9]+(\.[0-9]+)?$');
4
Anil

Von http://www.dba-Oracle.com/t_isnumeric.htm

LENGTH(TRIM(TRANSLATE(, ' +-.0123456789', ' '))) is null

Wenn nach dem TRIM noch etwas in der Zeichenfolge enthalten ist, müssen es nicht numerische Zeichen sein.

1
capitano666

Nach einigen Tests, die auf den in den vorangegangenen Antworten enthaltenen Vorschlägen aufbauen, scheinen zwei brauchbare Lösungen zu bestehen.

Methode 1 ist am schnellsten, jedoch weniger leistungsfähig, wenn es um komplexere Muster geht.
Methode 2 ist flexibler, aber langsamer.

Methode 1 - am schnellsten
Ich habe diese Methode an einer Tabelle mit 1 Million Zeilen getestet.
Es scheint 3,8-mal schneller als die Regex-Lösungen zu sein.
Die 0-Ersetzung löst das Problem, dass 0 einem Leerzeichen zugeordnet ist und die Abfrage nicht zu verlangsamen scheint.

SELECT *
FROM <table>
WHERE TRANSLATE(replace(<char_column>,'0',''),'0123456789',' ') IS NOT NULL;

Methode 2 - langsamer, aber flexibler
Ich habe die Geschwindigkeit verglichen, mit der die Negation innerhalb oder außerhalb der Regex-Anweisung platziert wurde. Beide sind gleich langsamer als die Übersetzungslösung. Daher erscheint der Ansatz von @ ciuly bei Verwendung von Regex am sinnvollsten.

SELECT *
FROM <table>
WHERE NOT REGEXP_LIKE(<char_column>, '^[0-9]+$');
0
Wouter

Sie können diesen einen Check verwenden:

create or replace function to_n(c varchar2) return number is
begin return to_number(c);
exception when others then return -123456;
end;

select id, n from t where to_n(n) = -123456;
0
egor7

Ich habe das nützlich gefunden:

 select translate('your string','_0123456789','_') from dual

Ist das Ergebnis NULL, ist es numerisch (Fließkommazahlen werden ignoriert.)

Ich bin jedoch etwas verblüfft, warum der Unterstrich benötigt wird. Ohne sie gibt das Folgende auch null zurück:

 select translate('s123','0123456789', '') from dual

Es gibt auch einen meiner Lieblingstricks - nicht perfekt, wenn die Zeichenfolge "*" oder "#" enthält:

 SELECT 'is a number' FROM dual WHERE UPPER('123') = LOWER('123')
0
aiGuru

Nach einigen Tests habe ich mir diese Lösung ausgedacht. Lass es mich wissen, falls es hilft.

Fügen Sie diese unter 2 Bedingungen in Ihre Abfrage ein und es werden die Datensätze gefunden, die keine numerischen Daten enthalten

 and REGEXP_LIKE(<column_name>, '\D') -- this selects non numeric data
 and not REGEXP_LIKE(column_name,'^[-]{1}\d{1}') -- this filters out negative(-) values
0
JAY SOPARIYA