Valid From 和 Valid To 列 - 仅显示基于日期之间的值的最新行

Valid From and Valid To columns - Only Show Latest Row based on Value between Dates

我为这件事焦头烂额,不是 100% 确定这是可能的,但在 SQL 中一切皆有可能所以它一定是?!

目的是能够历史地跟踪每个月底有多少活跃帐户。

我有两个table:

在“star_UserAccounts”table 我有(升序):

UserId UserStatus InsertedDate ValidToDate Row Version
JoeBloggs Active 2019-07-19 13:43:09.083 2019-10-31 16:08:27.633 1
JoeBloggs Active 2019-10-31 16:08:28.027 2020-01-09 10:08:27.840 2
JoeBloggs Active 2020-01-09 10:08:28.013 2020-01-09 11:08:28.813 3
JoeBloggs Active 2020-01-09 11:08:28.970 2020-01-16 11:08:24.547 4

现在 - 我想 return 2019 年 10 月 31 日有效的详细信息。那天有两次更新,因此那天的最新 RowVersion 应该是 returned .

当我将日期硬编码到我的 select 脚本中时,我可以获得帐户的单独行版本,但是当我尝试一次性将其应用于多个不同的日期时,它同时获取了两行2019 年 10 月 31 日,但我只希望它在需要的日期获取最新的行。

LastDayOfMonth ActiveAtDate
2019-07-31 1
2019-08-31 1
2019-09-30 1
2019-10-31 2 <-- The problem row
2019-11-30 1
2019-12-31 1

我怎么才能确保为每个推入的日期提取最新的行?

这里有一个 SQL Fiddle 可以玩:http://sqlfiddle.com/#!18/ed372/12

我保留了子查询中的语法错误,因为这种显示了我想要实现的目标,因为我需要将日期传递到收集该日期的 MAX 记录的子查询中。

感谢任何帮助。很难用简单的方式解释,如果很混乱,请见谅。

谢谢。

更新

重新阅读您的 post 后,我意识到在回答之前我没有完全理解您的问题。我会留下我原来的答案,因为它可能会有所帮助。

您的情况可能与使用 COUNT DISTINCT 一样简单,例如:

SELECT
    LastDayOfMonth,
    COUNT ( DISTINCT UserId ) AS ActiveAtDate
FROM @star_UserAccounts AS ua
CROSS APPLY (

    SELECT LastDayOfMonth FROM @LastDayOfMonth AS ld
        WHERE ld.LastDayOfMonth BETWEEN CAST( ua.InsertedDate AS date ) AND CAST( ua.ValidToDate AS date )
        
) AS x
GROUP BY
    LastDayOfMonth
ORDER BY
    LastDayOfMonth;

RETURNS

+----------------+--------------+
| LastDayOfMonth | ActiveAtDate |
+----------------+--------------+
| 2019-07-31     |            1 |
| 2019-08-31     |            1 |
| 2019-09-30     |            1 |
| 2019-10-31     |            1 |
| 2019-11-30     |            1 |
| 2019-12-31     |            1 |
+----------------+--------------+

使用 CROSS APPLY 在 LastDayOfMonth table.

期间将结果集限制为具有 activity 的用户仍然具有相同的效果

下面的原始答案

尝试如下操作:

DECLARE @star_UserAccounts table (
    [UserId] nvarchar (20) COLLATE Latin1_General_CI_AS NOT NULL,
    [InsertedDate] datetime NULL,
    [ValidToDate] datetime NULL,
    [RowVersion] int NOT NULL
);

INSERT INTO @star_UserAccounts ( [UserId], [InsertedDate], [ValidToDate], [RowVersion] )
VALUES
    ('JoeBloggs', '2020-01-09 11:08:28.970', '2020-01-16 11:08:24.547', 4 ), 
    ('JoeBloggs', '2020-01-09 10:08:28.013', '2020-01-09 11:08:28.813', 3 ), 
    ('JoeBloggs', '2019-10-31 16:08:28.027', '2020-01-09 10:08:27.840', 2 ), 
    ('JoeBloggs', '2019-07-19 13:43:09.083', '2019-10-31 16:08:27.633', 1 );

DECLARE @LastDayOFMonth table (
    LastDayOfMonth date
);

INSERT INTO @LastDayOFMonth ([LastDayOfMonth])
VALUES
    ('2019-07-31 00:00:00' ), 
    ('2019-08-31 00:00:00' ), 
    ('2019-09-30 00:00:00' ), 
    ('2019-10-31 00:00:00' ), 
    ('2019-11-30 00:00:00' ), 
    ('2019-12-31 00:00:00' );

;WITH current_activity AS (
    SELECT
        UserID, MAX( RowVersion ) AS CurrentVersion
    FROM @star_UserAccounts
    GROUP BY
        UserID
)
SELECT
    ua.*
FROM current_activity
INNER JOIN @star_UserAccounts AS ua
    ON current_activity.UserID = ua.UserID
    AND current_activity.CurrentVersion = ua.[RowVersion]
WHERE EXISTS (
    
    SELECT * FROM @star_UserAccounts AS u
    CROSS APPLY (
        SELECT * FROM @LastDayOfMonth AS ld
            WHERE CAST( ld.LastDayOfMonth AS date ) BETWEEN CAST( u.InsertedDate AS date ) AND CAST( u.ValidToDate AS date )
    ) AS d
    WHERE
        u.UserId = current_activity.UserId

)
ORDER BY
    current_activity.UserId;

RETURNS

+-----------+-------------------------+-------------------------+------------+
|  UserId   |      InsertedDate       |       ValidToDate       | RowVersion |
+-----------+-------------------------+-------------------------+------------+
| JoeBloggs | 2020-01-09 11:08:28.970 | 2020-01-16 11:08:24.547 |          4 |
+-----------+-------------------------+-------------------------+------------+

CTE 获取最新的 UserIdRowVersion,然后查看用户是否有任何 activity在 LastDayOfMonth.

中列出的日期期间

使用 CROSS APPLY 将结果限制为具有包含 LastDayOfMonth 的任何 activity 的用户。

你把它复杂化了。您可以使用简单的行编号来做到这一点

SELECT
    LastDayOfMonth,
    COUNT(*) ActiveAtDate
FROM (
    SELECT
      ld.LastDayOfMonth,
      ua.UserId,
      rn = ROW_NUMBER() OVER (PARTITION BY ld.LastDayOfMonth, ua.UserId ORDER BY ua.ValidToDate DESC)
    FROM dbo.star_UserAccounts ua
    INNER JOIN LastDayOfMonth ld
      ON ld.LastDayOfMonth >= ua.InsertedDate
      AND DATEADD(day, 1, ld.LastDayOfMonth) < ua.ValidToDate
    WHERE ua.UserId = 'JoeBloggs'
) latestRowForDate
WHERE rn = 1
GROUP BY LastDayOfMonth;

SQL Fiddle