SQL 服务器更新行,其中日期不是记录按某个 ID 分组时的最大日期
SQL Server Update Row where date is not the max date when records are grouped by some ID
我有一个 table 每天加载帐户记录的地方。如果一个帐户进入 table 并且它已经存在,我将这两个记录都保存在数据库中,但需要使用旧的 record_date 更新记录,将其 end_date 设置为今天。 Account_ID 是唯一的帐户标识符。
其次,如果 record_date 相同,我会保留较新的条目,可以通过 table_ID 身份字段识别。
例如
TABLE_ID,account_ID,end_date,record_date
2 28576800 NULL 2020-10-20
23 28576800 NULL 2020-10-20
20 32477400 NULL 2020-11-09
22 32477400 NULL 2020-11-13
这是加载数据时 table 的样子。
- 我需要更新 table_id=20 行中的 end_date,因为 table_id=22 行有更新的 record_date.
- 我需要更新 table_id=2 行中的 end_date 因为 record_date 是相同的所以我们结束较小的 table_ID
我试过了;
UPDATE dbo.accounts
SET END_DATE = GETUTCDATE()
where END_DATE is null
and Record_date not in
(SELECT MAX(Record_date ) as mxrptDate
FROM dbo.accounts
GROUP BY account_ID)
这没有按预期工作,因为它没有专门针对我要更新的特定 account_iD 的最大值(record_date)。
当 recrod_date 相同时,我使用相同类型的查询,我认为它有效,因为 table_id 是唯一的。不过感觉一定有更好的办法。
UPDATE dbo.accounts
SET END_DATE = GETUTCDATE()
where END_DATE is null
and table_id not in
(SELECT MAX(table_id ) as mxtblid
FROM dbo.accounts
GROUP BY account_ID)
你的第二个查询快完成了,你只需要关联子查询:
UPDATE ac
SET END_DATE = GETUTCDATE()
FROM dbo.accounts ac
where ac.END_DATE is null
and ac.table_id <>
(SELECT MAX(table_id) as mxtblid
FROM dbo.accounts ac2
WHERE ac2.account_ID = ac.account_ID)
但我们也可以使用 window 函数来解决这个问题,而无需求助于自连接。这可能或多或少的性能,做测试。
我们可以 select 使用子查询正确的行,并直接更新这些行:
UPDATE ac
SET END_DATE = GETUTCDATE()
FROM (
SELECT *,
rn = ROW_NUMBER() OVER (PARTITION BY account_ID ORDER BY TABLE_ID DESC)
FROM dbo.accounts ac
where ac.END_DATE is null
) ac
WHERE ac.rn > 1;
编辑
看来你也想按日期排序
最终解决方案将找到最新的 record_date 或者如果有多个记录具有该日期,则取最高的 table_id:
UPDATE ac
SET END_DATE = GETUTCDATE()
FROM (
SELECT *,
rn = ROW_NUMBER() OVER (PARTITION BY account_ID ORDER BY record_date desc, TABLE_ID DESC)
FROM dbo.accounts ac
where ac.END_DATE is null
) ac
WHERE ac.rn > 1;
我有一个 table 每天加载帐户记录的地方。如果一个帐户进入 table 并且它已经存在,我将这两个记录都保存在数据库中,但需要使用旧的 record_date 更新记录,将其 end_date 设置为今天。 Account_ID 是唯一的帐户标识符。 其次,如果 record_date 相同,我会保留较新的条目,可以通过 table_ID 身份字段识别。
例如
TABLE_ID,account_ID,end_date,record_date
2 28576800 NULL 2020-10-20
23 28576800 NULL 2020-10-20
20 32477400 NULL 2020-11-09
22 32477400 NULL 2020-11-13
这是加载数据时 table 的样子。
- 我需要更新 table_id=20 行中的 end_date,因为 table_id=22 行有更新的 record_date.
- 我需要更新 table_id=2 行中的 end_date 因为 record_date 是相同的所以我们结束较小的 table_ID
我试过了;
UPDATE dbo.accounts
SET END_DATE = GETUTCDATE()
where END_DATE is null
and Record_date not in
(SELECT MAX(Record_date ) as mxrptDate
FROM dbo.accounts
GROUP BY account_ID)
这没有按预期工作,因为它没有专门针对我要更新的特定 account_iD 的最大值(record_date)。
当 recrod_date 相同时,我使用相同类型的查询,我认为它有效,因为 table_id 是唯一的。不过感觉一定有更好的办法。
UPDATE dbo.accounts
SET END_DATE = GETUTCDATE()
where END_DATE is null
and table_id not in
(SELECT MAX(table_id ) as mxtblid
FROM dbo.accounts
GROUP BY account_ID)
你的第二个查询快完成了,你只需要关联子查询:
UPDATE ac
SET END_DATE = GETUTCDATE()
FROM dbo.accounts ac
where ac.END_DATE is null
and ac.table_id <>
(SELECT MAX(table_id) as mxtblid
FROM dbo.accounts ac2
WHERE ac2.account_ID = ac.account_ID)
但我们也可以使用 window 函数来解决这个问题,而无需求助于自连接。这可能或多或少的性能,做测试。
我们可以 select 使用子查询正确的行,并直接更新这些行:
UPDATE ac
SET END_DATE = GETUTCDATE()
FROM (
SELECT *,
rn = ROW_NUMBER() OVER (PARTITION BY account_ID ORDER BY TABLE_ID DESC)
FROM dbo.accounts ac
where ac.END_DATE is null
) ac
WHERE ac.rn > 1;
编辑
看来你也想按日期排序
最终解决方案将找到最新的 record_date 或者如果有多个记录具有该日期,则取最高的 table_id:
UPDATE ac
SET END_DATE = GETUTCDATE()
FROM (
SELECT *,
rn = ROW_NUMBER() OVER (PARTITION BY account_ID ORDER BY record_date desc, TABLE_ID DESC)
FROM dbo.accounts ac
where ac.END_DATE is null
) ac
WHERE ac.rn > 1;