如何获得每天包含多个列的事件的第一个实例,包括日期时间并返回这些列加上完整的日期时间值?

Posted

技术标签:

【中文标题】如何获得每天包含多个列的事件的第一个实例,包括日期时间并返回这些列加上完整的日期时间值?【英文标题】:How can I get the first instance of an event per day with multiple columns including a datetime and return those columns plus the full datetime value? 【发布时间】:2019-04-17 01:07:37 【问题描述】:

我需要生成一个 SQL 脚本,该脚本将使用许多列提取不同的条目,其中之一是日期时间列。我只对每个事件的第一次出现感兴趣,并且查询需要跨越多天。该查询将针对一个非常大的数据库运行,并且可能会返回数十万个结果,如果不是数百万的话。因此,我也需要这个脚本尽可能高效。这最终将是一个在 s-s-rS 中运行以提取访问事务的脚本。

我尝试过使用 GROUP BY、DISTINCT、子查询、FIRST 等,但均未成功。我可以在网上找到的所有示例都没有 JOIN 语句或计算列,例如仅从日期时间字段中收集日期。

我已将以下脚本简化为仅拉一天一扇门,但结果将是多天一扇门。此代码返回我需要的数据,我不关心 COUNT,但我还需要以某种方式在我的结果集中获取 (DateAdd(minute,-(ServerLocaleOffset),ServerUTC)) 字段。问题是因为它一直到秒,它使所有记录都不同。

DECLARE @Begin datetime2 = '4/10/2019',
        @End datetime2 = '4/11/2019',
        @Door varchar(max) = 'Front Entrance'

SELECT
        CONVERT(VARCHAR(10), (DateAdd(minute,-(ServerLocaleOffset),ServerUTC)),101) AS 'Date'
        ,AJ.PrimaryObjectIdentity
        ,AJ.SecondaryObjectIdentity
        ,AJ.MessageType
        ,AJ.PrimaryObjectName
        ,AJ.SecondaryObjectName
        ,AP.Text13
        ,COUNT(*) AS 'Count'
FROM Access.JournalLogView AJ
LEFT OUTER JOIN Access.Personnel as AP on AP.GUID = AJ.PrimaryObjectIdentity
WHERE (MessageType like 'CardAdmitted' OR MessageType like 'CardRejected')
AND (DateAdd(minute,-(ServerLocaleOffset),ServerUTC)) BETWEEN @Begin AND @End
AND (SecondaryObjectName IN (@Door))

GROUP BY CONVERT(VARCHAR(10), (DateAdd(minute,-(ServerLocaleOffset),ServerUTC)),101)
        ,PrimaryObjectIdentity
        ,SecondaryObjectIdentity
        ,MessageType
        ,PrimaryObjectName
        ,SecondaryObjectName
        ,Text13
ORDER BY AJ.PrimaryObjectName

我想获取 SELECT 语句中调用的列以及包含第二个的日期时间。同样,我也想要最有效的方式来提取这些数据。非常感谢。

【问题讨论】:

能否提供一下带有日期时间列的表结构? ServerUTC 是 datetime2 列,serverlocaloffset 只记录距 GMT 多少分钟是服务器的时区。 好吧……即使这样,我的查询也应该可以了……你试过了吗……?? 【参考方案1】:

假设 PrimaryObjectIdentity 是在 JournalLogview 和 ServerLocaleOffset 中查找人员的主键作为该表中的 datetime 列,我已经写下了:

DECLARE @Begin datetime2 = '4/10/2019',
        @End datetime2 = '4/11/2019',
        @Door varchar(max) = 'Front Entrance'

WITH cte 
AS(
SELECT 
ROW_NUMBER() OVER 
(PARTITION BY PrimaryObjectIdentity,CONVERT(VARCHAR(10), (DateAdd(minute,-(ServerLocaleOffset),ServerUTC)),101) ORDER BY ServerLocaleOffset) AS row_num,
--whatever the columns you want here
*
FROM
Access.JournalLogView)

SELECT
         DateAdd(minute,-(ServerLocaleOffset),ServerUTC)) AS 'DateTime'
        ,AJ.PrimaryObjectIdentity
        ,AJ.SecondaryObjectIdentity
        ,AJ.MessageType
        ,AJ.PrimaryObjectName
        ,AJ.SecondaryObjectName
        ,AP.Text13
        --I guess count(*) won't be of use a we are selecting only the first row
        ,COUNT(*) AS 'Count'
FROM cte AJ
LEFT OUTER JOIN 
Access.Personnel as AP 
on 
AP.GUID = AJ.PrimaryObjectIdentity
WHERE 
AJ.row_num = 1
AND (MessageType like 'CardAdmitted' OR MessageType like 'CardRejected')
AND (DateAdd(minute,-(ServerLocaleOffset),ServerUTC)) BETWEEN @Begin AND @End
AND (SecondaryObjectName IN (@Door))

GROUP BY (DateAdd(minute,-(ServerLocaleOffset),ServerUTC))
        ,PrimaryObjectIdentity
        ,SecondaryObjectIdentity
        ,MessageType
        ,PrimaryObjectName
        ,SecondaryObjectName
        ,Text13
ORDER BY AJ.PrimaryObjectName

在此查询中,我使用 PARTITION 按每个用户、日期对整个表进行分区,然后从每个用户在该特定日期的第一个条目开始将 row_number() 分配给每一行。因此,任何 row_num() = 1 的行都会为您提供该用户在该日期的第一个条目(这与我在 where 子句中使用的条件相同)。希望这会有所帮助:)

【讨论】:

以上是关于如何获得每天包含多个列的事件的第一个实例,包括日期时间并返回这些列加上完整的日期时间值?的主要内容,如果未能解决你的问题,请参考以下文章

如何返回最早日期的记录?

如何在 PostgreSQL 中获取表的每一天的第一个日期并将其转换为 JSON

Delphi如何检测表单上任何地方的点击事件,包括其他组件

基于多个日期列创建最小日期列的 SQL 代码 [重复]

SQL - 从单列到两列的所有日期组合

如何获得一天中的第一个日期时间?