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

时间:2018-11-21 08:30:30

标签: sql sql-server tsql 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                    |
+-----+--------+-------------------------+

有什么想法吗?

1 个答案:

答案 0 :(得分:3)

我为您提供2个版本

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 ='OUT'则为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,根据一些经验,大型表有时会更快。 例如对于具有产生下一个统计数据的示例语句

  

表“工作表”。扫描计数0,逻辑读取0,物理读取0,   预读读取0,lob逻辑读取0,lob物理读取0,lob   预读将读取0。表'SignIn'。扫描计数2,逻辑读取2,   物理读取0,预读读取0,lob逻辑读取0,lob   物理读为0,lob预读为0。

并存在声明:

  

表“ SignIn”。扫描计数2,逻辑读取8,物理读取0,   预读读取0,lob逻辑读取0,lob物理读取0,lob   预读将读取0。

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