Cómo seleccionar la primera fila de una unión que devuelve filas múltiples en la clave primaria

15

Esto está relacionado con esta pregunta: unir varias tablas da como resultado filas duplicadas

Tengo dos mesas a las que me estoy uniendo. Comparten una llave. La tabla de persona tiene un nombre por clave principal, pero la tabla de correo electrónico tiene varios correos electrónicos por ID de persona. Solo quiero mostrar el primer correo electrónico por persona. Actualmente recibo varias filas por persona porque tienen varios correos electrónicos. Estoy ejecutando SQL-Server 2005.

EDITAR: Esto es T-SQL. El primer correo electrónico es literalmente la primera fila de correo electrónico por persona.

Edición 2: primer correo electrónico, como veo, sería la primera fila de correo electrónico que se muestra en la unión a medida que SQL funciona a través de la consulta. No importa qué correo electrónico aparezca. Solo que no aparece más de un correo electrónico. Espero que eso lo aclare.

Table1: Person
Table2: Email

Select Person.PersonName, Email.Email
From person 
left join on Person.ID=Email.PersonId;
Normandantzig
fuente
3
¿Qué quieres decir con "primer" correo electrónico? ¿Qué criterio de clasificación determina "primero"?
Queue Mann
1
probaste el top 1?
Racer SQL
3
¿Qué DBMS estás usando? Postgres? ¿Oráculo?
a_horse_with_no_name
3
La "primera fila de correo electrónico por persona" realmente no nos dice nada. "Primero" ¿con qué criterios? Las tablas SQL no tienen un orden inherente.
ypercubeᵀᴹ
55
Bueno, ese es un criterio válido: "No me importa qué fila, solo una".
ypercubeᵀᴹ

Respuestas:

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
fuente
1
¿Qué es la 'A'? ¿Es una abreviatura del nombre de la tabla?
normandantzig
2
@normandantzig Eso es un alias .
Bacon Bits
1
1.) ¿Alias ​​mis dos tablas usando De (Seleccione Person.PersonName, Email.Email, ROW_NUMBER () OVER (PARTITION BY Person.ID ORDER BY Email.Email) AS RN From person left unirse en Person.ID = Email.PersonId) A y 2.) para que pueda referirse a ambas columnas usando A como tabla?
normandantzig
44
Lo que está dentro del paréntesis se llama tabla derivada . Es una tabla válida, al igual que las tablas base, pero su duración es solo por la duración de la ejecución de la consulta. Debe tener un nombre (o alias) y @sabin eligió nombrarlo A. Esta tabla tiene 3 columnas (PersonName, Correo electrónico, RN) y, fuera de los paréntesis, puede usar A.Emailtal como puede usar tablename.columnnamepara cualquier otra tabla en su código.
ypercubeᵀᴹ
13

Usaría una solicitud externa para esto, me parece más legible.

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;
Señor magoo
fuente
5

Como no importa qué correo electrónico aparece. Creo que el siguiente es muy directo.

Select Person.PersonName,  MIN(Email.Email)
From person 
left join email 
on Person.ID=Email.PersonId
group by Person.Id, Person.PersonName
JGA
fuente
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
Cola Mann
fuente
1
¿Qué es la 'P'? ¿Es una abreviatura del nombre de la tabla?
normandantzig
1
'P' es un alias para Persona. Sigue la declaración de la tabla en la cláusula FROM.
Queue Mann
1
@normandantzig Ambos son válidos en SQL Server en la mayoría de las situaciones.
Bacon Bits