¿Cómo usar DISTINCT y ORDER BY en la misma instrucción SELECT?


117

Después de ejecutar la siguiente declaración:

SELECT  Category  FROM MonitoringJob ORDER BY CreationDate DESC

Obtengo los siguientes valores de la base de datos:

test3
test3
bildung
test4
test3
test2
test1

pero quiero que se eliminen los duplicados, así:

bildung
test4
test3
test2
test1

Intenté usar DISTINCT pero no funciona con ORDER BY en una declaración. Por favor ayuda.

Importante:

  1. Lo probé con:

    SELECT DISTINCT Category FROM MonitoringJob ORDER BY CreationDate DESC

    no funciona.

  2. Ordenar por CreationDate es muy importante.


1
¿Cómo no funciona? ¿Salida incorrecta?
Fedearne

Respuestas:


195

El problema es que las columnas utilizadas en ORDER BYno se especifican en DISTINCT. Para hacer esto, necesita usar una función agregada para ordenar y usar a GROUP BYpara hacer el DISTINCTtrabajo.

Intente algo como esto:

SELECT DISTINCT Category, MAX(CreationDate) 
FROM MonitoringJob 
GROUP BY Category 
ORDER BY MAX(CreationDate) DESC, Category

99
Ni siquiera necesita la palabra clave DISTINCT si está agrupando por categoría.
MatBailie

18

Columnas de clave de clasificación extendidas

La razón por la que lo que quiere hacer no funciona es por el orden lógico de las operaciones en SQL , que, para su primera consulta, es (simplificado):

  • FROM MonitoringJob
  • SELECT Category, CreationDatees decir, agregue una columna de clave de clasificación extendida
  • ORDER BY CreationDate DESC
  • SELECT Categoryes decir, elimine la columna de clave de clasificación extendida nuevamente del resultado.

Por lo tanto, gracias a la función de columna de clave de ordenación extendida estándar de SQL , es totalmente posible ordenar por algo que no está en la SELECTcláusula, porque se está agregando temporalmente detrás de escena.

Entonces, ¿por qué no funciona esto DISTINCT?

Si sumamos la DISTINCToperación, se sumaría entre SELECTy ORDER BY:

  • FROM MonitoringJob
  • SELECT Category, CreationDate
  • DISTINCT
  • ORDER BY CreationDate DESC
  • SELECT Category

Pero ahora, con la columna de clave de ordenación extendida CreationDate , DISTINCTse ha cambiado la semántica de la operación, por lo que el resultado ya no será el mismo. Esto no es lo que queremos, por lo que tanto el estándar SQL como todas las bases de datos razonables prohíben este uso.

Soluciones alternativas

Se puede emular con la sintaxis estándar de la siguiente manera

SELECT Category
FROM (
  SELECT Category, MAX(CreationDate) AS CreationDate
  FROM MonitoringJob
  GROUP BY Category
) t
ORDER BY CreationDate DESC

O simplemente (en este caso), como también lo muestra Prutswonder

SELECT Category, MAX(CreationDate) AS CreationDate
FROM MonitoringJob
GROUP BY Category
ORDER BY CreationDate DESC

He escrito en un blog sobre SQL DISTINCT y ORDER BY más en detalle aquí .


1
Creo que está equivocado con cómo DISTINCT ONfunciona y bastante seguro de que no ayuda aquí. La expresión entre paréntesis es lo que se utiliza para determinar la distinción (la condición de agrupación). Si hay diferentes categorías con lo mismo CreationDate, ¡solo una de ellas aparecerá en el resultado! Como me preguntaba si tal vez estaba equivocado de alguna manera, también cargué la base de datos de ejemplo en la publicación de su blog para verificarla: la DISTINCT ONconsulta que dio allí produjo un total de 1000 resultados (con muchos duplicados length) mientras que la consulta a continuación dio solo 140 valores (únicos).
Inkling

@Inkling: Gracias por tu tiempo. El OP quiere explícitamente que se eliminen los "duplicados". Vea la redacción de OP "pero quiero que se eliminen los duplicados, así" . Probablemente cometió un error al copiar las consultas de mi publicación de blog. Hay dos consultas, una que usa DISTINCT(no ON) y otra que usa DISTINCT ON. Tenga en cuenta que este último no elimina explícitamente las longitudes duplicadas, sino los títulos duplicados. Creo que mi respuesta aquí es completamente correcta.
Lukas Eder

1
Mi punto es que sus DISTINCT ONcondiciones están eliminando duplicados usando la condición incorrecta. En la publicación de su blog, la DISTINCT ONconsulta elimina los títulos duplicados , sin embargo, la DISTINCTconsulta que está encima y la que se encuentra debajo (para la que afirma que es "azúcar sintáctico") eliminan las longitudes duplicadas , ya que presumiblemente ese es el objetivo. Lo mismo se aplica aquí: el OP quiere que se eliminen las Categorías duplicadas , no las CreationDates duplicadas como lo hace la DISTINCT ONconsulta. Si aún no me cree, pruébelo usted mismo.
Inkling

6

Si no se desea la salida de MAX (CreationDate), como en el ejemplo de la pregunta original, la única respuesta es la segunda declaración de la respuesta de Prashant Gupta:

SELECT [Category] FROM [MonitoringJob] 
GROUP BY [Category] ORDER BY MAX([CreationDate]) DESC

Explicación: no puede usar la cláusula ORDER BY en una función en línea, por lo que la declaración en la respuesta de Prutswonder no se puede usar en este caso, no puede poner una selección externa alrededor y descartar la parte MAX (CreationDate).


2

Simplemente use este código, si desea valores de las columnas [Categoría] y [Fecha de creación]

SELECT [Category], MAX([CreationDate]) FROM [MonitoringJob] 
             GROUP BY [Category] ORDER BY MAX([CreationDate]) DESC

O use este código, si solo desea valores de la columna [Categoría].

SELECT [Category] FROM [MonitoringJob] 
GROUP BY [Category] ORDER BY MAX([CreationDate]) DESC

Tendrás todos los registros distintos que quieras.


esas llaves [] son ​​totalmente confusas ... ¿es esta sintaxis SQL válida?
m13r

1
Los corchetes son para palabras clave de escape, como Orden, evento, etc., por lo que si tiene (por ejemplo) una columna en su tabla llamada Event, puede escribir en [Event]lugar de Eventevitar que SQL arroje un error de análisis.
Ben Maxfield

1

2) Ordenar por CreationDate es muy importante

Los resultados originales indicaron que "test3" tenía varios resultados ...

Es muy fácil comenzar a usar MAX todo el tiempo para eliminar duplicados en Group By's ... y olvidar o ignorar cuál es la pregunta subyacente ...

El OP presumiblemente se dio cuenta de que usar MAX le estaba dando el último "creado" y usar MIN daría el primer "creado" ...


3
Esto realmente no parece responder a la pregunta, parece ser un comentario sobre los usos de otros respondedores MAX, en lugar de algo que sea independiente como respuesta a la pregunta.
DaveyDaveDave

0
if object_id ('tempdb..#tempreport') is not null
begin  
drop table #tempreport
end 
create table #tempreport (
Category  nvarchar(510),
CreationDate smallint )
insert into #tempreport 
select distinct Category from MonitoringJob (nolock) 
select * from #tempreport  ORDER BY CreationDate DESC

0

Por subconsulta, debería funcionar:

    SELECT distinct(Category) from MonitoringJob  where Category in(select Category from MonitoringJob order by CreationDate desc);

Ummm ... no creo que lo haga. La selección externa no está ordenada.
Hossam El-Deen

no funcionará, estoy aquí porque esto no funciona
Amirreza

-1

Distinct clasificará los registros en orden ascendente. Si desea ordenar en orden desc, use:

SELECT DISTINCT Category
FROM MonitoringJob
ORDER BY Category DESC

Si desea ordenar los registros según el campo CreationDate, este campo debe estar en la declaración de selección:

SELECT DISTINCT Category, creationDate
FROM MonitoringJob
ORDER BY CreationDate DESC

12
Esto se ejecutará pero no dará lo que necesita el OP. El OP quiere Categorías distintas, no combinaciones distintas de Categoría y CreateDate. Este código puede generar varias instancias de la misma categoría, cada una con diferentes valores CreationDate.
MatBailie

-1

Puede utilizar CTE:

WITH DistinctMonitoringJob AS (
    SELECT DISTINCT Category Distinct_Category FROM MonitoringJob 
)

SELECT Distinct_Category 
FROM DistinctMonitoringJob 
ORDER BY Distinct_Category DESC

-3

Intente a continuación, pero no es útil para datos enormes ...

SELECT DISTINCT Cat FROM (
  SELECT Category as Cat FROM MonitoringJob ORDER BY CreationDate DESC
);

4
"La cláusula ORDER BY no es válida en vistas, funciones en línea, tablas derivadas, subconsultas y expresiones de tabla comunes, a menos que también se especifique TOP o FOR XML".
TechplexEngineer

Esto no funciona porque no especificó la columna CreationDate en el pedido por.
Mauro Bilotti

1
@TechplexEngineer Su comentario es incorrecto. El uso ORDER BYen subconsultas es absolutamente válido. Y alguien incluso votó a favor de tu comentario incorrecto.
Racil Hilan

Estoy intentando esto y tengo el mismo error con @TechplexEngineer. Estoy usando un pedido personalizado con estuche cuando.
Ege Bayrak

-4

Se puede hacer usando una consulta interna como esta

$query = "SELECT * 
            FROM (SELECT Category  
                FROM currency_rates                 
                ORDER BY id DESC) as rows               
            GROUP BY currency";

-5
SELECT DISTINCT Category FROM MonitoringJob ORDER BY Category ASC

2
¡Lo necesito ordenado por fecha de creación! es muy importante
rr

Entonces, ¿es imposible agregar la columna que desea ordenar usted mismo? Su ejemplo mostró entradas ordenadas alfabéticamente. Si necesita ordenar por fecha de creación, simplemente agréguelo. Realmente no es tan difícil.
Furicane

8
-1: El OP intentó eso, no funcionó, porque es imposible y aparentemente ignoraste ese hecho cuando patrocinabas el OP. El punto es que el operador DISTINCT recopilará varios registros con el mismo valor de Categoría, cada uno con fechas de creación potencialmente diferentes. Por tanto, es lógicamente imposible cuando se utiliza DISTINCT. Esto empuja la lógica requerida a GROUP BY en lugar de DISTINCT, permitiendo un agregado (MAX) en la fecha de creación.
MatBailie

En realidad, si observa más de cerca lo que hizo el OP, que es SQL absolutamente mal formado, no había cometido un solo error y el resultado dado corresponde al que solicitó. No me molestaré en -1, solo lea la próxima vez antes de corregir a las personas. Gracias.
Furicane

8
Sugiere directamente agregar el campo CreationDate, incluso diciendo "realmente no es tan difícil". Si lo hace, se produce el SQL mal formado. Obtuvo -1 por patrocinar el OP, dar un consejo que lleva al OP a la declaración que publicó originalmente y no notar la disputa entre DISTINCT y ordenar por un campo que no está en DISTINCT. Además, 'b' viene antes de 't' y '1' viene antes de '4', por lo que los resultados dados por el OP no están categóricamente en orden alfabético. Entonces, ¿puedo sugerir su propio consejo: lea (con más atención) la próxima vez.
MatBailie
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.