SQL Server 2008.
我正在编写一些T-SQL来获取两个数据库之间通用的表列表(基本上是同一数据库的两个副本,因此列名是常见的),截断目标数据库中列表中的每个表并附加来自源数据库中匹配表的行。
作为其中的一部分,我正在构建一个列名列表,以便在最终的SELECT语句中使用它来执行追加。
问题在于,当我尝试将有问题的表的列名列表插入表变量时,我什么也得不到。然而,我分别开发了T-SQL的那一部分,并且它可以单独工作。
有什么明显的错误吗?
DECLARE @SourceCompany CHAR(1)
DECLARE @TargetCompany CHAR(1)
DECLARE @SQL NVARCHAR(4000)
DECLARE @lcParmDef NVARCHAR(4000)
DECLARE @TableCount INT
DECLARE @t INT
DECLARE @ThisTable NVARCHAR(256)
DECLARE @TableList TABLE (name NVARCHAR(256), RowID INT)
DECLARE @ColumnCount INT
DECLARE @c INT
DECLARE @RowList NVARCHAR(4000)
DECLARE @ThisCol NVARCHAR(4000)
DECLARE @ColumnList TABLE (column_name NVARCHAR(4000), id INT IDENTITY )
DECLARE @ColString NVARCHAR(4000)
---------------- Set source and target companies here ----------------
SET @SourceCompany = 'Z'
SET @TargetCompany = 'X'
---------------- Set source and target companies here ----------------
INSERT @TableList (name, RowID) VALUES (N'stran',1), (N'sanal', 2)
SET @TableCount = @@ROWCOUNT
SET @t = 1
WHILE (@t <= @TableCount)
BEGIN
SELECT @ThisTable = name FROM @TableList WHERE RowID = @t
SET @ThisTable = N'[dbo].[' + @ThisTable + N']'
-- Clear target table.
SET @SQL = N'TRUNCATE TABLE [COMP_' + @TargetCompany + N'].[dbo].[' + @ThisTable + N']'
SET @lcParmDef = N''
EXECUTE sp_executesql @SQL, @lcParmDef
-- Build column list for current table.
DELETE FROM @ColumnList
INSERT INTO @ColumnList
SELECT column_name from information_schema.columns
WHERE table_name = @ThisTable
-- PROBLEM - this always returns zero.
SELECT @ColumnCount = Count(*) FROM @ColumnList
SET @c = 1
SET @ColString = ''
WHILE (@c <= @ColumnCount)
BEGIN
SELECT @ThisCol = column_name FROM @ColumnList WHERE id = @c
SET @ColString = @ColString + '[' + @ThisCol + ']'
IF (@c < @ColumnCount) SET @ColString = @ColString + ','
SET @c = @c + 1
END
--- Just print the column string for now, ultimately I will build a SELECT statement and execute.
PRINT @ColString
SET @t = @t + 1
END
答案 0 :(得分:1)
尝试以下更改
评论此行SET @ThisTable = N'[dbo].[' + @ThisTable + N']'
。因为在information_schema.columns
系统视图中,表名称将仅存储为tablename
,而不是[dbo].[tablename]
。甚至不是[square brackets]
。
为架构添加新的variable
并为其指定dbo
。
声明@schema_name
变量
Declare @schema_name char(3) = 'dbo'
将架构名称过滤器添加到查询
INSERT INTO @ColumnList
SELECT column_name
from information_schema.columns
WHERE table_name = @ThisTable
and schema_name = @schema_name
答案 1 :(得分:0)
好的,事实证明使用'information_schema'需要数据库上下文。这里我使用变量中保存的动态数据库名称,你不能(AFAIK,烦人地)在sp_executesql
语句中使用变量。所以我在下面做的是构建一些T-SQL并使用带有输出参数的-- Takes a list of tables in @TableList, truncates that table in a target database and appends all rows
-- from the same table in a source database, building a column list dynamically in each case.
DECLARE @SourceCo CHAR(1)
DECLARE @TargetCo CHAR(1)
DECLARE @SourceCoName CHAR(6)
DECLARE @TargetCoName CHAR(6)
DECLARE @SQLString NVARCHAR(4000)
DECLARE @ParmDefinition NVARCHAR(4000)
DECLARE @TableCount INT
DECLARE @t INT
DECLARE @ThisTable NVARCHAR(256)
DECLARE @TableList TABLE (name NVARCHAR(256), RowID INT)
DECLARE @RowList NVARCHAR(4000)
DECLARE @ThisCol NVARCHAR(4000)
DECLARE @ColumnList TABLE (column_name NVARCHAR(4000), id INT IDENTITY )
DECLARE @ColumnString NVARCHAR(4000)
---------------- Set source and target companies here ----------------
SET @SourceCo = 'Z'
SET @TargetCo = 'X'
SET @SourceCoName = 'COMP_' + @SourceCo
SET @TargetCoName = 'COMP_' + @TargetCo
---------------- Set source and target companies here ----------------
-- Build the list of tables to process.
INSERT @TableList (name, RowID) VALUES (N'stran',1), (N'sanal', 2)
SET @TableCount = @@ROWCOUNT
SET @t = 1
-- Iterate through list of tables.
WHILE (@t <= @TableCount)
BEGIN
SELECT @ThisTable = name FROM @TableList WHERE RowID = @t
-- Clear relevant table in target database.
SET @SQLString = N'TRUNCATE TABLE [' + @TargetCoName + N'].[dbo].[' + @ThisTable + N']'
SET @ParmDefinition = N''
EXECUTE sp_executesql @SQLString, @ParmDefinition
-- Retrieve the column list for current table.
SET QUOTED_IDENTIFIER OFF
SET @SQLString = "DECLARE @ColumnList TABLE (column_name NVARCHAR(4000), id INT IDENTITY );"
SET @SQLString = @SQLString + "DECLARE @c INT;"
SET @SQLString = @SQLString + "DECLARE @ColumnCount INT;"
SET @SQLString = @SQLString + "DECLARE @ThisCol NVARCHAR(4000);"
SET @SQLString = @SQLString + "USE " + @SourceCoName + ";"
SET @SQLString = @SQLString + "INSERT INTO @ColumnList SELECT column_name from information_schema.COLUMNS"
SET @SQLString = @SQLString + " WHERE TABLE_NAME = '" + @ThisTable + "' "
SET @SQLString = @SQLString + " AND TABLE_SCHEMA = 'dbo';"
SET @SQLString = @SQLString + "SELECT @ColumnCount = Count(*) FROM @ColumnList;"
SET @SQLString = @SQLString + "SET @c = 1; SET @ColStringOUT = '';"
SET @SQLString = @SQLString + "WHILE (@c <= @ColumnCount) "
SET @SQLString = @SQLString + " BEGIN "
SET @SQLString = @SQLString + " SELECT @ThisCol = column_name FROM @ColumnList WHERE id = @c"
SET @SQLString = @SQLString + " SET @ColStringOUT = @ColStringOUT + '[' + @ThisCol + ']'"
SET @SQLString = @SQLString + " IF (@c < @ColumnCount) SET @ColStringOUT = @ColStringOUT + ','"
SET @SQLString = @SQLString + " SET @c = @c + 1 "
SET @SQLString = @SQLString + " END"
SET QUOTED_IDENTIFIER ON
SET @ParmDefinition = N'@ColStringOUT NVARCHAR(4000) OUTPUT'
EXECUTE sp_executesql @SQLString, @ParmDefinition, @ColStringOUT = @ColumnString OUTPUT
--- Just print the column string for now, ultimately I will build a SELECT statement using it.
PRINT @ColumnString
SET @t = @t + 1
END
动态执行它,以返回一个字符串,其中包含正在处理的每个表的列名。
REM INSERTING into database1."Users"
SET DEFINE OFF;
Insert into database1."Users" ("id","right") values ('1','R');