So wählen Sie die erste Zeile aus einem Join aus, der mehrere Zeilen auf dem Primärschlüssel zurückgibt

14

Dies hängt mit dieser Frage zusammen: Das Verknüpfen mehrerer Tabellen führt zu doppelten Zeilen

Ich habe zwei Tische, an denen ich teilnehme. Sie teilen einen Schlüssel. Die Personentabelle hat einen Namen pro Primärschlüssel, aber die E-Mail-Tabelle enthält mehrere E-Mails pro Personen-ID. Ich möchte nur die erste E-Mail pro Person anzeigen. Derzeit erhalte ich mehrere Zeilen pro Person, da sie mehrere E-Mails hat. Ich verwende SQL-Server 2005.

EDIT: Dies ist T-SQL. Die erste E-Mail ist buchstäblich die erste E-Mail-Zeile pro Person.

Bearbeiten 2: Erste E-Mail, wie ich sehe, ist die erste E-Mail-Zeile, die im Join angezeigt wird, wenn SQL die Abfrage durcharbeitet. Es ist mir egal, welche E-Mail angezeigt wird. Nur dass nicht mehr als eine E-Mail angezeigt wird. Ich hoffe das macht es klarer.

Table1: Person
Table2: Email

Select Person.PersonName, Email.Email
From person 
left join on Person.ID=Email.PersonId;
normandantzig
quelle
3
Was meinst du mit "erster" E-Mail? Welche Sortierkriterien bestimmen "zuerst"?
Warteschlange Mann
1
Hast du Top 1 ausprobiert?
Racer SQL
3
Welches DBMS verwenden Sie? Postgres? Orakel?
a_horse_with_no_name
3
Die "erste E-Mail-Zeile pro Person" sagt uns eigentlich nichts. "Zuerst" nach welchen Kriterien? SQL-Tabellen haben keine inhärente Reihenfolge.
Ypercubeᵀᴹ
5
Nun, das ist ein gültiges Kriterium: "Es ist mir egal, welche Zeile, nur eine".
Ypercubeᵀᴹ

Antworten:

17
SELECT
    A.PersonName, A.Email
FROM
        (
        Select Person.PersonName, Email.Email
            ,ROW_NUMBER() OVER(PARTITION BY Person.ID ORDER BY Email.Email) AS RN
        From person 
        left join Email on Person.ID=Email.PersonId
        ) A
WHERE A.RN = 1
Sabin Bio
quelle
1
Was ist das "A"? Ist es eine Abkürzung für den Tabellennamen?
Normandantzig
2
@normandantzig Das ist ein Alias .
Bacon Bits
1
1.) Haben Sie beide Tabellen mit dem Alias ​​"Von" (Wählen Sie "Person.PersonName", "Email.Email", "ROW_NUMBER") ("PARTITION BY Person.ID ORDER BY Email.Email") als RN From person left join on Person.ID = Email.PersonId) A und 2.) damit Sie mit A als Tabelle auf beide Spalten verweisen können?
Normandantzig
4
Was sich in der Klammer befindet, wird als abgeleitete Tabelle bezeichnet . Es ist eine gültige Tabelle, genau wie Basistabellen, aber ihre Lebensdauer gilt nur für die Dauer der Abfrageausführung. Es muss einen Namen (oder Alias) haben und @sabin hat ihn benannt A. Diese Tabelle enthält 3 Spalten (PersonName, Email, RN). Außerhalb der Klammern können Sie sie A.Emailgenauso verwenden, wie Sie sie tablename.columnnamefür jede andere Tabelle in Ihrem Code verwenden können.
Ypercubeᵀᴹ
13

Ich würde dafür eine äußere Bewerbung verwenden, ich finde sie besser lesbar.

Select Person.PersonName, coalesce(Email.Email,'No email found.') as Email
From person 
outer apply (
  select top(1) Email.Email 
  from Email 
  where Person.ID=Email.PersonId
  order by <whatever suits you>
) as Email;
Herr Magoo
quelle
5

Da es egal ist, welche E-Mail angezeigt wird. Ich denke, dass der folgende sehr direkt ist.

Select Person.PersonName,  MIN(Email.Email)
From person 
left join email 
on Person.ID=Email.PersonId
group by Person.Id, Person.PersonName
JGA
quelle
3
select
  P.PersonID,
  (SELECT TOP 1 E.Email FROM Email E WHERE E.PersonID = P.PersonID ORDER BY <pick your column here>)
from
  Person P
Warteschlange Mann
quelle
1
Was ist das "P". Ist es eine Abkürzung für den Tabellennamen?
Normandantzig
1
'P' ist ein Alias ​​für Person. Es folgt der Tabellendeklaration in der FROM-Klausel.
Warteschlange Mann
1
@normandantzig Beide sind in den meisten Situationen in SQL Server gültig.
Bacon Bits