2017-12-01 4 views
1

Meine App verfügt über eine users Tabelle, eine teams Tabelle, eine teams_users Tabelle und eine assessments Tabelle. Übersimplified:Effiziente Abfrage zum Verbinden von drei Tabellen

**users** 
id 

**teams** 
id 

**teams_users** 
team_id 
user_id 

**assessments** 
id 
user_id 
team_id 

Ein Benutzer kann viele Bewertungen haben.

Wenn ich Benutzer in einem bestimmten Kontext ergreife, möchte ich auch ihre zugehörigen Bewertungen (das ganze Objekt) plus als Wert für den zurückgegebenen Benutzer die team_ids, die im Wesentlichen das Ergebnis der Rupfen der team_id Spalte sind für alle Zeilen in der teams_users Tabelle mit user_id des Benutzers.

Ich weiß, wie jede dieser Abfragen getrennt zu tun, aber ich bin mir nicht sicher, wie viel ich zu einer effizienten Abfrage kombinieren kann, und noch unsicherer wie zu tun, wie ich ziemlich rostig mit SQL bin . Mein erster Gedanke war etwas in der Art:

SELECT users.id, users.name, users.email, users.role 
FROM users 
INNER JOIN assessments ON assessments.user_id = users.id 
WHERE users.id='someID' 

In dieser Abfrage tue ich eigentlich nichts mit den Bewertungen. Also ich erwäge etwas wie folgt aus:

SELECT users.id, users.name, users.email, users.role, assessments 
FROM users 
INNER JOIN assessments ON assessments.user_id = users.id 
WHERE users.id='someID' 

Diese Art der Werke, sondern gibt die Einschätzungen als Klammer-getrennte Anordnung von Werten (I JavaScript bin mit, und die pg Bibliothek sonst Antworten in JSON parst), die es besser scheint auf einer SQL-Ebene zu beheben, als in JSON zu analysieren:

{ 
    id: 'mEPRVHp3', 
    name: 'Frank', 
    role: 'admin', 
    assessments: '(uibbH0ff,rPWZDIoA,mEPRVHp3,99,2017-12-01)' 
} 

um zu klären, ich würde es vorziehen, etwa so:

{ 
    id: 'mEPRVHp3', 
    name: 'Frank', 
    role: 'admin', 
    assessments: [ 
    { 
     id: 'uibbH0ff', 
     team_id: 'rPWZDIoA', 
     user_id: 'mEPRVHp3', 
     score: 99, 
     date: '2017-12-01' 
    } 
    ] 
} 

Dann separat , Würde ich gerne die teams_usersteam_id s in der gleichen Abfrage greifen. So dass das Ende Antwort so etwas wie diese:

{ 
    id: 'mEPRVHp3', 
    name: 'Frank', 
    role: 'admin', 
    assessments: [ 
    { 
     id: 'uibbH0ff', 
     team_id: 'rPWZDIoA', 
     user_id: 'mEPRVHp3', 
     score: 99, 
     date: '2017-12-01' 
    } 
    ], 
    team_ids: ['rPWZDIoA'] 
} 

Versuchte teams_users.team_id AS team_ids bis zum Ende der SELECT-Anweisung an, brach aber die gesamte Abfrage.

Noch einmal, nicht sicher, ob das möglich ist, und in diesem Fall nicht ganz sicher, wie es geht.

Irgendwelche Gedanken? Ich arbeite an meinen begrenzten SQL-Fähigkeiten.

Danke!

Antwort

2

Angenommen, Sie verwenden PostgreSQL Version 9.3 oder neuer.

Ich würde row_to_json() verwenden, um den Bewertungssatz zu "formatieren". Dann würde ich einen lateralen Join verwenden, um Ihre Team-IDs zu erhalten.

Wie so:

SELECT 
    usr.id, 
    usr.name, 
    usr.email, 
    usr.role, 
    row_to_json(asmnt) AS assessments, --Use row_to_json() 
    tusr.team_ids 
FROM 
    users usr 
INNER JOIN 
    assessments asmnt 
    ON asmnt.user_id = usr.id 
INNER JOIN LATERAL 
    (
    SELECT 
     array_agg(teams_users.team_id) AS team_ids 
    FROM 
     teams_users 
    WHERE 
     teams_users.user_id = usr.id 
    ) tusr 
    ON TRUE 
WHERE 
    usr.id = 'someID'; 
+0

Das ist genial! Vielen Dank! Ran in ein Problem - "Assessments" wird als ein einzelnes JSON-Objekt formatiert (sinnvoll), aber ein Benutzer kann viele Assessments haben. Ich habe 'array_to_json (asmnt)' versucht, aber es wurde ein Fehler ausgegeben, der besagt, dass das keine Funktion ist. Irgendwelche Ideen, wie das zu beheben ist? Vielen Dank! – Sasha

+0

Verstanden! 'jsonb_build_array' funktionierte wie ein Zauber! https://www.postgresql.org/docs/9.5/static/functions-json.html – Sasha