将用户服务的最后状态插入 SQL Server 中的另一个表
Posted
技术标签:
【中文标题】将用户服务的最后状态插入 SQL Server 中的另一个表【英文标题】:insert the last status of a service of users to another table in SQL Server 【发布时间】:2014-06-18 06:25:42 【问题描述】:我在 SQL 数据库中有一个表,并为所有用户插入服务激活日志。例如:服务 a 今天为 mike 停用,然后明天为他启用,然后再次停用。我需要为另一个表中的用户提供每个服务的最后状态。 (唯一约束:userid,serviceid)
logid | userid | serviceid | status
-------+-------------+-------------+--------
1 | mike | a | 0
2 | mike | b | 1
3 | mike | b | 0
4 | mike | a | 1
5 | Dave | c | 1
6 | Dave | a | 0
7 | mike | d | 1
8 | mike | c | 1
9 | mike | a | 0
例如:在上表中,我需要有下表:
userid | serviceid | laststatus
-------+-------------+-------------+--------
mike | a | 0
mike | b | 0
mike | c | 1
mike | d | 1
Dave | c | 1
Dave | a | 0
是否有任何 while 循环从 table1 读取所有记录并插入或更新 table2 以存储用户每个服务的最后状态?像这样:
while (select * from table1)
IF EXISTS
(
SELECT 1
FROM table2
where table2.userid=table1.userid and table2.serviceid=table1.serviceid
)
BEGIN
UPDATE table2
SET table2.laststatus = table1.status
WHERE table2.userid=@userid and table2.serviceid=table1.serviceid
END
ELSE
INSERT INTO table2 VALUES ( table1.userid ,table1.serviceid ,table1.status )
Last status 是给定用户和服务具有最大 logid 的状态
【问题讨论】:
最后一个状态是给定用户和服务logid
最大的状态?
问题不清楚..尝试使用Row_number()
【参考方案1】:
这可以通过MERGE
语句来解决,如下所示:
merge table2 as tgt
using
(
select * from table1
where logid in
(
--Get the row which has the last status for that user-service combination
select distinct max(logid) over (partition by userid, serviceid order by userid,serviceid) mid
from table1)
) as src
on tgt.userid = src.userid and tgt.serviceid = src.serviceid
when matched then
update
set tgt.[status] = src.[status]
when not matched then
insert (userid,serviceid, [status])
values(src.userid, src.serviceid, src.[status]);
演示here.
【讨论】:
非常感谢。我在 table1 上有一个日期时间列作为 dt。我如何使用 max(dt) 而不是 max(logid)?【参考方案2】:在 Table1 上创建一个 INSERT
触发器,它将更新您的 Table2。
触发器将更新 Table2 的 laststatus
。您可以像这样获取特定用户的最后状态:
declare @status int
select top 1 @status = status from Table1 where userid = 'dave' and serviceid = 'c'
order by logid desc
select @status
希望对你有帮助。
【讨论】:
不需要触发器。 如果不使用触发器,您将需要一个持续运行的进程来轮询表。 IMO 这种激活/停用服务不会太频繁,以至于应该运行一个单独的进程来轮询表,并且一个小触发器不会是开销。【参考方案3】:相信下面的代码会给你带来你想要的结果。
使用下面的代码,您将在 table2 中插入 table1 中的所有记录,我不知道这是否是您正在寻找的场景。否则,您可以将其与 @shree.pat18 建议的 MERGE
语句结合使用。
WITH cte AS
(
SELECT
userid
,serviceid
,status
,ROW_NUMBER() OVER (PARTITION BY userid, serviceid ORDER BY logid DESC) Rnk
FROM table1
)
INSERT INTO table2
SELECT
userid
,serviceid
,status AS laststatus
FROM cte
WHERE Rnk=1
【讨论】:
【参考方案4】:不需要触发器。无需合并。不需要partition by
或其他疯狂的东西。
insert into my_second_table (userid, serviceid, laststatus)
select t1.userid, t1.serviceid, t2.status
from (
select userid, serviceid, max(logid) as lastlogid
from my_first_table
group by userid, serviceid
) as t1
join my_first_table t2 on t1.lastlogid = t2.logid
【讨论】:
@shree.pat18:到目前为止,这是最困难的部分。我相信他能弄清楚这一点。 :) 哎呀,只需删除所有记录并再次插入。 你会建议删除并再次插入一个有 100K 记录的表吗? :P @shree.pat18:是的。 :P以上是关于将用户服务的最后状态插入 SQL Server 中的另一个表的主要内容,如果未能解决你的问题,请参考以下文章
如何知道我在 SQL Server 中使用插入触发器的最后日期?