SQL - 查找组中最早和最新的非null值

时间:2014-07-21 20:29:21

标签: sql sql-server-2012

我需要在Group By语句中找到列的最早和最新(Non Null)值。

示例:

鲍勃在某一天有多个购买记录。我需要在当天的一组记录中找到Bob的第一次和最后一次购买。

  • Bob于2014年1月1日中午12点收购铅笔
  • Bob没有购买,但于2014年1月1日下午1:00办理了
  • 鲍勃于2014年1月1日下午2:00买了纸。

所以我有三条记录,一条是空值,表示没有购买。

我使用以下查询来检索所有员工记录,其中给定日期内有多个记录。

SELECT nameid, 
       Min(CONVERT(NVARCHAR(25), mdatetime, 10)) AS Date, 
       Count(*)                                  AS Duplicates 
       -- <<<Get Earliest Purchase And Latest Purchase From each group Where Not Null>>>
FROM   employee 
GROUP  BY nameid,  CONVERT(NVARCHAR(25), mdatetime, 111) 
HAVING Count(*) > 1 

如果我只是使用MIN(mDateTime)检索最早的日期,则该值可能为null。我需要最早的非空值和每个分组的最新非空值。

感谢您的指导和耐心。

警告:这是我正在编辑的代码的假设再现。场景,命名约定和完整性缩写为简化和突出问题。

2 个答案:

答案 0 :(得分:1)

在所有评论之后,答案是:

考虑这个构建方案:

create table employee  (nameid varchar(100), mdatetime datetime, purchase varchar(200))
insert into employee values ('Bob', '2014/01/01 12:00pm', 'books')
insert into employee values ('Bob', '2014/01/01 01:00pm', NULL)
insert into employee values ('Bob', '2014/01/01 02:00pm', 'pencil')

将获得第一次和最后一次无空购买并选择购买字段的查询是:

SELECT A.nameid, A.Date, A.MIN_DATE, B.purchase MIN_PURCHASE, A.MAX_DATE, C.PURCHASE MAX_PURCHASE
FROM (
  SELECT nameid, 
   CONVERT(NVARCHAR(25), mdatetime, 10) AS Date, 
   Min(case when purchase is null then null else mDateTime end) MIN_DATE,
   Max(case when purchase is null then null else mDateTime end) MAX_DATE,
   Count(*) AS Duplicates 
 FROM   employee A
 GROUP  BY nameid,  CONVERT(NVARCHAR(25), mdatetime, 10) 
 HAVING Count(*) > 1 
) A
INNER JOIN employee B
  on A.nameid = B.nameid
  and A.MIN_DATE = B.mdatetime
INNER JOIN employee C
  on A.nameid = C.nameid
  and A.MAX_DATE = C.mdatetime

查看SQL Fiddle

答案 1 :(得分:1)

SELECT nameid,
       CONVERT(NVARCHAR(25), mdatetime, 10) AS dt,
       min(case when purchase is not null then mdatetime else null end) as first_purch,
       max(case when purchase is not null then mdatetime else null end) as last_purch
  FROM employee
 GROUP BY nameid, CONVERT(NVARCHAR(25), mdatetime, 10)
having sum(case when purchase is not null then 1 else 0 end) > 1

如果您还想购买已购买的商品(包括第一个和最后一个),您可以运行以下内容:

with sub as(
SELECT nameid,
       CONVERT(NVARCHAR(25), mdatetime, 10) AS dt,
       min(case when purchase is not null then mdatetime else null end) as first_purch,
       max(case when purchase is not null then mdatetime else null end) as last_purch
  FROM employee
 GROUP BY nameid, CONVERT(NVARCHAR(25), mdatetime, 10)
having sum(case when purchase is not null then 1 else 0 end) > 1
)
select  s.nameid,
        s.dt,
        s.first_purch,
        f.purchase as first_purch_item,
        s.last_purch,
        l.purchase as last_purch_item
from sub s join employee f on s.nameid = f.nameid and s.first_purch = f.mdatetime
           join employee l on s.nameid = l.nameid and s.last_purch = l.mdatetime