【问题标题】:SQL Join two tables with same column names, and get sum of each columnSQL连接两个具有相同列名的表,并获取每列的总和
【发布时间】:2017-07-07 21:52:43
【问题描述】:

我知道从长远来看...列名相同可能无关紧要。但这是我所拥有的:

主表:

| PersonID | 1970 | 1971 | 1972 | 1973 |
|----------|------|------|------|------|
|        1 |   50 |   50 |  100 |   50 |
|        2 |   30 |   30 |   40 |   40 |
|        3 |   40 |   40 |   40 |   20 |

补充表

| PersonID |   1972 |   1973 |
|----------|--------|--------|
|        1 |    100 | (null) |
|        2 | (null) | (null) |
|        3 | (null) |    200 |

我想要一个表(实际上是一个视图),它将连接这两个表,并将列的总和添加到具有相同名称的列中

组合表:

| PersonID | 1970 | 1971 | 1972 | 1973 |
|----------|------|------|------|------|
|        1 |   50 |   50 |  200 |   50 |
|        2 |   30 |   30 |   40 |   40 |
|        3 |   40 |   40 |   40 |  220 |

生成的表需要将两个表合并。年份一直到 2017 年,并且每个表的名称相同。

SQLfiddle

【问题讨论】:

    标签: sql sql-server sql-server-2008


    【解决方案1】:

    如果每个 id 只有一个匹配行,那么 left join 会这样做:

    select t1.person_id, t1.[1970], t1.[1971],
           (t1.[1972] + coalesce(t2.[1972], 0)) as [1972],
           (t1.[1973] + coalesce(t2.[1973], 0)) as [1973]       
    from t1 left join
         t2
         on t1.person_id = t2.person_id
    

    【讨论】:

      【解决方案2】:

      除非您选择使用动态 SQL(通常最好避免以防止 SQL 注入、错误和负面性能影响),否则列名相同不会给我们提供任何快捷方式。

      执行此操作的规范方法是明确地对每一列求和:

      SELECT mt.PersonID, COALESCE(mt.[1970], 0) + COALESCE(st.[1970], 0), COALESCE(mt.[1971], 0) + COALESCE(st.[1971], 0), ... COALESCE(mt.[2017], 0) + COALESCE(st.[2017], 0)
      FROM MasterTable mt
      LEFT JOIN SupplementalTable st
          ON mt.PersonID = st.PersonID;
      

      但是,这 40 列很糟糕(听起来将来可能会更多)。动态 SQL 通常最好避免,但有时它仍然是完成这项工作的最佳工具。以下是使用动态 SQL 解决相同问题的方法:

      DECLARE @dynamicSql NVARCHAR(MAX);
      DECLARE @selectList NVARCHAR(MAX);
      
      SELECT @selectList = COALESCE(@selectList + ', ', '') + 'COALESCE(mt.[' + mtColumns.COLUMN_NAME + '], 0)' + COALESCE(' + COALESCE(st.[' + stColumns.COLUMN_NAME + '], 0)', '')
      FROM INFORMATION_SCHEMA.COLUMNS mtColumns
      LEFT JOIN INFORMATION_SCHEMA.COLUMNS stColumns ON mtColumns.COLUMN_NAME = stColumns.COLUMN_NAME
      WHERE mtColumns.TABLE_NAME = 'MasterTable'
            AND stColumns.TABLE_NAME = 'SupplementaryTable';
      
      SET @dynamicSql = 'SELECT ' + @selectList + ' FROM MasterTable mt INNER JOIN SupplementaryTable st ON mt.PersonID = st.PersonID;';
      
      EXECUTE sp_executesql @dynamicSql;
      

      我还没有生成实际的表来测试它,但它应该相当接近。该查询应为每个字段生成SELECT 字段总和列表,然后运行它。它还应该跳过 SupplementaryTable 中不存在的字段,并且它只会对 确实 存在于 MasterTable 中的字段进行操作。

      使用 ORM(如 Hibernate)可以通过提前验证列名来大大减少潜在的错误或 SQL 注入漏洞。

      【讨论】:

      • 我真的希望动态 SQL 工作,因为你是对的,它确实很糟糕。不幸的是,当我插入我的值时,我不断收到“必须声明标量变量@selectList”。我从来没有玩过动态 SQL,但我可以清楚地看到,我们正在声明它。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-11-25
      • 2016-03-24
      • 2021-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-07
      相关资源
      最近更新 更多