使用具有不同外键的另一个表的特定行的Count更新多个行

时间:2013-04-17 17:29:39

标签: sql sql-update sql-server-2012

我的表格上有一个触发器,用于记录特定页面的所有视图。此触发器使用总视图更新公司表,该视图应由插入的字段派生。在实际情况下,一个公司不应该获得多个视图(所以只选择所有视图并添加一个就足够了),但我喜欢安全编码,所以...

公司: Id,意见

CompanyViews: Id,CompanyId

需要的触发器:

UPDATE Companies 
    SET Views = Views + (SELECT Count(1) FROM INSERTED  AS i WHERE i.CompanyId = Id) 
    WHERE Id IN (SELECT DISTINCT(CompanyId) FROM INSERTED)

但是,这......不起作用。我不太清楚为什么,但基本上预期的结果如下: 说,插入的表有

Id, CompanyId
1   2
2   2
3   3
4   5
5   2
6   3

在这种情况下,公司2将获得3次观看,公司3将获得2次观看,公司5将获得1次观看。

当我的查询失败时,我应该怎么做?

编辑:“不起作用”,我的意思是,值保持不变。实际上,它会将NULL插入到它检测到的行中(即DISTINCT值)。如果我遗漏了Views +,它只会使它为0。

1 个答案:

答案 0 :(得分:0)

不知道为什么要手动尝试使用触发器跟踪此数据,并处理并发问题,确保减少单独触发器中的删除计数等。相反,我只想创建一个索引视图,让SQL Server为您完成工作:

CREATE VIEW dbo.CompanyViewTotals
WITH SCHEMABINDING
AS
  SELECT CompanyId, Views = COUNT_BIG(*)
    FROM dbo.CompanyViews
    GROUP BY CompanyId;
GO
CREATE UNIQUE CLUSTERED INDEX x ON dbo.CompanyViewTotals(CompanyId);
GO

是的,这会对您的插页造成影响,但触发器也是如此。这样做的另一个好处是始终保持正确,允许您放弃触发器,并允许您放弃Views表上浪费的Companies列。即使没有索引视图,这显然是没有该列的情况下已经可以获得的冗余数据。

如果您真的无法解决Entity Framework中所有这些糟糕的限制,那么您可以使用触发器以缓慢且不可靠的方式执行此操作。您需要修复更新语句,以便在inserted与基表之间使用正确的关联,并正确考虑基表中潜在的NULL值。

;WITH cte(CompanyId,NewViews) AS 
(
  SELECT CompanyId, COUNT(CompanyId) 
    FROM inserted 
    GROUP BY CompanyId
)
UPDATE c
  SET c.Views = COALESCE(c.Views, 0) + cte.NewViews
  FROM cte INNER JOIN dbo.Companies AS c
  ON cte.CompanyId = c.CompanyId;