将用户服务的最后状态插入 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 视图中插入重复行

如何知道我在 SQL Server 中使用插入触发器的最后日期?

SQL Server事务回滚对自增键的影响

在 SQL Server 和 C# 中获取最后插入的字符串 ID

SQL SERVER 2008 获取最后插入的值

VBA + SQL Server - 获取插入的最后一个 ID