sql - TSQL - 如果组内不存在特定条目,则插入条目

标签 sql sql-server t-sql sql-server-2012

如果没有记录表明组中的用户已注销,我将尝试插入一个条目。

declare @test table (grp varchar(2),logged varchar(4),time datetime)

insert into @test (grp,logged,time)
values ('A1', 'IN','20181111 09:00:00')
      ,('A1', 'OUT','20181111 10:00:00')
      ,('A2', 'IN','20181111 09:10:00')
      ,('A2', 'IN','20181111 09:20:00')
      ,('A3', 'IN','20181111 09:30:00') 
      ,('A3', 'OUT','20181111 10:30:00')

期望的输出

+-----+--------+-------------------------+
| grp | logged |          time           |
+-----+--------+-------------------------+
| A1  | IN     | 2018-11-11 09:00:00.000 |
| A1  | OUT    | 2018-11-11 10:00:00.000 |
| A2  | IN     | 2018-11-11 09:10:00.000 |
| A2  | IN     | 2018-11-11 09:20:00.000 |
| A2  | OUT    | NULL                    |
| A2  | OUT    | NULL                    |
| A3  | IN     | 2018-11-11 09:30:00.000 |
| A3  | OUT    | 2018-11-11 10:30:00.000 |
| A4  | IN     | 2018-11-11 09:40:00.000 |
| A4  | OUT    | NULL                    |
+-----+--------+-------------------------+

有什么想法吗?

最佳答案

我有两个版本给你

CREATE TABLE SignIn(grp varchar(10), logged varchar(3), [time] datetime)
INSERT INTO SignIn
VALUES
('A1','IN'  ,   '2018-11-11 09:00:00.000'   ),
('A1','OUT',    '2018-11-11 10:00:00.000'   ),
('A2','IN'  ,   '2018-11-11 09:10:00.000'   ),
('A2','IN' ,    '2018-11-11 09:20:00.000'   ),
('A3','IN'  ,   '2018-11-11 09:30:00.000'   ),
('A3','OUT',    '2018-11-11 10:30:00.000'   ),
('A4','IN',     '2018-11-11 09:40:00.000'   )

这个版本正如您所期望的那样。对于每条记录,您将获得一份 OUT 副本

INSERT INTO SignIn (grp, logged, time)
SELECT s.grp, 'OUT', NULL
FROM SignIn s
INNER JOIN (
        SELECT grp
        FROM SignIn
        GROUP BY grp
        HAVING  MAX(CASE WHEN Logged = 'OUT' THEN 1 ELSE 0 END) = 0
        ) notSignedOut ON s.grp = notSignedOut.grp

但是,如果您不想要重复的记录,并且只想为该组提供一条记录,您可以使用以下选项:

    INSERT INTO SignIn (grp, logged, time)
    SELECT grp, 'OUT', NULL
        --ISLoggedOut = MAX(CASE WHEN Logged = 'OUT' THEN 1 ELSE 0 END)
    FROM SignIn
    GROUP BY grp
    HAVING  MAX(CASE WHEN Logged = 'OUT' THEN 1 ELSE 0 END) = 0

主要逻辑隐藏在 ISLoggedOut = MAX(CASE WHEN Logged = 'OUT' THEN 1 ELSE 0 END) 下。对于每组记录,我添加了是否有记录的指示器。如果没有 - 值将为 0。

另一种选择是使用不存在子句

   INSERT INTO SignIn (grp, logged, time)
   SELECT s.grp, 'OUT', NULL
   FROM SignIn s
   WHERE NOT EXISTS (SELECT TOP 1 1 FROM SignIn i WHERE i.grp = s.grp AND Logged = 'OUT')

我个人更喜欢使用HAVING,根据一些经验,对于大表来说,它有时会更快。 例如对于我们的示例语句,having 会生成下一个统计数据

Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. Table 'SignIn'. Scan count 2, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

并存在语句:

Table 'SignIn'. Scan count 2, logical reads 8, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

看起来 HAVING 语句的读取次数比 EXISTS 少

关于sql - TSQL - 如果组内不存在特定条目,则插入条目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53407943/

相关文章:

sql-server - SQL Server - 生成重复日期的计划列表

sql - SQL中如何从不相关的表中获取引用值

mysql - 访问网站的平均日期

mysql - 如何在 MySQL 中选择其值位于 json 数组中的列

sql - 列引用含糊不清

sql-server - VARCHAR' 不是可识别的内置函数名称

sql-server - 无法继续执行,因为 session 处于终止状态。在构建聚集索引时

sql-server - 表 Visual Basic 数据库 (T-SQL) 中的条件 If 语句

sql - 只选择第一个结果...有更好的方法吗?

php - PHP Mysql使用循环和条件语句创建和输出数据