Teilstring in Liste suchen ( ... in ...)

krameger

Benutzer
Beiträge
6
Hallo
Ich arbeite mit dem SQL Developer .

Zwei Tabellen -Bestellnummer -Mailversand.

select Bestellnummer from Bestellung
where Bestellnummer in (
select bestelltext from mailversand
);

Das Problem ist, dass in Mailversand die Bestellnummer Teil des Textes ist ZB bestelltext "Bestellung 1537 am 2.2. versendet"

Tabelle Bestellnummern
1536
1537
1538

Tabelle mailversand
"Bestellung 1537 am 1.2. versendet"
"Bestellung 1538 am 2.2. versendet"

Letztendlich benötige die Bestellnummern, die in Mailversand NICHT vorkommen.

****Diese Beispiel ist konstruiert und würde in der Praxis so nicht vorkommen, beschreibt aber mein Problem ganz gut.

Ich habe die Abfrage mit Vergleich mit Liste probiert, aber mit Wildcard % komme ich nicht weiter.

Vielen Dank für eure Hilfe.

Freundliche Grüße
Gerold
 
Werbung:
Die Bestellnummer ist in diesem Fall natürlich der Fremdschlüssel in der Tabelle mailversand der auf die Tabelle Bestellnummern verweist. Den in Text mit LIKE zu suchen ist natürlich Big Fail und schreit nach einem Fix durch die offensichtlich unfähige oder unmotivierte Programmierfirma, aber was solls...

Code:
SELECT * FROM Bestellnummern b LEFT JOIN mailversand m ON m.spalte LIKE '%' + b.spalte + '%'

Eine rein numerische Bestellnummer sollte idealerweise explizit in eine Zeichenkette konvertiert werden und eventuell muss auch die Text-Spalte konvertiert werden, je noch Größe. Schnell wird es nie sein aber es müsste so funtionieren, zumindest in MSSQL ist das lauffähig.
 
Code:
test=*# select * from bestellnummern ;
  n   
------
 1536
 1537
 1538
(3 rows)

test=*# select * from mailversand ;
  t   
-----------------------------------
 Bestellung 1537 am 1.2. versendet
 Bestellung 1538 am 2.2. versendet
(2 rows)

test=*# select * from bestellnummern where n not in (select regexp_replace(replace(t,'Bestellung ',''),' .*$','') from mailversand);
  n   
------
 1536
(1 row)

test=*#

(Gemacht mit PostgreSQL.)

Das ist dreckig, schmutzig & verwerflich. Sowas will man nicht in einer produktiven Umgebung.
 
Das Tabellendesign macht für uns eine Programmierfirma

Eine "Programmierfirma"? Was es nicht alles gibt :D

Wenn die Pfuscher das nicht anders hinbekommen, könnte man das Schlimmste ggf. mit einem funktionsbasierten Index verhindern:
Code:
create table t (col1 varchar2(100));
insert into t
select 'Bestellung '||level||' am 2.2. versendet' from dual connect by level <=5000;
create index t_ix on t( to_number(substr(col1,instr(col1,' ')+1,(instr(col1,' am')-instr(col1,' ')-1)) ));
select * from t where substr(col1,instr(col1,' ')+1,(instr(col1,' am')-instr(col1,' ')-1))=333;

Und der Plan dazu:

---------------------------------------------------------------------------------------------
| Id  | Operation                           | Name | E-Rows |E-Bytes| Cost (%CPU)| E-Time   |
---------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                    |      |      1 |    65 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID BATCHED| T    |      1 |    65 |     2   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN                  | T_IX |      1 |       |     1   (0)| 00:00:01 |
---------------------------------------------------------------------------------------------
Voraussetzung ist natürlich, dass der Text immer gleich aufgebaut ist. Sobald es hier unterschiedliche Versionen gibt, kann es zu Fehlern kommen.
Davon abgesehen hätte ich Angst davor, was sonst noch so von den selbsternannten Programmierern in eurer Anwendung verbrochen wurde.
 
Oder vielleicht kann man eine Spalte anhängen und mit einem Trigger die Bestellnummer extrahieren um sie schonmal für alles nutzbar zu machen.
 
Werbung:
Gute Idee, aber nicht als Trigger, sondern mittels einer virtuellen Spalte:
Code:
alter table t add bestellnummer GENERATED ALWAYS AS (to_number(substr(col1,instr(col1,' ')+1,(instr(col1,' am')-instr(col1,' ')-1)) )) VIRTUAL;
create index t_ix2 on t (bestellnummer);
select * from t where bestellnummer=456;

----------------------------------------------------------------------------------------------
| Id  | Operation                           | Name  | E-Rows |E-Bytes| Cost (%CPU)| E-Time   |
----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                    |       |      1 |    65 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID BATCHED| T     |      1 |    65 |     2   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN                  | T_IX2 |      1 |       |     1   (0)| 00:00:01 |
----------------------------------------------------------------------------------------------

Damit spart man sich den etwas unhandlichen Aufruf in der WHERE Bedingung.
 
Zurück
Oben