2012-08-16 18 views
36

He estado tratando de encontrar información sobre cómo seleccionar una columna no agregada que no está contenida en la declaración Agrupar por en SQL, pero nada de lo que he encontrado hasta ahora parece para responder mi pregunta Tengo una tabla con tres columnas que quiero de ella. Una es una fecha de creación, una es una identificación que agrupa los registros por una ID de reclamación en particular, y la final es la PK. Quiero encontrar el registro que tiene la fecha de creación máxima en cada grupo de ID de reclamo. Estoy seleccionando el MAX (fecha de creación) y el ID de reclamo (cpe.fmgcms_cpeclaimid) y agrupando por el ID de reclamo. Pero necesito el PK de estos registros (cpe.fmgcms_claimid), y si intento agregarlo a mi cláusula de selección, aparece un error. Y no puedo agregarlo a mi grupo por cláusula porque arrojará mi agrupación prevista. ¿Alguien sabe alguna solución para esto? Aquí está una muestra de mi código:Seleccionar una columna en SQL no en el grupo Por

Select MAX(cpe.createdon) As MaxDate, cpe.fmgcms_cpeclaimid 
from Filteredfmgcms_claimpaymentestimate cpe 
where cpe.createdon < 'reportstartdate' 
group by cpe.fmgcms_cpeclaimid 

Este es el resultado que me gustaría conseguir:

Select MAX(cpe.createdon) As MaxDate, cpe.fmgcms_cpeclaimid, cpe.fmgcms_claimid 
from Filteredfmgcms_claimpaymentestimate cpe 
where cpe.createdon < 'reportstartdate' 
group by cpe.fmgcms_cpeclaimid 

Respuesta

15

Usted puede hacer esto con PARTITION y RANK:

select * from 
(
    select MyPK, fmgcms_cpeclaimid, createdon, 
     Rank() over (Partition BY fmgcms_cpeclaimid order by createdon DESC) as Rank 
    from Filteredfmgcms_claimpaymentestimate 
    where createdon < 'reportstartdate' 
) tmp 
where Rank = 1 
3

Usted puede join la tabla en sí mismo para obtener el PK:

Select cpe1.PK, cpe2.MaxDate, cpe1.fmgcms_cpeclaimid 
from Filteredfmgcms_claimpaymentestimate cpe1 
INNER JOIN 
(
    select MAX(createdon) As MaxDate, fmgcms_cpeclaimid 
    from Filteredfmgcms_claimpaymentestimate 
    group by fmgcms_cpeclaimid 
) cpe2 
    on cpe1.fmgcms_cpeclaimid = cpe2.fmgcms_cpeclaimid 
    and cpe1.createdon = cpe2.MaxDate 
where cpe1.createdon < 'reportstartdate' 
8

La respuesta directa es que no se puede. Usted debe seleccione un agregado o algo por lo que usted está agrupando.

Por lo tanto, necesita un enfoque alternativo.

1). Tome la consulta actual y vuelva a unir los datos base

SELECT 
    cpe.* 
FROM 
    Filteredfmgcms_claimpaymentestimate cpe 
INNER JOIN 
    (yourQuery) AS lookup 
    ON lookup.MaxData   = cpe.createdOn 
    AND lookup.fmgcms_cpeclaimid = cpe.fmgcms_cpeclaimid 

2). Use un CTE de hacerlo todo de una sola vez ...

WITH 
    sequenced_data AS 
(
    SELECT 
    *, 
    ROW_NUMBER() OVER (PARITION BY fmgcms_cpeclaimid ORDER BY CreatedOn DESC) AS sequence_id 
    FROM 
    Filteredfmgcms_claimpaymentestimate 
    WHERE 
    createdon < 'reportstartdate' 
) 
SELECT 
    * 
FROM 
    sequenced_data 
WHERE 
    sequence_id = 1 

NOTA: El uso de ROW_NUMBER() asegurará un solo registro por fmgcms_cpeclaimid. Incluso si varios registros están vinculados con el mismo valor exacto createdon. Si puede tener vínculos y desea todos los registros con el mismo valor createdon, use RANK().

32

Las columnas del conjunto de resultados de una consulta con selectgroup by cláusula deben ser:

  • una expresión utilizada como uno de los criterios group by, o ...
  • una función agregada, o .. .
  • un valor literal

por lo tanto, no se puede hacer lo que quiere hacer en una sola consulta, simple.Lo primero que debe hacer es indicar su planteamiento del problema de una manera clara, algo así como:

Quiero encontrar la fila reclamación individual que lleva la fecha más reciente de creación dentro de cada grupo en mi mesa de reclamaciones

Dado

create table dbo.some_claims_table 
(
    claim_id  int  not null , 
    group_id  int  not null , 
    date_created datetime not null , 

    constraint some_table_PK primary key (claim_id    ) , 
    constraint some_table_AK01 unique (group_id , claim_id ) , 
    constraint some_Table_AK02 unique (group_id , date_created) , 

) 

el primero que hay que hacer es identificar la fecha más reciente creación para cada grupo:

select group_id , 
     date_created = max(date_created) 
from dbo.claims_table 
group by group_id 

Eso le da los criterios de selección que necesita (1 fila por grupo, con 2 columnas: group_id y la fecha alta creada) para completar la primera parte del requisito (seleccionando la fila individual de cada grupo. Eso tiene que ser una tabla virtual en su select consulta final:

select * 
from dbo.claims_table t 
join (select group_id , 
     date_created = max(date_created) 
     from dbo.claims_table 
     group by group_id 
    ) x on x.group_id  = t.group_id 
     and x.date_created = t.date_created 

Si la tabla no es única por date_created dentro group_id (AK02), que se puede obtener filas duplicadas para un grupo dado.

1

Lo que está preguntando, señor, es la respuesta de RedFilter. Esta respuesta también ayuda a entender por qué agrupar es de alguna manera una versión más simple o una partición sobre: ​​ SQL Server: Difference between PARTITION BY and GROUP BY ya que cambia la forma en que se calcula el valor devuelto y por lo tanto podría (de alguna manera) devolver columnas por grupo no puede devolver.

Cuestiones relacionadas