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;