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;

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

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;

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

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

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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.