Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
SQL连接两个具有相同列名的表,并获取每列的总和_Sql_Sql Server_Sql Server 2008 - Fatal编程技术网

SQL连接两个具有相同列名的表,并获取每列的总和

SQL连接两个具有相同列名的表,并获取每列的总和,sql,sql-server,sql-server-2008,Sql,Sql Server,Sql Server 2008,我知道从长远来看。。。列名相同可能与此无关。但我得到的是: 主表: | PersonID | 1970 | 1971 | 1972 | 1973 | |----------|------|------|------|------| | 1 | 50 | 50 | 100 | 50 | | 2 | 30 | 30 | 40 | 40 | | 3 | 40 | 40 | 40 | 20 | 补充表 | Pers

我知道从长远来看。。。列名相同可能与此无关。但我得到的是:

主表:

| 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年,每个表都有相同的名称


如果每个id只有一个匹配行,则left join将执行以下操作:


除非您选择使用动态SQL来避免SQL注入、bug和负面性能影响,否则在这里,相同的列名不会给我们提供任何快捷方式

实现这一点的标准方法是显式求和每列:

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;
我还没有生成实际的表来测试这一点,但应该非常接近。查询应该为每个字段生成一个选择字段和的列表,然后运行它。它还应该跳过补充表中不存在的字段,并且只对主表中确实存在的字段进行操作


使用像Hibernate这样的ORM可以通过提前验证列名来大大减少潜在的bug或SQL注入漏洞。

我真的很想让动态SQL工作,因为你是对的,它确实很糟糕。不幸的是,当我插入我的值时,我总是得到必须声明标量变量@selectList。。我从来没有玩弄过动态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;