2012-07-22 66 views
4

我有以下SQL Server 2008的表:计数更新的记录

CREATE TABLE tbl (ID INT, dtIn DATETIME2, dtOut DATETIME2, Type INT, nID INT) 
INSERT tbl VALUES 
(1, '05:00', '10:00', 1, 1), --will be changed 
(2, '08:00', '16:00', 2, 1), 
(3, '02:00', '08:00', 1, 1), --will be changed 
(4, '07:30', '11:00', 1, 1) 

,我用下面的SQL来更新部分重叠记录:

UPDATE tbl 
SET dtOut = COALESCE((
    SELECT MIN(dtIn) 
    FROM tbl as t2 
    WHERE t2.type = tbl.type AND 
      t2.id <> tbl.id AND 
      t2.dtIn >= tbl.dtIn AND t2.dtIn < tbl.dtOut 
    ), dtOut) 
WHERE nID=1; 

SELECT ROWCOUNT_BIG(); 

用最后一个SELECT认为检索更新的记录数,但它不起作用。

所以我的问题是,我该如何重写这个语句来获取实际更新的记录数? (在上面的数据表中有2个)。

+0

+1使用这样的别名加入表本身就是很酷 – whytheq 2012-07-22 18:45:51

+0

@whytheq:谢谢。别名可能很酷......它并不完全给我我想要的东西。 – ahmd0 2012-07-23 18:39:18

回答

2

1. 就在最后SELECT

UPDATE tbl 
SET dtOut = COALESCE((
    SELECT MIN(dtIn) 
    FROM tbl as t2 
    WHERE t2.type = tbl.type AND 
      t2.id <> tbl.id AND 
      t2.dtIn >= tbl.dtIn AND t2.dtIn < tbl.dtOut 
    ), dtOut) 
WHERE nID=1 
SELECT @@ROWCOUNT; 

删除分号......现在返回的东西 - 4 - 这是因为更新运行在全部行,而不仅仅是你需要的2。

2. 越来越近 - 以下只是运行在3行是1型:

update x 
set x.dtout = y.mn 
from tbl x 
inner join 
    ( 
    SELECT t1.type, min(t1.dtIn) mn 
    FROM tbl t1 
    inner join tbl t2 
    on 
     t1.type = t2.type AND 
     t1.id <> t2.id AND 
     t1.dtIn >= t2.dtIn AND 
     t1.dtIn < t2.dtOut 
    group by t1.type 
) y 
    on 
     x.type = y.type 
SELECT @@ROWCOUNT; 

HERE IS THE SQL FIDDLE OF THE ABOVE

3. 感谢@Gilm我炒什么,我希望没问题;它非常类似于Gilm的CTE答案使用的逻辑:

update x 
set x.dtout = y.mn 
from tbl x 
inner join 
    ( 
    SELECT t1.id, min(t2.dtIn) mn 
    FROM tbl t1 
    inner join tbl t2 
    on 
     t1.type = t2.type AND 
     t1.id <> t2.id AND 
     t2.dtIn >= t1.dtIn AND 
     t2.dtIn < t1.dtOut 
    group by t1.id 
) y 
    on 
     x.id = y.id 
SELECT @@ROWCOUNT; 
SELECT * FROM tbl; 

ON SQL FIDDLE HERE

+1

这是错误的,并更新错误的行。从tbl添加一个选择*来查看结果。 – GilM 2012-07-23 03:23:45

+0

@GilM我的第三个查询更新相同的行(ID 1和ID 3)作为您的查询只是没有相同的信息......不知道为什么,因为我们的查询看起来逻辑上相同! – whytheq 2012-07-23 07:00:03

+0

@GilM好的 - 我会再次修改我的狡猾的答案 - 希望只是包括一个正确的答案。 – whytheq 2012-07-23 07:07:24

2

SQL Server将更新原始示例中的所有行。怎么样是这样的:

WITH CTE AS (
    SELECT t1.ID, MIN(t2.dtIn) as New_dtOut 
    FROM tbl as t1 
    LEFT JOIN tbl AS t2 ON t2.type = t1.type AND t2.id <> t1.id 
      AND t2.dtIn >= t1.dtIn AND t2.dtIn < t1.dtOut 
    WHERE t1.nID = 1 
    GROUP BY t1.ID 
) 
UPDATE t1 SET dtOut = t2.New_dtOut 
FROM tbl t1 
JOIN CTE t2 on t2.ID = t1.ID 
WHERE t1.dtOut <> t2.New_dtOut 

SELECT ROWCOUNT_BIG(); 
+0

有趣。让我回顾一下... – ahmd0 2012-07-22 06:43:54

+0

只是好奇,你为什么要做GROUP BY t1.ID? – ahmd0 2012-07-22 06:48:56

+0

需要将一列(或多列)与非聚合列组合的聚合组合起来。我不只是用CTE生成一行,我为每个ID值生成一行。 – GilM 2012-07-22 06:57:05

2

WHERE nID=1是决定多少行会被更新。即使你自己分配dtOut的行也会被更新和计数。

您可以使用output子句捕获表变量中的更新行,然后对dtOut已更改的行进行计数。

DECLARE @T TABLE 
(
    dtOutOld DATETIME2, 
    dtOutNew DATETIME2 
) 

UPDATE tbl 
SET dtOut = COALESCE((
    SELECT MIN(dtIn) 
    FROM tbl as t2 
    WHERE t2.type = tbl.type AND 
      t2.id <> tbl.id AND 
      t2.dtIn >= tbl.dtIn AND t2.dtIn < tbl.dtOut 
    ), dtOut) 
OUTPUT deleted.dtOut, inserted.dtOut INTO @T 
WHERE nID=1 

SELECT COUNT(*) 
FROM @T 
WHERE dtOutOld <> dtOutNew 

SQL-Fiddle

+0

对不起,我想我不擅长SQL。我在SQL小提琴中尝试这个,它不喜欢@T部分...... – ahmd0 2012-07-23 18:38:30

+0

SQL小提琴不喜欢语句分隔符';'。我已经更新了一个链接到小提琴的工作。 – 2012-07-23 19:21:47