【问题标题】:Bulk updating a table from rows from another table从另一个表的行批量更新一个表
【发布时间】:2008-09-25 23:56:56
【问题描述】:

2 个表:

Employees
- EmployeeID
- LeadCount


Leads
- leadID
- employeeID

我想通过计算Leads 表中具有相同EmployeeID 的潜在客户数来更新Employees.LeadCount 列。

注意:可能有不止 1 个潜在客户具有相同的employeeID,所以我必须做一个DISTINCT(SUM(employeeID))。

【问题讨论】:

    标签: sql sql-update


    【解决方案1】:
    UPDATE
        Employees E
    SET
        E.LeadCount = (
            SELECT COUNT(L.EmployeeID)
            FROM Leads L
            WHERE L.EmployeeID = E.EmployeeID
        )
    

    【讨论】:

      【解决方案2】:

      您正在为数据同步问题做好准备。随着 Leads 表中的行被插入、更新或删除,您需要不断更新 Employees.LeadCount 列。

      最好的解决方案是根本不存储 LeadCount 列,而是根据需要使用 SQL 聚合查询重新计算潜在客户数。这样它就永远是正确的。

      SELECT employeeID, COUNT(leadId) AS LeadCount
      FROM Leads
      GROUP BY employeeID;
      

      另一种解决方案是在 Leads 表上为 INSERT、UPDATE 和 DELETE 创建触发器,以便始终保持Employees.LeadCount 列最新。例如,使用 MySQL 触发器语法:

      CREATE TRIGGER leadIns AFTER INSERT ON Leads
      FOR EACH ROW BEGIN
        UPDATE Employees SET LeadCount = LeadCount + 1 WHERE employeeID = NEW.employeeID;
      END
      
      CREATE TRIGGER leadIns AFTER UPDATE ON Leads
      FOR EACH ROW BEGIN
        UPDATE Employees SET LeadCount = LeadCount - 1 WHERE employeeID = OLD.employeeID;
        UPDATE Employees SET LeadCount = LeadCount + 1 WHERE employeeID = NEW.employeeID;
      END
      
      CREATE TRIGGER leadIns AFTER DELETE ON Leads
      FOR EACH ROW BEGIN
        UPDATE Employees SET LeadCount = LeadCount - 1 WHERE employeeID = OLD.employeeID;
      END
      

      如果您使用 MySQL,另一种选择是使用多表 UPDATE 语法。这是 SQL 的 MySQL 扩展,它不能移植到其他品牌的 RDBMS。首先,将所有行中的 LeadCount 重置为零,然后对 Leads 表进行连接,并在连接产生的每一行中增加 LeadCount。

      UPDATE Employees SET LeadCount = 0;
      UPDATE Employees AS e JOIN Leads AS l USING (employeeID)
        SET e.LeadCount = e.LeadCount+1;
      

      【讨论】:

      • 如果不需要确切的值,那么如果以某种方式作为计划任务运行,所要求的可能会非常好。
      • + 1 表示不存储 LeadCount,但 -1 表示触发器。我认为它们真的应该是单独的回复。
      【解决方案3】:

      Join 对更新(和删除)的作用与对选择的作用相同(编辑:至少在某些流行的 RDBMS 中*):

      UPDATE Employees SET
        LeadCount = Leads.LeadCount
      FROM Employee
      JOIN (
        SELECT EmployeeId, COUNT(*) as LeadCount 
        FROM Leads 
        GROUP BY EmployeeId
      ) as Leads ON
        Employee.EmployeeId = Leads.EmployeeId  
      

      SUM(DISTINCT EmployeeId) 没有意义 - 你只需要一个 COUNT(*)。

      • MS SQL Server 支持UPDATE...FROM 和DELETE...FROM 语法,MySql 也支持,但 SQL-92 标准不支持。 SQL-92 会让您使用行表达式。我知道DB2 支持这种语法,但不确定其他任何语法。坦率地说,我发现 SQL-92 版本令人困惑 - 但标准和理论专家会争辩说,FROM 语法违反了关系理论,并且在不精确的 JOIN 子句或切换 RDBMS 供应商时会导致不可预测的结果。

      【讨论】:

      • 由于某种原因更新查询更加复杂,希望现在我能以同样的方式思考它们!
      • UPDATE 和 DELETE 中的联接不是标准 SQL,但某些实现支持它们作为扩展。哪个品牌的 RDBMS 支持上述语法?
      【解决方案4】:
      UPDATE Employees SET LeadCount = (
        SELECT Distinct(SUM(employeeID)) FROM Leads WHERE Leads.employeeId = Employees.employeeId
      )
      

      【讨论】:

      • sum(employeeid) 没有任何意义,并且围绕单个值区分将始终返回相同的值,因此它是多余的。
      • IIRC 会很慢(我只用过 MySQL)
      【解决方案5】:

      从上面提取并删除依赖的子查询。

      // create tmp -> TBL (EmpID, count)
      
      insert into TBL 
         SELECT employeeID COUNT(employeeID) Di
         FROM Leads WHERE Leads.employeeId = Employees.employeeId GROUP BY EmployeeId
      UPDATE Employees SET LeadCount = (
        SELECT count FROM TBL WHERE TBL.EmpID = Employees.employeeId
      )
      
      // drop TBL
      

      编辑这是“分组依据”而不是“不同”:b(感谢 Mark Brackett)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-09-28
        • 2013-06-03
        • 2013-02-15
        • 1970-01-01
        • 2012-05-24
        • 1970-01-01
        • 2018-07-01
        • 1970-01-01
        相关资源
        最近更新 更多