2016-05-25 54 views
0

的我有什么简单的例子:是否可以从这个动态查询中移除游标?

两个表(TABLE_1和TABLE_2),其中有一个类似的列(同上),但也有几个“有效载荷”用不同的名称(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 '[email protected]_name+' WHERE '[email protected] 
    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

如果您想更改对象名称(tables/databases/schemas/...),您将不得不使用动态SQL。 – mxix

回答

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 
+0

谢谢,效果很好。 –

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折叠每个表和另一个列 - 将所有查询合并成一个大脚本。

+0

这也可以,谢谢 –

相关问题