Mysql: geht sowas ?

Hallo !

Ich habe 2 Tabellen:
Tabelle 1: id (weitere Spalten) (p-key: id)
Tabelle 2: id, attid, attval (p-key: id,attid)

Jetzt suche ich eine Abfrage, die mir alle Datensätze von Tabelle 1 liefert, und, falls in Tabelle 2 attid zu dieser id existiert und einen betimmten Wert hat, attval, sonst null.
Subselects gehen leider nicht in mysql,
select a.id, b.attval from t1 a left outer join t2 b on a.id=b.id where b.attid=wert
liefert leider nur die Zeilen, wo attid auch den Wert hat, die, wo das Attribut nicht vorhanden ist, fallen weg.
Geht das nur mit Hilfe einer temp. Tabelle und einem left outer koin ohne Bedingung, oder gibt es da eine bessere Lösung ?

Hi,

Jetzt suche ich eine Abfrage, die mir alle Datensätze von
Tabelle 1 liefert, und, falls in Tabelle 2 attid zu dieser id
existiert und einen betimmten Wert hat, attval, sonst null.

Was Du nehmen kannst ist die IF-Funktion:

select a.id, if(strcmp(b.attval, 'Wert'), 'Wert', null) attvalneu
 from t1 a left outer join t2 b 
 on a.id = b.id;

Mußt Du aber ausprobieren, da ich momentan kein MySQL hab.

Gruß

J.

Hallo !

Ich habe 2 Tabellen:
Tabelle 1: id (weitere Spalten) (p-key: id)
Tabelle 2: id, attid, attval (p-key: id,attid)

Jetzt suche ich eine Abfrage, die mir alle Datensätze von
Tabelle 1 liefert, und, falls in Tabelle 2 attid zu dieser id
existiert und einen betimmten Wert hat, attval, sonst null.
Subselects gehen leider nicht in mysql,
select a.id, b.attval from t1 a left outer join t2 b on
a.id=b.id where b.attid=wert

Versuch mal sowas in der Richtung:
select a.id, b.attval from t1 a left inner join t2 b on a.id = b.id where b.attid = wert

Kenne mich mit MySQL leider nicht so aus, kann sein, daß Du mal experimentieren musst mit „left inner“ und „right outer“ sowie „right inner“-Joins…

liefert leider nur die Zeilen, wo attid auch den Wert hat,
die, wo das Attribut nicht vorhanden ist, fallen weg.
Geht das nur mit Hilfe einer temp. Tabelle und einem left
outer koin ohne Bedingung, oder gibt es da eine bessere Lösung
?

Hi,

Jetzt suche ich eine Abfrage, die mir alle Datensätze von
Tabelle 1 liefert, und, falls in Tabelle 2 attid zu dieser id
existiert und einen betimmten Wert hat, attval, sonst null.

Was Du nehmen kannst ist die IF-Funktion:

select a.id, if(strcmp(b.attval, ‚Wert‘), ‚Wert‘, null)
attvalneu
from t1 a left outer join t2 b
on a.id = b.id;

Mußt Du aber ausprobieren, da ich momentan kein MySQL hab.

das liefert leider „zuviel“, da ich vorher auf die addid filtern muss. Nur wirft mir gerade diese where Bedingung die Datensätze, zu denen es keine attid gibt, weg.

Was ich suche, ist so etwas:

select a.id, b.attval from t1 a, t2 b
where a.id=b.id and b.attid=wert
union
select a.id,NULL from t1 a
where a.id not in (select c.id from t2 c where c.id=a.id and c.attid=wert)

…nur das geht in mysql nicht…

Die meiner Meinung nach etwas unelegante Lösung (da tmp. Tabelle), ist:

delete from tmp\_table
insert into tmp\_table select id,attval from t2 where attid=wert
select a.id,b.attvar from t1 left outer join tmp\_table on a.id=b.id

Alexander

Hi,

> > select a.id, if(strcmp(b.attval, 'Wert'), 'Wert', null)  
> > attvalneu  
> > from t1 a left outer join t2 b  
> > on a.id = b.id;

das liefert leider „zuviel“, da ich vorher auf die addid
filtern muss.

Wieso mußt Du irgendwas filtern?
Der Left Join hat zur Folge, daß Du alle Datensätze von t1 siehst. Damit wäre es fast fertig, nur willst Du alle attvals, die ungleich ‚Wert‘ sind, zu NULL konvertieren - das machst Du mit dem
Ausdruck if(strcmp(b.attval, ‚Wert‘), ‚Wert‘, null). Fertig! Keine Where-Klausel mehr!

Nur wirft mir gerade diese where Bedingung die
Datensätze, zu denen es keine attid gibt, weg.

Das ist klar, hier darfst Du keinen Where einsetzen.

> select a.id, b.attval from t1 a, t2 b  
> where a.id=b.id and b.attid=wert  
> union  
> select a.id,NULL from t1 a  
> where a.id not in (select c.id from t2 c where c.id=a.id and  
> c.attid=wert)

Das geht auch ohne IN:

select a.id, b.attval 
 from t1 a, t2 b
 where a.id=b.id 
 and b.attid=wert
union
select a.id, NULL 
 from t1 a, t2 b
 where a.id=b.id 
 and b.attid wert
union
select a.id, NULL 
 from t1 a left outer join t2 b
 on a.id = b.id
 and b.attid is null;

Der erste Ausdruck holt alle existierenden Attvals = Wert, der zweite holt alle existierenden Attvals Wert und macht sie zu NULL, und der dritte holt alle nicht existierenden Attvals dazu.

Die meiner Meinung nach etwas unelegante Lösung

Nun, ob dieses zweite Konstrukt elegant ist, sei mal dahingestellt :smile:

Aber der erste Vorschlag müßte eigentlich funktionieren. Unter Oracle klappt das (mit decode statt if ), unter Access auch (mit iif statt if).

Gruß

J.

Hi,

Hallo !

Erst einmal vielen Dank für die Antwort.

das liefert leider „zuviel“, da ich vorher auf die attid
filtern muss.

Wieso mußt Du irgendwas filtern?

Das Problem ist, das in der 2. Tabelle (id,attid,attval) (id,attid) einen zusammengesetzten Schlüssel bilden, und deswegen zu einer id mehrere Zeilen mit verschiedenen attid’s existieren. Für die gesuchte attid kann aber auch kein Eintrag (id,attid) vorhanden sein.

Ich will alle id’s aus Tabelle t1. Wenn (id, festgelegte attid) in Tabelle t2 enthalten ist, dann aus dieser Zeile attval, sonst null. Aber eben nicht die restlichen Zeilen (id, attidfestglegter Wert)

Beispiel
t1:
id
1
2
3
4

t2:
id attid attval
1 1 12
1 3 23
2 1 22
2 2 11
2 3 756
3 2 33
3 3 54

Im Ergebnis bei festgeletem Wert (attid) = 2:
1 NULL
2 11
3 33
4 NULL

Der Left Join hat zur Folge, daß Du alle Datensätze von t1
siehst. Damit wäre es fast fertig, nur willst Du alle attvals,
die ungleich ‚Wert‘ sind, zu NULL konvertieren - das machst Du

Nein, s.o.

mit dem
Ausdruck if(strcmp(b.attval, ‚Wert‘), ‚Wert‘, null). Fertig!

Das liefert doch aber alle Zeilen aus t2 mit id. Also auch die „falschen“ attid’s. Wenn ich da statt attval attid prüfe, habe ich im Ergebnis für eine id mehrere Zeilen, im schlimmsten Fall ein paar mit null und eine mit dem richtigen Wert. Alle mit null kann ich aber nicht wegwerfen, sonst habe ich da gleich wieder den Fall, das id’s fehlen. im Ergebnis soll id ja wieder Schlüssel und eindeutig sein.

Das geht auch ohne IN:

select a.id, b.attval
from t1 a, t2 b
where a.id=b.id
and b.attid=wert

… ok, alle mit dem Wert

union
select a.id, NULL
from t1 a, t2 b
where a.id=b.id
and b.attid wert

Das gibt zuviel, da es in t2 eben mehrere Zeilen (id, attid) geben kann, und ich hier nur die will, die in Tabelle 2 keinen Eintrag (id,attid=Wert) haben.
Das wert liefert aber alle Zeilen zurück, die eine andere attid haben, das sind viel zu viele.

union
select a.id, NULL
from t1 a left outer join t2 b
on a.id = b.id
and b.attid is null;

Ist nie null, Nullwerte gibt’s in der Spalte nicht.

Die meiner Meinung nach etwas unelegante Lösung

Nun, ob dieses zweite Konstrukt elegant ist, sei mal
dahingestellt :smile:

Ich kann mich nur nicht wirklich mit der temp. Tabelle anfreunden. So läuft es zumindest und macht, was es soll.
Ohne temp. Tabelle wäre es mir aber lieber. Ich hatte leider noch nicht die Möglichkeit, dies mit einer größeren Anzahl von Datensätzen hinsichtlich der Geschwindigkeit zu testen.

Alexander

Hi,

Beispiel
t1:
id
1
2
3
4

t2:
id attid attval
1 1 12
1 3 23
2 1 22
2 2 11
2 3 756
3 2 33
3 3 54

Im Ergebnis bei festgeletem Wert (attid) = 2:
1 NULL
2 11
3 33
4 NULL

OK, jetzt habe ich es kapiert :smile:

Mir fällt nichts in einer einzigen Abfrage ein.
Mit zwei Abfragen ginge das aber:
Erste Abfrage x:

SELECT t1.id, t2.attval 
 FROM t1 INNER JOIN t2 
 ON t1.id = t2.id 
 AND t2.attid = 2;

Zweite Abfrage:

select t1.id, attval
 from t1 left join x 
 on t1.id = x.id

Das löst das Problem.

Evtl. läßt sich das unter MySQL in eine Abfrage quetschen. Unter Oracle lautet diese:

select t1.id, x.attval
 from t1, (select a.id, b.attval 
 from t1 a, t2 b 
 where a.id = b.id 
 and b.attid=2) x
 where t1.id = x.id(+);

Unter MySQL müßte die Syntax so lauten:

select t1.id, x.attval
 from t1 left join (select a.id, b.attval 
 from t1 a, t2 b 
 where a.id = b.id 
 and b.attid=2) x
 on t1.id = x.id;

Gruß

J.

P.S. Kleiner Kommentar:

union
select a.id, NULL
from t1 a left outer join t2 b
on a.id = b.id
and b.attid is null;

Ist nie null, Nullwerte gibt’s in der Spalte nicht.

Doch. Das ist der Left-Join, der alle nicht-zugeordneten Datensätze bringt und ersetzt einen NOT IN. (Der Left Join bildet Pärchen aus a.id und b.id, und bei denen aus b, die er nicht findet, macht er NULL daraus - die picken wir uns raus :smile:

Hallo !

…und danke für die Antwort…

Mir fällt nichts in einer einzigen Abfrage ein.

Schade…


Evtl. läßt sich das unter MySQL in eine Abfrage quetschen.

… leider nicht, mysql bietet keine Subselects, und leider muss ich mit mysql auskommen. Also bleibt die temp. Tabelle…

P.S. Kleiner Kommentar:

union
select a.id, NULL
from t1 a left outer join t2 b
on a.id = b.id
and b.attid is null;

Ist nie null, Nullwerte gibt’s in der Spalte nicht.

Doch. Das ist der Left-Join, der alle nicht-zugeordneten
Datensätze bringt und ersetzt einen NOT IN. (Der Left Join
bildet Pärchen aus a.id und b.id, und bei denen aus b, die er
nicht findet, macht er NULL daraus - die picken wir uns raus

Alles klar, da hatte ich jetzt nicht dran gedacht, das der da Nullwerte erzeugt, falls es nicht existiert. Die Spalte ist „NOT NULL“, deswegen dachte ich, der Fall kann nicht eintreten, durch den OUTER JOIN kommen da ja aber Nullwerte dazu…

Vielen Dank nochmal…

Alexander