UNION vermeiden?

UNION vermeiden?

am 18.06.2007 20:47:08 von Matthias Moers

Hallo zusammen,

ich benutze MySQL 5.0.37 und habe zwei Tabellen mit den angegebenen
Spalten:

Gegenstände: ID | Name | Details

besitzt: userID | gegenstandID

Nun suche ich eine SQL-Query die mir bei gegebener userID _alle_
Gegenstände mit einer zusätzlichen Spalte "besitzt" liefert, die mir
sagt ob der angegebene Benutzer den Gegenstand besitzt (Wert 1) oder
nicht (Wert 0).

Beispiel:

Gegenstände:
1 | Hammer | xyz
2 | Zange | abc
3 | Schere | 123

besitzt:
1 | 1
1 | 3
2 | 1
2 | 2

Die Query mit userID=1 ausgeführt soll dann
1 | Hammer | xyz | 1
2 | Zange | abc | 0
3 | Schere | 123 | 1
liefern, mit userID=2 soll
1 | Hammer | xyz | 1
2 | Zange | abc | 1
3 | Schere | 123 | 0
herauskommen, und mit userID=3
1 | Hammer | xyz | 0
2 | Zange | abc | 0
3 | Schere | 123 | 0

Mir ist bisher nur eine Lösung mit UNION eingefallen:
SELECT *,1 FROM Gegenstände WHERE id IN (SELECT gegenstandID FROM
besitzt WHERE userID=$userID)
UNION
SELECT *,0 FROM Gegenstände WHERE id NOT IN (SELECT gegenstandID FROM
besitzt WHERE userID=$userID)

Die Lösung gefällt mir aber nicht, da später evtl andere Spalten
hinzukommen sollen (wie z.B. "benutzt"), dann bräuchte ich zu viele
UNIONS ;)

Hoffe ihr habt ne Idee,
Gruß,
Matthias

Re: UNION vermeiden?

am 18.06.2007 22:08:14 von Heiko Richler

Matthias Moers wrote:
> ich benutze MySQL 5.0.37 und habe zwei Tabellen mit den angegebenen
> Spalten:
>
> Gegenstände: ID | Name | Details
>
> besitzt: userID | gegenstandID
>
> Nun suche ich eine SQL-Query die mir bei gegebener userID _alle_

Hinweis auf left (oder right) join.

> Gegenstände mit einer zusätzlichen Spalte "besitzt" liefert, die mir
> sagt ob der angegebene Benutzer den Gegenstand besitzt (Wert 1) oder
> nicht (Wert 0).

Leichter ist es die Anzahl der besessenen Werkzeuge auszugeben:
0 wäre dann Deine 0
>0 deine 1

SELECT Gegenstände.ID, Gegenstände.Name, Gegenstände.Detail,
count(besitzt) as anzahl
FROM Gegenstände
LEFT JOIN besitzt
WHERE userID=$userID
GROUP BY Gegenstände.ID, Gegenstände.Name, Gegenstände.Detail


Du solltest Dir zu join (inner, left, right, ...) sowie group by das
Handbuch durchlesen.

> Die Lösung gefällt mir aber nicht, da später evtl andere Spalten
> hinzukommen sollen (wie z.B. "benutzt"), dann bräuchte ich zu viele
> UNIONS ;)

Ich fürchte Du hast kein Datenmodell erstellt, oder? Wenn Du jetzt noch
etwas Zeit in ein Modell bzw. die Grundlagen dazu steckst wirst Du Dir
mit etwas Glück viele Probleme ersparen.

Heiko
--
http://portal.richler.de/ Namensportal zu Richler
http://www.richler.de/ Heiko Richler: Computer - Know How!
http://www.richler.info/ private Homepage

Re: UNION vermeiden?

am 18.06.2007 23:17:32 von Matthias Moers

Hallo,

Heiko Richler schrieb
> Matthias Moers wrote:
>> ich benutze MySQL 5.0.37 und habe zwei Tabellen mit den angegebenen
>> Spalten:
>>
>> Gegenstände: ID | Name | Details
>>
>> besitzt: userID | gegenstandID
>>
>> Nun suche ich eine SQL-Query die mir bei gegebener userID _alle_
>
> Hinweis auf left (oder right) join.

Danke für den Hinweis, das war der entscheidene Punkt. Die Bedeutung
davon war mir bisher nicht bekannt...

Gruß,
Matthias

Re: UNION vermeiden?

am 18.06.2007 23:46:00 von Axel Schwenke

Heiko Richler wrote:
> Matthias Moers wrote:
>>
>> Nun suche ich ...
>
> Hinweis auf left (oder right) join.

Ja. Und allgemein heißen die OUTER JOIN (im Gegensatz zu INNER JOIN).

> SELECT Gegenstände.ID, Gegenstände.Name, Gegenstände.Detail,
> count(besitzt) as anzahl
> FROM Gegenstände
> LEFT JOIN besitzt
> WHERE userID=$userID
> GROUP BY Gegenstände.ID, Gegenstände.Name, Gegenstände.Detail

Was soll das? Das ist ein klassischer LEFT JOIN:

SELECT gegenstand.* ,
NOT(ISNULL(besitzt.gegenstand_id)) AS besitzt
FROM gegenstand LEFT JOIN besitzt ON gegenstand.id = besitzt.gegenstand_id
WHERE besitzt.user_id = ...

> Du solltest Dir zu join (inner, left, right, ...) sowie group by das
> Handbuch durchlesen.

Du auch.


XL

Re: UNION vermeiden?

am 19.06.2007 08:48:52 von Heiko Richler

Axel Schwenke wrote:
>> SELECT Gegenstände.ID, Gegenstände.Name, Gegenstände.Detail,
>> count(besitzt) as anzahl
>> FROM Gegenstände
>> LEFT JOIN besitzt
>> WHERE userID=$userID
>> GROUP BY Gegenstände.ID, Gegenstände.Name, Gegenstände.Detail
>
> Was soll das? Das ist ein klassischer LEFT JOIN:

ON hatte ich natürlich vergessen, das ist richtig.

Das Group by halte ich für notwendig. Das was vom Datenmodell zu
erkennen ist zeigt, dass es grundsätzlich möglich ist den gleichen Typ
eines Werkzeugs mehrmals zu besitzen. Auch wenn es nicht dabei stand
gehe ich davon aus, dass Dubletten nicht gewünscht sind.

Auch darum meine Empfehlung die entsprechenden Teile zu SQL zu lesen.
Dann kann der OP sich selbst eine Meinung bilden.

Heiko
--
http://portal.richler.de/ Namensportal zu Richler
http://www.richler.de/ Heiko Richler: Computer - Know How!
http://www.richler.info/ private Homepage

Re: UNION vermeiden?

am 19.06.2007 08:57:27 von Gregor Kofler

Heiko Richler meinte:

> Das Group by halte ich für notwendig. Das was vom Datenmodell zu
> erkennen ist zeigt, dass es grundsätzlich möglich ist den gleichen Typ
> eines Werkzeugs mehrmals zu besitzen. Auch wenn es nicht dabei stand
> gehe ich davon aus, dass Dubletten nicht gewünscht sind.

Dafür gäbe es DISTINCT.

Gruß, Gregor


--
http://www.gregorkofler.at ::: Landschafts- und Reisefotografie
http://www.image2d.com ::: Bildagentur für den alpinen Raum

Re: UNION vermeiden?

am 19.06.2007 10:46:19 von Axel Schwenke

Heiko Richler wrote:
> Axel Schwenke wrote:

>>> SELECT Gegenstände.ID, Gegenstände.Name, Gegenstände.Detail,
>>> count(besitzt) as anzahl
>>> FROM Gegenstände
>>> LEFT JOIN besitzt
>>> WHERE userID=$userID
>>> GROUP BY Gegenstände.ID, Gegenstände.Name, Gegenstände.Detail
>>
>> Was soll das? Das ist ein klassischer LEFT JOIN:
>
> Das Group by halte ich für notwendig. Das was vom Datenmodell zu
> erkennen ist zeigt, dass es grundsätzlich möglich ist den gleichen Typ
> eines Werkzeugs mehrmals zu besitzen. Auch wenn es nicht dabei stand
> gehe ich davon aus, dass Dubletten nicht gewünscht sind.

Jein. Die blinde Verwendung von JOIN mit GROUP BY ist ein typischer
Anfängerfehler. Ansonsten gibt das Datenmodell nicht genug her um
einschätzen zu können, ob die Gegenstand-Tabelle Einträge pro Instanz
oder pro Klasse hat. Aber wenn das pro Klasse ist und man mehr als
einen Gegenstand der gleichen Art haben kann, würde man ein Anzahl
Feld in der besitzt-Tabelle haben wollen.


XL