【问题标题】:SQL - Set column value to the SUM of all referencesSQL - 将列值设置为所有引用的总和
【发布时间】:2020-02-06 11:30:14
【问题描述】:

我想让列“CurrentCapacity”成为所有引用特定列的总和。

假设SecTable 中有三行,它们都有FirstTableID = 1Size 值为 1、1 和 3。 FirstTableID = 1 的行现在在 CurrentCapacity 列中的值应为 5。

我怎样才能做到这一点以及如何在插入、更新和删除时自动执行?

谢谢!

第一个表

+----+-------------+-------------------------+
| ID | MaxCapacity | CurrentCapacity         |
+----+-------------+-------------------------+
| 1  | 5           | 0 (desired result = 5)  |
+----+-------------+-------------------------+
| 2  | 5           | 0                       |
+----+-------------+-------------------------+
| 3  | 5           | 0                       |
+----+-------------+-------------------------+

安全表

+----+-------------------+------+
| ID | FirstTableID (FK) | Size |
+----+-------------------+------+
| 1  | 1                 | 2    |
+----+-------------------+------+
| 2  | 1                 | 3    |
+----+-------------------+------+

【问题讨论】:

  • 请在问题中作为文本表格提供示例数据和所需结果。还要解释为什么仅仅使用join/group by 不足以满足您的应用程序。复制数据通常不是一个好主意。
  • 改为创建一个视图,或者至少使用触发器。
  • 我不会存储可以按需计算的数据。
  • @GordonLinoff 我添加了文本表。我认为这是我想要创建的触发器。因此,当我在 SecTable 中插入、更新或删除时,应计算 CurrentCapacity 以正确的值。
  • 这里似乎涵盖了您想要的内容:stackoverflow.com/questions/2769007/… 您可以创建一个用户定义的函数来获取值,然后在计算列中使用该用户定义的函数

标签: sql sql-server


【解决方案1】:

一般来说,视图是一个比试图使计算列保持最新的更好的解决方案。对于您的示例,您可以使用:

CREATE VIEW capacity AS
SELECT f.ID, f.MaxCapacity, COALESCE(SUM(s.Size), 0) AS CurrentCapacity
FROM FirstTable f
LEFT JOIN SecTable s ON s.FirstTableID = f.ID
GROUP BY f.ID, f.MaxCapacity

那么你就可以简单了

SELECT *
FROM capacity

得到你想要的结果。对于您的示例数据:

ID  MaxCapacity     CurrentCapacity
1   5               5
2   5               0
3   5               0

Demo on SQLFiddle

【讨论】:

    【解决方案2】:

    让这个问题与这个触发器一起工作:

    CREATE TRIGGER UpdateCurrentCapacity
    ON SecTable
    AFTER  INSERT, UPDATE, DELETE
    AS
    BEGIN
    SET NOCOUNT ON
        DECLARE @Iteration INT
        SET @Iteration = 1
        WHILE @Iteration <= 100
        BEGIN
            UPDATE FirstTable SET FirstTable.CurrentCapacity = (SELECT COALESCE(SUM(SecTable.Size),0) FROM SecTable WHERE FirstTableID = @Iteration) WHERE ID = @Iteration;
            SET @Iteration = @Iteration + 1
        END
    END
    GO
    

    【讨论】:

    • 请记住,它仅适用于 100 行。如果表会增长,则必须更新此变量,并且每次更改第二个表中的任何行时都必须运行此循环。使用 SQL,您希望避免使用 RBAR 和编程方法。您可以做的是将视图合并到您的表中或执行 UPDATE 以提高性能。
    【解决方案3】:

    就个人而言,我不会使用触发器或将 CurrentCapacity 存储为值,因为它违反了数据库设计的规范化规则。您有一个关系,并且已经可以通过创建视图或将 CurrentCapacity 设置为计算列来获得结果。

    您的视图可能如下所示:

    SELECT Id, MaxCapacity, ISNULL(O.SumSize,0) AS CurrentCapacity 
    FROM dbo.FirstTable FT
    OUTER APPLY
    (
        SELECT ST.FirstTableId, SUM(ST.Size) as SumSize FROM SecTable ST
        WHERE ST.FirstTableId = FT.Id
        GROUP BY ST.FirstTableId
    ) O
    

    当然,每次在第二个表中更新/插入或删除行并重新计算列时,您都可以触发 proc,但您也可以即时计算它。如果不需要使列准确,您可以让工作每 X 小时更新一次值。您可以将此与您的视图结合起来,以获得容量数据的“实时”和“缓存”版本。

    【讨论】:

    • 感谢您的回答。这是针对学校项目而不是在专业环境中。我在 C# 中构建了一个控制台应用程序,并希望每次运行对数据库的查询时都更新 CurrentCapacity。现在我可能会使用触发解决方案。感谢您的意见!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-07
    • 2019-08-17
    • 1970-01-01
    • 2020-05-21
    • 1970-01-01
    • 1970-01-01
    • 2022-11-16
    相关资源
    最近更新 更多