MYSQL: Zwei IDS Auswählen (aus einer Tabelle) und damit eine zweite Tabellezeile selektieren


#1
Bildschirmfoto 2019-01-30 um 20.57.05.png Bildschirmfoto 2019-01-30 um 20.57.45.png

Hallo liebes Forum,
und schon wieder brennt mir eine Frage unter den Fingern. Ich versuche über zwei IDs aus der Sten Tabelle die richtige Conversation
aus der zweiten Tabelle zu bekommen.


Kurz zu dem Beispiel:

James Keith und Patrick Black chatten miteinander, Tabelle eins.
Gesucht ist die "Conversation" aus der zweiten Tabelle.

*SELECT * FROM `user_visitors` WHERE first name LIKE James AND last name LIKE Keith OR first name LIKE Patrick AND last name LIKE Black
Resultat wäre in diesem Fall: eine zweizeilige Ausgabe, wie auch oben zu sehen, James Keith und Patrick Black, beide haben eine ID (Schlüssel für zweite Tabelle)

Ich bräuchte ein Statement in dem ich ID1(James) und ID2(Patrick) herausbekomme aus Tabelle 1
und damit dann aus Tabelle 2, aus beiden Schlüsseln (ID0, und ID16) die Conversation selektieren kann.

Wie geht das? In einem Select ?

Ersuche um Hilfe, vielen Dank
 
Zuletzt bearbeitet:

Yaslaw

n/a
Moderator
#2
Vornweg. Wenn du mit AND und OR arbeitest, solltest du Klammern setzen. Dann ist klar wie die Hierarchie ist.
SQL:
WHERE 
    (
        first name LIKE James 
        AND last name LIKE Keith
    ) OR (
        first name LIKE Patrick 
        AND last name LIKE Black
    )
Zu deiner Frage.

Bauen wir doch mal auf (alles ungetestet)
ALs erstes die Abfrage mit den IDs der 2 Personen
SQL:
-- [A]:
SELECT id
FROM user_visitors
WHERE 
    (
        first name LIKE James 
        AND last name LIKE Keith
    ) OR (
        first name LIKE Patrick 
        AND last name LIKE Black
    )
Dann bauen wir die Konversationstabelle su um, dass die 2 Ids untereinander stehen.

SQL:
-- [B]:
select chat_id, user_id, 'user' as type
from conveersation
union select chat_id, partner_id as user_id, 'partner_id' as type
from conveersation
Dann verbinden wir die 2 Tabellen über die neue ID. Gruppieren, damit nur eine Zeile pro Chat ausgegeben wird.
Zusätzlich zählen wir, ob es auch 2 Zeilen aus B sind um sicher zu gehen, dass James und Patrick zusammen diskutiert haben und nicht auch James und Doris
Ich habe A und B mal nur als Platzhalter drin
SQL:
-- [C]:
select b.chat_id
from [B] as b, [A] as a
where b.user_id = a.id
group by b.chat_id
having count(*) = 2
Ünd jetzt alles zusammengesetzt
SQL:
select b.chat_id
from 
    (
        select chat_id, user_id, 'user' as type
        from conveersation
        union select chat_id, partner_id as user_id, 'partner_id' as type
        from conveersation
    ) as b,
    (
        SELECT id
        FROM user_visitors
        WHERE 
            (
                first name LIKE James 
                AND last name LIKE Keith
            ) OR (
                first name LIKE Patrick 
                AND last name LIKE Black
            )
    ) as a
where b.user_id = a.id
group by b.chat_id
having count(*) = 2
Wenn du den Rest des Chats sehen willst, dann solltest du den erst danach anbinden
SQL:
select t.*
from conveersation as t, [C] as c
where T.chat_id = c.chat_id
 
#4
Servus habe deinen Code jetzt ausprobiert, er funktioniert aber leider nicht wie er soll.
In einem Beispiel Funktioniert er "James Keith" mit "Patrick Black".

Was nicht funktioniert:
Per Vorname und Nachname des Partners(partner_id) und des Users (user_id) will ich eine Conversation
auswählen. Ich hab die Namen verändert und einige Zeilen hinzugefügt....

Code:
SELECT b.*
FROM
    (
        SELECT t.*
        FROM `chat` as t, `user_visitor` as c
        WHERE (
               t.user_id = c.id ) OR
              (t.partner_id = c.id)
            
    ) as b,
    (
        SELECT id
        FROM `user_visitor`
        WHERE
            (
                `firstname` LIKE "Patrick"
                AND `lastname` LIKE "Black"
            ) OR (
                `firstname` LIKE "Michael"
                AND `lastname` LIKE "Waldbauer"
            )
    ) as a
WHERE b.user_id = a.id
GROUP BY b.chat_id
having count(*) = 2

RESULT:
Bildschirmfoto 2019-01-31 um 17.35.12.png


Hier eine Übersicht über die Erweiterten Tabellen:

Bildschirmfoto 2019-01-31 um 17.36.22.png
Bildschirmfoto 2019-01-31 um 17.36.38.png




Was mache ich falsch?
 
Zuletzt bearbeitet:
#5
Code:
SELECT b.*
FROM
    (
        SELECT chat_id, user_id, conversation as 'conversation'
        FROM `chat`
        UNION SELECT chat_id, partner_id as user_id, conversation AS `conversation`
        FROM `chat`
    ) as b,
    (
        SELECT id
        FROM user_visitor
        WHERE
            (
                `firstname` LIKE "Patrick"
                AND `lastname` LIKE "Black"
            ) OR (
                `firstname` LIKE "Michael"
                AND `lastname` LIKE "Waldbauer"
            )
    ) as a
where b.user_id = a.id
GROUP BY `chat_id`
having count(*) = 2
Dieses Statement funktioniert und liefert auch die "Conversation" zurück. Vielen Dank!

Die Master Frage:
Geht das auch noch schneller? 0.0095 Sekunden ist langsamer als wenn ich einfach
[A] mache und dann in PHP mit einem zweiten Statement die zwei IDs manuell Selektiere?

DAUER: 0.0016 Sekunden
Code:
SELECT id
FROM user_visitor
WHERE
    (
        `firstname` LIKE "James"
        AND`lastname` LIKE "Keith"
    ) OR (
        `firstname` LIKE "Patrick"
        AND`lastname` LIKE "Black"
    )
Limit 0,2
DAUER: UNBEKANNT
Code:
$row          = mysql::executeResult($statment);
$id_one       = $row[0]['id'];
$id_second    = $row[1]['id'];
DAUER: 0.0014 Sekunden
Code:
SELECT `conversation`
FROM `chat`
WHERE
(`partner_id` = 18 AND `user_id` = 16 )
OR (`user_id` = 18 AND `partner_id` = 16)
LIMIT 0,1
INSGESAMT-DAUER CA: 0.0046 Sekunden
 
Zuletzt bearbeitet:

Yaslaw

n/a
Moderator
#6
Ob es schneller geht, kommt auf die Indexe etc. drauf an. Es gibt noch viele weitere Möglichkeiten zum Auswählen des Chats. Was schneller ist kann an selten direkt sagen. Zu dem Thema gibt es dicke Bücher.
Der UNION ist auch nicht performant.

Anstelle die Verknüpfung über den WHERE kann man es mit einem INNER JOIN versuchen.
Anstelle des JOINS ev. 2 mal [A] einbinden und mit Inner Joins an die 2 Ids hängen
Indexe auf die Ids setzen
Anstelle eines Joins ein Innerere Subquery setzen und mit IN() prüfen
etc.
AUf alle Fälle ist die Suche über die Namen sicher langsam.
 

Yaslaw

n/a
Moderator
#8
Oh, noch eine Bremse. EIn Group by auf Select *. Das sollte man niemals so verwenden. MySql ist da Fehlerbehaftet tollerant. Jede Andere DB wirft dir da zurecht ein Fehler.

So auf die Schnelle
SQL:
SELECT b.chat_id
FROM
    (
        SELECT chat_id, user_id, conversation as 'conversation'
        FROM `chat`
        UNION SELECT chat_id, partner_id as user_id, conversation AS `conversation`
        FROM `chat`
    ) as b
    inner join (
        SELECT id
        FROM user_visitor
        WHERE
            (
                `firstname` LIKE "Patrick"
                AND `lastname` LIKE "Black"
            ) OR (
                `firstname` LIKE "Michael"
                AND `lastname` LIKE "Waldbauer"
            )
    ) as a
    on b.user_id = a.id
GROUP BY b.chat_id
having count(*) = 2
SQL:
SELECT b.chat_id
from chat as b
where
    user_id in (
        SELECT id
        FROM user_visitor
        WHERE
            (
                `firstname` LIKE "Patrick"
                AND `lastname` LIKE "Black"
            ) OR (
                `firstname` LIKE "Michael"
                AND `lastname` LIKE "Waldbauer"
            )
    )
    and partner_id in (
        SELECT id
        FROM user_visitor
        WHERE
            (
                `firstname` LIKE "Patrick"
                AND `lastname` LIKE "Black"
            ) OR (
                `firstname` LIKE "Michael"
                AND `lastname` LIKE "Waldbauer"
            )
    )
GROUP BY b.chat_id
having count(*) = 2