我有一个查询,可以在其中提取数据并将其显示在折线图中。我在演示时遇到麻烦,因为我希望每n分钟将结果分组一次(在我的示例中为5)。
我希望我的结果集在每n:th分钟包括一行,即使在给定的n:th分钟没有点击。
我面临的另一个问题是在仅拥有只读权限的连接上工作。
我尝试阅读有关如何解决问题的各种建议,但大多数似乎都建议在每n:th分钟作为一个表加入一个额外的时间表,或者包括一个服务器端功能。 我无法利用这些特殊建议,因为我无法向数据库添加函数和/或表。
非常感谢您提供有关解决此问题的建议。 -乔纳斯(Jonas)
SELECT
CONVERT(varchar,DATEADD(MINUTE, DATEDIFF(MINUTE, 0, P.[TIME])/5 * 5,0), 120),
SUM(P.[AMOUNT]),
P.[Q],
FROM
(SELECT
MessageType AS [Q],
Handled AS [TIME],
count(Handled) AS [AMOUNT]
FROM dbo.CosMessage
WHERE MessageType IN('Z03', 'Z04', 'Z05')
GROUP BY Handled, MessageType) AS P
GROUP BY DATEADD(MINUTE, DATEDIFF(MINUTE, 0, P.[TIME])/5 * 5,0), P.[Q]
我当前的结果集如下:
2019-07-02 10:45 2 Z03
2019-07-02 10:45 2 Z04
2019-07-02 10:45 2 Z05
2019-07-02 10:50 7 Z03
2019-07-02 10:50 24 Z04
2019-07-02 10:50 2 Z05
2019-07-02 11:20 1 Z05
我希望我的结果按以下顺序排序:
2019-07-02 10:45 2 Z03
2019-07-02 10:45 2 Z04
2019-07-02 10:45 2 Z05
2019-07-02 10:50 7 Z03
2019-07-02 10:50 24 Z04
2019-07-02 10:50 2 Z05
2019-07-02 10:55 0 Z03
2019-07-02 10:55 0 Z04
2019-07-02 10:55 0 Z05
…
2019-07-02 11:20 0 Z03
2019-07-02 11:20 0 Z04
2019-07-02 11:20 1 Z05
答案 0 :(得分:1)
根据我的评论,我们需要生成一些日期行。为此最好使用数字表,但我假设您没有一个:
WITH dg (d) AS (
SELECT CONVERT(datetime, '2019-07-02 10:45:00', 120) AS d
UNION ALL
SELECT dateadd(minute, 5, a.d) as d
FROM dg a
WHERE a.d < CONVERT(datetime, '2019-07-02 11:20:01', 120)
)
从中进行选择将生成1045和1120之间相隔5分钟的日期列表
接下来,我们需要将其与一些值交叉连接以获取Z值;
SELECT * FROM
dg
CROSS JOIN
(SELECT 'Z03' as z UNION ALL SELECT 'Z04' UNION ALL SELECT 'Z05') z
这将每三次重复一次,并与每个不同的Z匹配,所以现在我们只需要将我们的真实数据连接到上面:
SELECT dg.d, z.z, COUNT(m.MessageType) as c FROM
dg
CROSS JOIN
(SELECT 'Z03' as z UNION ALL SELECT 'Z04' UNION ALL SELECT 'Z05') z
LEFT JOIN dbo.CosMessage m
ON
z.z = m.MessageType AND
m.Handled >= dg.d AND
m.Handled < DATEADD(minute, 5, dg.d)
GROUP BY
dg.d, z.z
您的原始查询需要花一些时间将时间四舍五入到最接近的5分钟。我们可以通过使sqlserver根据实际时间所属的时间范围进行连接来避免这种情况-10:46的时间属于10:45 to 10:45+5
范围。 z.z = m.messagetype
上的匹配将仅限于z3到z5。最后,如果没有匹配的记录,这是左联接,因此dg.d和zz的值是vale,但是m.messagetype将为null,count不计为null,因此对于这些行将返回零:>
dg.d z.z m.handled m.messagetype
2019-07-02 10:50 Z05 2019-07-02 10:51 Z05 --it will count as 2 when grouped
2019-07-02 10:50 Z05 2019-07-02 10:52 Z05 --it will count as 2 when grouped
2019-07-02 10:55 Z03 null null --it will count as 0 when grouped
了解如何将10:51和10:52分配给10:50时隙。当我们仅将dg.d和z.z分组时,这些在该插槽中将计为2,而空行将计为0
要在更多操作中查看最终查询,请删除group by
并将其设为select *
不要忘记,您需要从此答案的顶部开始组合WITH和SELECT;您不能单独运行SELECT,因为它需要在开始时定义的CTE,但是为了清楚起见,我没有在最终查询中重复使用WITH
答案 1 :(得分:0)
是可以的,但有点复杂。您应该在分组之前修改日期。在您的示例中,您需要每5分钟记录一次。因此,将分钟的最后一位数字更改为0或5。您可以通过将模数设为DATEADD(MINUTE, (DATEPART(MINUTE, your_date) % 5) * -1, your_date)
来实现。进行此更改后,将该计算的格式设置为FORMAT(DATEADD(MINUTE, (DATEPART(MINUTE, your_date) % 5) * -1, your_date), 'yyyyMMddhhmm')
。现在,您可以按此值分组。
SELECT FORMAT(DATEADD(MINUTE, (DATEPART(MINUTE, your_date) % 5) * -1, your_date), 'yyyyMMddhhmm'), COUNT(*)
FROM your_table
GROUP BY FORMAT(DATEADD(MINUTE, (DATEPART(MINUTE, your_date) % 5) * -1, your_date), 'yyyyMMddhhmm')