2011-01-11 31 views
54

Digamos que tengo una tabla de direcciones de clientes:Cómo seleccionar sólo las primeras filas para cada valor único de una columna

CName   | AddressLine 
------------------------------- 
John Smith  | 123 Nowheresville 
Jane Doe  | 456 Evergreen Terrace 
John Smith  | 999 Somewhereelse 
Joe Bloggs  | 1 Second Ave 

En la tabla, un cliente como John Smith puede tener varias direcciones. Necesito la consulta de selección para esta tabla para devolver solo la primera fila donde haya duplicados en 'CName'. Para esta tabla, debe devolver todas las filas, excepto la tercera (o 1ra); cualquiera de esas dos direcciones está bien, pero solo se puede devolver una. ¿Hay una palabra clave que pueda agregar a la consulta SELECT para filtrar en función de si el servidor ya ha visto el valor de la columna antes?

Respuesta

82

Una respuesta muy simple si dices que no te importa qué dirección se utiliza.

SELECT 
    CName, MIN(AddressLine) 
FROM 
    MyTable 
GROUP BY 
    CName 

Si desea que el primer acuerdo con, por ejemplo, una columna "insertada", entonces se trata de una consulta diferente

SELECT 
    M.CName, M.AddressLine, 
FROM 
    (
    SELECT 
     CName, MIN(Inserted) AS First 
    FROM 
     MyTable 
    GROUP BY 
     CName 
    ) foo 
    JOIN 
    MyTable M ON foo.CName = M.CName AND foo.First = M.Inserted 
+3

El uso de MIN con GROUP BY parece funcionar. – nuit9

+0

Aunque puede no estar destinado a ser utilizado de esta manera al seleccionar 10 columnas. También parece que no puede aceptar una columna del tipo de bit. – nuit9

+0

@ nuit9: por supuesto no funcionará con bit y 10 columnas. Ninguno de estos hechos está en su pregunta. Utilizarías la segunda técnica o la técnica de Ben Thul. Respondí lo que preguntaste específicamente, con consejos sobre cómo resolver de manera más general. – gbn

19

En SQL 2k5 +, puede hacer algo como:

;with cte as (
    select CName, AddressLine, 
    rank() over (partition by CName order by AddressLine) as [r] 
    from MyTable 
) 
select CName, AddressLine 
from cte 
where [r] = 1 
+0

Por favor, explique qué significa rango, partición y [r] do – Roberto

+5

No, para ser sarcástico, pero leer la documentación de Wii será más útil que todo lo que podría decir aquí. Simplemente arroje "rank function SQL" en su motor de búsqueda favorito. ¡Avíseme si tiene alguna pregunta específica después de eso! –

9

Puede usar row_number() para obtener el número de fila de la fila. Utiliza el comando over - la cláusula partition by especifica cuándo reiniciar la numeración y order by selecciona en qué orden el número de fila. Incluso si agregó un order by al final de su consulta, conservaría el orden en el comando over al numerar.

select * 
from mytable 
where row_number() over(partition by Name order by AddressLine) = 1 
+5

En postgresql, las funciones de ventana no están permitidas en la cláusula WHERE – ekanna

+1

. Esto tampoco está permitido para MS-SQL. – Mixxiphoid

+0

'ROW_NUMBER()' no funciona en la cláusula 'Where' en Teradata también –

0

Usted puede utilizar la sintaxis row_numer() over(partition by ...) así:

select * from 
(
select * 
, ROW_NUMBER() OVER(PARTITION BY CName ORDER BY AddressLine) AS row 
from myTable 
) as a 
where row = 1 

Lo que esto hace es que crea una columna llamada row, que es un contador que se incrementa cada vez que se ve la misma CName, y indexa esas ocurrencias por AddressLine. Al imponer where row = 1, se puede seleccionar CName cuyo AddressLine viene primero en orden alfabético. Si el order by fuera desc, elegiría el CName cuyo AddressLine viene en orden alfabético por última vez.

Cuestiones relacionadas