如果为空,则按顺序检索不同的值

时间:2013-05-22 09:28:39

标签: sql sql-server-2005

我有一个包含不同类型度量的表,使用id_measure_type来识别它们。我需要做一个SELECT,在其中我检索所有求和的时间段,每个单位(id_unit)butif某个度量为空检索另一个等等。

措施是按日期,单位和小时。这是我的表的摘要:

id_unit     dateBid     hour    id_measure_type     measure
252         05/22/2013  11      6                   500
252         05/22/2013  11      4                   250
252         05/22/2013  11      1                   300
107         05/22/2013  11      4                   773
107         05/22/2013  11      1                   500
24          05/22/2013  11      6                   0
24          05/22/2013  11      4                   549
24          05/22/2013  11      1                   150

我需要一个选项,为所有输入数据范围设置SUM并按此顺序获取“最佳”度量类型:首先是id_measure_type = 6,如果为空或0 然后是id_measure_type = 4,并且条件相同,然后是id_measure_type = 1,如果没有则为0。

只要存在类型6的每个度量值,此选择都是正确的:

SELECT id_unit, SUM(measure) AS measure
FROM UNIT_MEASURES
WHERE dateBid BETWEEN '03/23/2013' AND '03/24/2013' AND id_unit IN (325, 326) 
AND id_measure_type = 6 GROUP BY id_unit

输入是日期和单位的范围。有一种方法可以在一个选择中完成吗?

修改
我还有一个calendar表,其中包含每个日期和小时,因此可以在必要时用它来连接它(以检索每一小时)。

修改
这些值永远不会是NULL,当“空或0”时,我的意思是0或缺少一小时的值。我需要从“最佳”可能的衡量标准中,每个可能的小时都在SUM中。

3 个答案:

答案 0 :(得分:1)

不确定我是否理解正确,但我认为这应该有效(改为你的表)

我的测试设置:

DECLARE @Table TABLE ([id_unit] INT, [dateBid] DATE, [hour] INT, [id_measure_type] INT, [measure] INT);

INSERT INTO @Table
    SELECT *
      FROM (
        VALUES (252, GETDATE(), 11, 6, 500)
             , (252, GETDATE(), 11, 4, 250)
             , (252, GETDATE(), 11, 1, 300)
             , (107, GETDATE(), 11, 4, 773)
             , (107, GETDATE(), 11, 1, 500)
         ) [Values]([id_unit], [dateBid], [hour], [id_measure_type], [measure]);

实际查询:

WITH [Filter] AS (
    SELECT *
         , DENSE_RANK() OVER(PARTITION BY [id_unit] ORDER BY [id_measure_type] DESC) [Rank]
      FROM @Table
     WHERE [measure] > 0
)
SELECT [id_unit], SUM([measure])
  FROM [Filter]
 WHERE [Rank] = 1
   AND [id_unit] IN (252, 107)
   AND [dateBid] BETWEEN CAST(GETDATE()-1 AS DATE) AND CAST(GETDATE() AS DATE)
 GROUP BY [id_unit];

SUM()之前的输出视图:

WITH [Filter] AS (
    SELECT *
         , DENSE_RANK() OVER(PARTITION BY [id_unit] ORDER BY [id_measure_type] DESC) [Rank]
      FROM @Table
     WHERE [measure] > 0
)
SELECT *
  FROM [Filter]
 WHERE [Rank] = 1
   AND [id_unit] IN (252, 107)
   AND [dateBid] BETWEEN CAST(GETDATE()-1 AS DATE) AND CAST(GETDATE() AS DATE);

编辑(每小时): 我不知道你是否在表格中有更多的数据,上面的示例总和只会(据我所知)只有SUM()一行,但它仍然有效,所以我会留下它。

WITH [Filter] AS (
    SELECT *
         , DENSE_RANK() OVER(PARTITION BY [id_unit], [Hour] ORDER BY [id_measure_type] DESC) [Rank]
      FROM @Table
     WHERE [measure] > 0
)
SELECT [id_unit], [Hour], SUM([measure])
  FROM [Filter]
 WHERE [Rank] = 1
   AND [id_unit] IN (252, 107)
   AND [dateBid] BETWEEN CAST(GETDATE()-1 AS DATE) AND CAST(GETDATE() AS DATE)
 GROUP BY [id_unit], [Hour];

答案 1 :(得分:0)

我不确定您的某些列是如何相关的,因为您提供的每个样本行都具有相同的值,并且measure没有0,但我认为您想要的是这些行:

;With Priorities as (
    select *,ROW_NUMBER() OVER (
         PARTITION BY id_unit,dateBid,hour
         ORDER BY CASE
             WHEN COALESCE(measure,0) > 0 THEN id_measure_type
             else -1 END desc) as priority
    from @t
)
select id_unit,SUM(measure)
from Priorities
where priority = 1
group by id_unit

假设没有id_measure_type小于0,并且没有measure小于0 - 如果这些是要求,可以对其进行调整。

(我添加了一个COALESCE,假设您的“空或0”要求实际上是在讨论NULL和0)

答案 2 :(得分:0)

Don answer完美无缺,但由于表格中有大量数据,因此选择时间超过3分钟。

我制作了自己的解决方案,它更大更丑,但速度更快(持续约1秒):

SELECT tUND.id_unit, ROUND(SUM(
    CASE WHEN ISNULL(t1.measure, 0) > 0 THEN t1.measure ELSE 
    CASE WHEN ISNULL(t2.measure, 0) > 0 THEN t2.measure ELSE
    CASE WHEN ISNULL(t3.measure, 0) > 0 THEN t3.measure ELSE 0 
    END END END END
/1000),3) AS myMeasure
FROM calendar
LEFT OUTER JOIN UNITS_TABLE tUND ON tUND.id_unit IN (252, 107)
LEFT OUTER JOIN MEASURES_TABLE t1 ON t1.id_measure_type = 6 
    AND t1.dateBid = dt AND t1.hour = h AND t1.id_uf = tUND.id_uf
LEFT OUTER JOIN MEASURES_TABLE t2 ON t2.id_unit = t1.id_unit 
    AND t2.dateBid = t1.dateBid AND t2.id_measure_type = 1 
    AND t2.id_unit = tUND.id_unit 
LEFT OUTER JOIN MEASURES_TABLE t3 ON tCNT.id_unit = tUFI.id_unit
    AND t3.dateBid = t1.dateBid AND t3.id_measure_type = 4 
    AND t3.id_unit = tUND.id_unit 
WHERE dt BETWEEN '03/23/2013' AND '03/24/2013' 
GROUP BY tUND.id_unit