我有一个包含不同类型度量的表,使用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中。
答案 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