我所拥有的简化示例:
两个表(table_1和table_2),它们具有一个相似的列(Id),但也有几个具有不同名称的“有效负载”列(col_1_1,col_2_1,col_2_2)。对于不同的表,“有效负载”列的数量是不同的。
我感兴趣的是将两个表中的ID提取到另一个表中,以查找所有“有效负载”列为空的行。
可以使用的所有表的所有“有效负载”列的列表(#temp)
这是用光标完成的:
CREATE TABLE #temp (tab nvarchar(20) not null, col nvarchar(20) not null)
INSERT INTO #temp SELECT 'table_1','col_1_1' UNION SELECT 'table_2','col_2_1' UNION SELECT 'table_2','col_2_2'
DECLARE @table_name nvarchar(20)
DECLARE @sql nvarchar(max)
DECLARE curs CURSOR FOR (SELECT DISTINCT tab FROM #temp)
OPEN curs
FETCH NEXT FROM curs INTO @table_name
WHILE @@FETCH_STATUS = 0
BEGIN
SELECT @sql = ISNULL(@sql,'')+col+' IS NULL AND ' FROM #temp WHERE tab = @table_name
SET @sql += 'Id IS NOT NULL'
SET @sql = 'INSERT INTO #temp_master SELECT ID FROM '+@table_name+' WHERE '+@sql
print @sql
SET @sql = ''
FETCH NEXT FROM curs INTO @table_name
END
CLOSE curs
DEALLOCATE curs
结果如下:
INSERT INTO #temp_master SELECT ID FROM table_1 WHERE col_1_1 IS NULL AND Id IS NOT NULL
INSERT INTO #temp_master SELECT ID FROM table_2 WHERE col_2_1 IS NULL AND col_2_2 IS NULL AND Id IS NOT NULL
是否可以删除光标以获得相同的结果动态查询?问题是当我移除光标时,我无法为不同的表创建动态“IS NULL AND”部分。
答案 0 :(得分:2)
可以摆脱那个光标。这可能就是你所需要的:
CREATE TABLE #temp (tab nvarchar(20) not null, col nvarchar(20) not null)
INSERT INTO #temp SELECT 'table_1','col_1_1' UNION SELECT 'table_2','col_2_1' UNION SELECT 'table_2','col_2_2'
DECLARE @table_name nvarchar(20)
DECLARE @sql nvarchar(max) = ''
select @sql = 'INSERT INTO #temp_master SELECT ID FROM ' + t.tab + ' WHERE Id IS NOT NULL AND ' + substring(t.cols, 0, len(t.cols)-3) + '
' + @sql from
(
SELECT
distinct
t2.tab,
stuff(
(
select t1.col + cast(' IS NULL AND ' as varchar(max))
from #temp t1
WHERE t1.tab = t2.tab
order by t1.tab
for xml path('')
), 1, 0, '') AS cols
FROM
#temp t2
) as t
order by t.tab desc
print @sql
drop table #temp
答案 1 :(得分:1)
这是一个常规的CONCAT
问题,你可以找到很多方法来完成它而不用光标。其中一种方法是光标,对于这样的任务来说并不坏。
另一个也更受欢迎 - FOR XML
可以保证行顺序(如果有的话):
DECLARE @sql VARCHAR(MAX)
CREATE TABLE #temp (tab nvarchar(20) not null, col nvarchar(20) not null)
INSERT INTO #temp SELECT 'table_1','col_1_1' UNION SELECT 'table_2','col_2_1' UNION SELECT 'table_2','col_2_2'
SET @sql = (SELECT (
SELECT '
INSERT INTO #temp_master (ID) SELECT t.ID FROM '+t.tab +' t WHERE t.Id IS NOT NULL'
+ (select ' AND t.' + tt.col + ' is NULL' from #temp tt WHERE tt.tab = t.tab FOR XML PATH(''), TYPE).value('.', 'varchar(max)')
FROM #temp t
GROUP BY t.tab
FOR XML PATH(''), TYPE).value('.', 'varchar(max)'))
PRINT @sql
DROP TABLE #temp
一点点"棘手"事情是你有两件事需要解决:
所以你有一个内部FOR XML
来折叠每个表的列和另一个 - 将所有查询组合成一个大的脚本。