web-dev-qa-db-fra.com

Sélectionnez une colonne dans SQL pas dans Grouper par

J'ai essayé de trouver des informations sur la manière de sélectionner une colonne non agrégée qui ne figure pas dans l'instruction Group By en SQL, mais rien de ce que j'ai trouvé jusqu'à présent ne semble répondre à ma question. J'ai une table avec trois colonnes que je veux en tirer. L'une est une date de création, l'autre est un ID qui regroupe les enregistrements en fonction d'un ID de revendication particulier et la dernière est la PK. Je souhaite rechercher l’enregistrement qui a la date de création maximale dans chaque groupe d’ID de revendication. Je sélectionne le MAX (date de création), l'ID de revendication (cpe.fmgcms_cpeclaimid) et le regroupement par l'ID de revendication. Mais j'ai besoin du PK de ces enregistrements (cpe.fmgcms_claimid), et si j'essaie de l'ajouter à ma clause select, j'obtiens une erreur. Et je ne peux pas l'ajouter à mon article groupe par article, car cela annulera le regroupement auquel il est destiné. Est-ce que quelqu'un connaît des solutions de contournement pour cela? Voici un exemple de mon code:

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

Voici le résultat que j'aimerais obtenir:

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
44
user1603734

Les colonnes du jeu de résultats d’une requête select avec group by La clause doit être:

  • une expression utilisée comme l'un des group by critères, ou ...
  • une fonction d'agrégat, ou ...
  • une valeur littérale

Donc, vous ne pouvez pas faire ce que vous voulez faire dans une requête simple et simple. La première chose à faire est d’énoncer clairement l’énoncé de votre problème, par exemple:

Je souhaite trouver la ligne de revendication individuelle portant la date de création la plus récente dans chaque groupe de mon tableau de revendications.

Donné

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 ) ,

)

La première chose à faire est d’identifier la date de création la plus récente pour chaque groupe:

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

Cela vous donne les critères de sélection dont vous avez besoin (1 ligne par groupe, avec 2 colonnes: ID_groupe et la date de création haute heure) pour répondre à la 1ère partie de l'exigence (sélection de la ligne individuelle dans chaque groupe. Il doit s'agir d'une table virtuelle dans votre dernière requête select:

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 table n'est pas unique par date_created dans les group_id _ (AK02), vous pouvez obtenir des lignes en double pour un groupe donné.

37
Nicholas Carey

Vous pouvez le faire avec PARTITION et 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
17
RedFilter

La réponse directe est que vous ne pouvez pas. Vous devez sélectionner un agrégat ou un élément que vous regroupez.

Donc, vous avez besoin d'une approche alternative.

1). Prenez votre requête actuelle et joignez les données de base dessus

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

2) Utilisez un CTE pour tout faire en une fois ...

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

REMARQUE: L'utilisation de ROW_NUMBER() ne garantit qu'un seul enregistrement par fmgcms_cpeclaimid. Même si plusieurs enregistrements sont liés avec exactement la même valeur createdon. Si vous pouvez avoir des liens et que vous voulez que tous les enregistrements aient la même valeur createdon, utilisez plutôt RANK().

8
MatBailie

Vous pouvez join la table sur elle-même pour obtenir le 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'
3
Taryn

Ce que vous demandez, Monsieur, est la réponse de RedFilter. Cette réponse aide également à comprendre pourquoi group by est en quelque sorte une version ou partition plus simple: SQL Server: Différence entre PARTITION BY et GROUP BY puisqu’elle modifie le mode de calcul de la valeur renvoyée. (en quelque sorte) renvoient groupe de colonnes par ne peut pas retourner.

1
Eyad Ebrahim