SQL Server: solo la última entrada en GROUP BY
-
22-07-2019 - |
Pregunta
Tengo la siguiente tabla en MSSQL2005
id | business_key | result
1 | 1 | 0
2 | 1 | 1
3 | 2 | 1
4 | 3 | 1
5 | 4 | 1
6 | 4 | 0
Y ahora quiero agrupar basado en business_key que devuelve la entrada completa con la identificación más alta. Entonces mi resultado esperado es:
business_key | result
1 | 1
2 | 1
3 | 1
4 | 0
Apuesto a que hay una manera de lograrlo, simplemente no puedo verlo en este momento.
Solución
Una solución alternativa, que puede brindarle un mejor rendimiento (pruebe en ambos sentidos y verifique los planes de ejecución):
SELECT
T1.id,
T1.business_key,
T1.result
FROM
dbo.My_Table T1
LEFT OUTER JOIN dbo.My_Table T2 ON
T2.business_key = T1.business_key AND
T2.id > T1.id
WHERE
T2.id IS NULL
Esta consulta asume que el ID es un valor único (al menos para cualquier clave_empresarial) y que está establecido en NOT NULL.
Otros consejos
select
drv.business_key,
mytable.result
from mytable
inner join
(
select
business_key,
max(id) as max_id
from mytable
group by
business_key
) as drv on
mytable.id = drv.max_id
Prueba esto
select business_key,
result
from myTable
where id in
(select max(id)
from myTable
group by business_key)
EDITAR: creé la tabla para probar mi código. Lo incluyo a continuación en caso de que alguien más quiera probarlo.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[myTable](
[id] [int] NOT NULL,
[business_key] [int] NOT NULL,
[result] [int] NOT NULL
) ON [PRIMARY]
go
insert into myTable values(1,1,0);
insert into myTable values(2,1,1);
insert into myTable values(3,2,1);
insert into myTable values(4,3,1);
insert into myTable values(5,4,1);
insert into myTable values(6,4,0);
select * from mytable
select business_key,
result
from
(select id,
business_key,
result,
max(id) over (partition by business_key) as max_id
from mytable) x
where id = max_id
Esta es una publicación anterior pero era relevante para algo que estaba haciendo actualmente (2013). Si obtiene un conjunto de datos más grande (típico en la mayoría de los DB), el rendimiento de las diversas consultas (mirando los planes de ejecución) dice mucho. Primero creamos una tabla "TALLY" para generar números al azar, luego use una fórmula arbitraria para crear datos para el " MyTable " ;:
CREATE TABLE #myTable(
[id] [int] NOT NULL,
[business_key] [int] NOT NULL,
[result] [int] NOT NULL,
PRIMARY KEY (Id)
) ON [PRIMARY];
; WITH
-- Tally table Gen Tally Rows: X2 X3
t1 AS (SELECT 1 N UNION ALL SELECT 1 N), -- 4 , 8
t2 AS (SELECT 1 N FROM t1 x, t1 y), -- 16 , 64
t3 AS (SELECT 1 N FROM t2 x, t2 y), -- 256 , 4096
t4 AS (SELECT 1 N FROM t3 x, t3 y), -- 65536 , 16,777,216
t5 AS (SELECT 1 N FROM t4 x, t4 y), -- 4,294,967,296, A lot
Tally AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) N
FROM t5 x, t5 y)
INSERT INTO #MyTable
SELECT N, CAST(N/RAND(N/8) AS bigINT)/5 , N%2
FROM Tally
WHERE N < 500000
A continuación, ejecutamos tres tipos diferentes de consultas para revisar el rendimiento (active "Plan de ejecución real" si está utilizando SQL Server Management Studio):
SET STATISTICS IO ON
SET STATISTICS TIME ON
----- Try #1
select 'T1' AS Qry, id, business_key,
result
from #myTable
where id in
(select max(id)
from #myTable
group by business_key)
---- Try #2
select 'T2' AS Qry, id, business_key,
result
from
(select id,
business_key,
result,
max(id) over (partition by business_key) as max_id
from #mytable) x
where id = max_id
---- Try #3
;with cteRowNumber as (
select id,
business_key,
result,
row_number() over(partition by business_key order by id desc) as RowNum
from #mytable
)
SELECT 'T3' AS Qry, id, business_key,
result
FROM cteRowNumber
WHERE RowNum = 1
Limpieza:
IF OBJECT_ID(N'TempDB..#myTable',N'U') IS NOT NULL
DROP TABLE #myTable;
SET STATISTICS IO OFF
SET STATISTICS TIME OFF
Encontrará, mirando los planes de ejecución, " Pruebe 1 " tiene el mejor "Costo de consulta" y el tiempo de CPU más bajo pero '' Prueba 3 '' tiene la menor cantidad de lecturas y el tiempo de CPU no es tan malo. Recomendaría usar un método CTE para las lecturas menos