在不同时间计算具有特定标志的项目的状态

时间:2014-06-17 23:41:33

标签: sql sql-server tsql

我有可以标记时间范围状态的项目。在每一行中,我都有一个带标志的项目的开始和停止时间。

例如:

start   stop    itemid  flag
1-Jan   1-Feb   1       a
1-Feb   1-Mar   1       b
1-Feb   1-Mar   2       a
1-Jan   1-Mar   3       a
1-Jan   null    4       a

我需要的是一个计数的子计数。也就是说,对于给定的两个日期(例如1-Jan1-Mar),我需要计算在第一个日期标记a但不标记a的项目数在第二次约会。 (还有其他一些因素,其中包括a而非 - a的其他3种组合。)

我还需要在任何一个日期(但不是两个)以某种方式解释没有标志,但是现在我可以假设没有标志是b

基本上,我需要计算以下情况:(a,a),(a,b),(a,null),(b,a),(b,b),(b,null); for(x,y),其中x是第一个日期的每个项目的标志,y是第二个日期的标志。

现有的,我可以计算一个日期存在多少个标记ab

select count(1)
from table
where start <= '2014-02-15'
  and (stop >= '2014-02-15' or stop is null)
  and flag = a

2 个答案:

答案 0 :(得分:1)

这应该可以帮到你。

请注意,我将“stop&gt; ='2014-02-15'”更改为“stop&gt;'2014-02-15'”。

您需要确定“停止”日期是否在该间隔内。我假设不是因为你在项目1的开始和停止都有“1月2日”。否则项目1在1月2日的状态a和b都有。

select sum(case when d1.flag='a' and d2.flag='a' then 1 else 0 end) AA
    ,sum(case when d1.flag='a' and d2.flag='b' then 1 else 0 end) AB
    ,sum(case when d1.flag='a' and d2.flag is null then 1 else 0 end) Anull
    ,sum(case when d1.flag='b' and d2.flag='a' then 1 else 0 end) BA
    ,sum(case when d1.flag='b' and d2.flag='b' then 1 else 0 end) BB
    ,sum(case when d1.flag='b' and d2.flag is null then 1 else 0 end) Bnull
from 
(
    select *
    from table
    where start <= '2014-01-15'
      and (stop > '2014-01-15' or stop is null)
      and flag = 'a'
) d1
left join (
    select *
    from table
    where start <= '2014-02-15'
      and (stop > '2014-02-15' or stop is null)
      and flag = 'a'
) d2 on d1.itemid = d2.itemid

答案 1 :(得分:1)

这可能会或可能不会比其他答案更好。虽然它不使用自联接,但它使用两次分组:子选择中的显式分组和PIVOT中的隐式分组。所以,在这一点上,我提供这个解决方案只是你尝试的另一个选择,因为另一个选项不适合你,according to your comment

SELECT *
FROM (
  SELECT
    itemid,
    S = ISNULL(MAX(CASE WHEN start <= @d1 AND (@d1 < stop OR stop IS NULL) THEN flag END), '_')
      + ISNULL(MAX(CASE WHEN start <= @d2 AND (@d2 < stop OR stop IS NULL) THEN flag END), '_')
  FROM @table
  WHERE start <= @d1 AND (@d1 < stop OR stop IS NULL)
     OR start <= @d2 AND (@d2 < stop OR stop IS NULL)
  GROUP BY
    itemid
) AS s
PIVOT (COUNT(itemid) FOR S IN (aa, ab, a_, ba, bb, b_)) AS p
;

@d1@d2是您参数化的日期。

子选择查找具有与至少一个日期参数匹配的数据的itemid,然后确定每个itemid在任一日期具有的状态,标记缺少具有下划线的状态。然后,它将两个状态组合成一个字符串值,作为列S返回。因此,如果第一个日期的状态'a'和另一个的状态相同,则生成的字符串将为'aa',如果是另一个示例,则第一个日期为'b',第二个日期没有数据,S将为'b_',依此类推。

然后对结果集进行透视和聚合,S列为透视结果提供列名称。请注意,派生表还可能返回字符串'_a''_b'。如果您决定将它们包含在PIVOT列列表中,那么它们也可能会得到非零结果。

相关问题