Como selecionar a primeira linha de uma junção que retorna várias linhas na chave primária

15

Isso está relacionado a esta pergunta: A união de várias tabelas resulta em linhas duplicadas

Eu tenho duas tabelas nas quais estou entrando. Eles compartilham uma chave. A tabela de pessoas tem um nome por chave primária, mas a tabela de email tem vários emails por personId. Quero mostrar apenas o primeiro email por pessoa. Atualmente, recebo várias linhas por pessoa porque elas têm vários e-mails. Estou executando o SQL-Server 2005.

EDIT: Este é o T-SQL. O primeiro email é literalmente a primeira linha de email por pessoa.

Editar 2: o primeiro email, a meu ver, seria a primeira linha de email que aparece na junção, à medida que o SQL trabalha na consulta. Não importa qual e-mail aparece. Só que não é exibido mais de um email. Espero que isso fique mais claro.

Table1: Person
Table2: Email

Select Person.PersonName, Email.Email
From person 
left join on Person.ID=Email.PersonId;
normandantzig
fonte
3
O que você quer dizer com "primeiro" email? Que critério de classificação determina "primeiro"?
Fila Mann,
1
você tentou o top 1?
Racer SQL
3
Qual DBMS você está usando? Postgres? Oráculo?
a_horse_with_no_name
3
A "primeira linha de email por pessoa" não nos diz nada. "Primeiro" por quais critérios? As tabelas SQL não têm ordem inerente.
ypercubeᵀᴹ
5
Bem, esse é um critério válido: "Eu não ligo para qual linha, apenas uma".
ypercubeᵀᴹ

Respostas:

18
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
fonte
1
O que é o 'A'? É uma abreviação do nome da tabela?
Normandantzig
2
@normandantzig Esse é um apelido .
Bacon Bits
1
1.) Você aliasou minhas duas tabelas usando o comando From (Select Person.PersonName, Email.Email, ROW_NUMBER () OVER (PARTITION BY Person.ID ORDER BY Email.Email) AS RN Da pessoa deixada ingressar em Person.ID = Email.PersonId) A E 2.) para que você possa consultar as duas colunas usando A como a tabela?
Normandantzig
4
O que está dentro dos parênteses é chamado de tabela derivada . É uma tabela válida, assim como as tabelas base, mas sua duração é apenas para a duração da execução da consulta. Ele deve ter um nome (ou apelido) e o @sabin escolheu nomeá-lo A. Esta tabela possui 3 colunas (PersonName, Email, RN) e fora dos parênteses, você pode usar A.Emailda mesma forma que tablename.columnnameem qualquer outra tabela do seu código.
ypercubeᵀᴹ
13

Eu usaria uma aplicação externa para isso, acho mais legível.

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;
Senhor Magoo
fonte
5

Como não importa qual e-mail é exibido. Eu acho que o seguinte é muito direto.

Select Person.PersonName,  MIN(Email.Email)
From person 
left join email 
on Person.ID=Email.PersonId
group by Person.Id, Person.PersonName
JGA
fonte
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
Queue Mann
fonte
1
O que é o 'P'. É uma abreviação do nome da tabela?
Normandantzig
1
'P' é um apelido para Person. Segue a declaração da tabela na cláusula FROM.
Fila Mann,
1
@normandantzig Ambos são válidos no SQL Server na maioria das situações.
Bacon Bits