在SQL中选择一个不在Group By中的列

时间:2012-08-16 15:54:38

标签: sql sql-server-2008 tsql greatest-n-per-group

我一直试图找到一些关于如何选择SQL中Group By语句中未包含的非聚合列的信息,但到目前为止我找不到的任何内容似乎都回答了我的问题。我有一张桌子,上面有三列,我想要它。一个是创建日期,一个是通过特定声明ID对记录进行分组的ID,最后一个是PK。我想在每组声明ID中找到具有最大创建日期的记录。我选择MAX(创建日期)和Claim ID(cpe.fmgcms_cpeclaimid),并按照声明ID进行分组。但是我需要来自这些记录的PK(cpe.fmgcms_claimid),如果我尝试将它添加到我的select子句中,我会收到错误。而且我不能将它添加到我的group by子句中,因为它会抛弃我想要的分组。有谁知道这方面的任何变通办法?以下是我的代码示例:

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

这是我想得到的结果:

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

7 个答案:

答案 0 :(得分:36)

具有select子句的group by查询的结果集中的列必须为:

  • 用作group by条件之一的表达式,或......
  • 聚合函数,或者......
  • 字面值

因此,您无法在一个简单的查询中执行您想要执行的操作。首先要做的是以明确的方式陈述您的问题陈述,例如:

  

我想找到最新的个人索赔行   我的索赔表中每个组内的创建日期

鉴于

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

)

首先要确定每个组的最新创建日期:

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

这为您提供了所需的选择标准(每组1行,有2列:group_id和高水位创建日期)以满足要求的第1部分(从每个组中选择单独的行。这需要是最终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

如果date_created({02}}中的group_id表不是唯一的,您可以获得给定组的重复行。

答案 1 :(得分:17)

您可以使用PARTITIONRANK

执行此操作
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

答案 2 :(得分:8)

直接的答案是你做不到。您 必须 选择聚合或您要分组的内容。

所以,你需要一种替代方法。

1)。带上当前查询并将基础数据加入其中

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

2)。使用CTE一次完成所有操作......

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

注意:使用ROW_NUMBER()将确保每fmgcms_cpeclaimid只有一条记录。即使多个记录与完全相同的createdon值相关联。如果您可以拥有关系,并希望所有具有相同createdon值的记录,请改用RANK()

答案 3 :(得分:3)

你可以join自己的表来获得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'

答案 4 :(得分:1)

主席先生,您所问的是RedFilter的答案。 这个答案也有助于理解为什么group by以某种方式更简单的版本或分区:     SQL Server: Difference between PARTITION BY and GROUP BY 因为它改变了计算返回值的方式,因此你可以(以某种方式)返回列组,不能返回。

答案 5 :(得分:0)

我想做的是将附加列包装在聚合函数中,例如max()。 当您不希望重复的值时,它会非常好用。

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

答案 6 :(得分:-1)

您可以按以下方式使用

Select X.a, X.b, Y.c from (
                Select X.a as a, sum (b) as sum_b from name_table X
                group by X.a)X
left join from name_table Y on Y.a = X.a

示例;

CREATE TABLE #products (
    product_name VARCHAR(MAX),
    code varchar(3),
    list_price [numeric](8, 2) NOT NULL
);

INSERT INTO #products VALUES ('paku', 'ACE', 2000)
INSERT INTO #products VALUES ('paku', 'ACE', 2000)
INSERT INTO #products VALUES ('Dinding', 'ADE', 2000)
INSERT INTO #products VALUES ('Kaca', 'AKB', 2000)
INSERT INTO #products VALUES ('paku', 'ACE', 2000)

--SELECT * FROM #products 
SELECT distinct x.code, x.SUM_PRICE, product_name FROM (SELECT code, SUM(list_price) as SUM_PRICE From #products 
               group by code)x
left join #products y on y.code=x.code

DROP TABLE #products