【发布时间】:2019-09-12 18:46:16
【问题描述】:
我正在尝试创建一组可供我的测试人员使用的查询,这些查询可以重复,当然还有“参数”驱动。
我的一个测试涉及将一个表的数据类型与另一个表的数据类型进行比较,并且我尝试将查询参数化到使用该查询的人只需要修改查询的顶部区域的程度,但我遇到了问题一个区域,数据库名称。
我不想为此走动态 SQL 路线,但正在寻找解决问题的方法
DECLARE @Source_DB nvarchar(128) = 'SourceDB'
, @Source_Table nvarchar(128) = 'SourceTable'
, @Source_Schema nvarchar(128) = 'PJ';
SELECT *
FROM @Source_DB.INFORMATION_SCHEMA.COLUMNS isc
WHERE isc.TABLE_NAME = @Source_Table AND isc.TABLE_SCHEMA = @Source_Schema
下面的完整查询:
DECLARE @Source_DB nvarchar(128) = 'SourceDB'
, @Source_Table nvarchar(128) = 'SourceTable'
, @Source_Schema nvarchar(128) = 'SS'
, @Target_DB nvarchar(128) = 'TargetDB'
, @Target_Table nvarchar(128) = 'TargetTable'
, @Target_Schema nvarchar(128) = 'TS';
SELECT a.Source_TABLE_CATALOG
, b.Target_TABLE_CATALOG
, a.Source_SCHEMA
, b.Target_SCHEMA
, a.Source_TABLE_NAME
, b.Target_TABLE_NAME
, a.Source_ORDINAL_POSITION
, b.Target_ORDINAL_POSITION
, a.Source_COLUMN_NAME
, b.Target_COLUMN_NAME
, a.Source_DATATYPE
, b.Target_DATATYPE
, a.Source_Nullable
, b.Target_Nullable
, a.Source_Default
, b.Target_Default
FROM (
SELECT isc.TABLE_CATALOG AS [Source_TABLE_CATALOG]
, isc.TABLE_SCHEMA AS [Source_SCHEMA]
, isc.TABLE_NAME AS [Source_TABLE_NAME]
, isc.ORDINAL_POSITION AS [Source_ORDINAL_POSITION]
, isc.COLUMN_NAME AS [Source_COLUMN_NAME]
, CASE
WHEN isc.DATA_TYPE IN ('decimal', 'money', 'numeric')
THEN CONCAT(isc.DATA_TYPE, '(', isc.NUMERIC_PRECISION, ',', isc.NUMERIC_SCALE, ')')
WHEN isc.DATA_TYPE IN ('datetime','date','int')
THEN isc.DATA_TYPE
WHEN isc.DATETIME_PRECISION IS NOT NULL
THEN CONCAT(isc.DATA_TYPE, '(', isc.DATETIME_PRECISION, ')')
WHEN isc.DATA_TYPE = 'varchar' AND (isc.CHARACTER_MAXIMUM_LENGTH = 8000 OR isc.CHARACTER_MAXIMUM_LENGTH = -1)
THEN 'varchar(MAX)'
WHEN isc.DATA_TYPE = 'nvarchar' AND (isc.CHARACTER_MAXIMUM_LENGTH = 4000 OR isc.CHARACTER_MAXIMUM_LENGTH = -1)
THEN 'nvarchar(MAX)'
ELSE
CONCAT(isc.DATA_TYPE, '(', isc.CHARACTER_MAXIMUM_LENGTH, ')')
END AS [Source_DATATYPE]
, CASE isc.IS_NULLABLE
WHEN 'YES' THEN 'NULL'
WHEN 'NO' THEN 'NOT NULL'
END AS [Source_Nullable]
, isc.COLUMN_DEFAULT AS [Source_Default]
FROM @Source_DB.INFORMATION_SCHEMA.COLUMNS isc
WHERE isc.TABLE_NAME = @Source_Table AND isc.TABLE_SCHEMA = @Source_Schema
) a
JOIN (
SELECT isc.TABLE_CATALOG AS [Target_TABLE_CATALOG]
, isc.TABLE_SCHEMA AS [Target_SCHEMA]
, isc.TABLE_NAME AS [Target_TABLE_NAME]
, isc.ORDINAL_POSITION AS [Target_ORDINAL_POSITION]
, isc.COLUMN_NAME AS [Target_COLUMN_NAME]
, CASE
WHEN isc.DATA_TYPE IN ('decimal', 'money', 'numeric')
THEN CONCAT(isc.DATA_TYPE, '(', isc.NUMERIC_PRECISION, ',', isc.NUMERIC_SCALE, ')')
WHEN isc.DATA_TYPE IN ('datetime','date','int')
THEN isc.DATA_TYPE
WHEN isc.DATETIME_PRECISION IS NOT NULL
THEN CONCAT(isc.DATA_TYPE, '(', isc.DATETIME_PRECISION, ')')
WHEN isc.DATA_TYPE = 'varchar' AND (isc.CHARACTER_MAXIMUM_LENGTH = 8000 OR isc.CHARACTER_MAXIMUM_LENGTH = -1)
THEN 'varchar(MAX)'
WHEN isc.DATA_TYPE = 'nvarchar' AND (isc.CHARACTER_MAXIMUM_LENGTH = 4000 OR isc.CHARACTER_MAXIMUM_LENGTH = -1)
THEN 'nvarchar(MAX)'
ELSE
CONCAT(isc.DATA_TYPE, '(', isc.CHARACTER_MAXIMUM_LENGTH, ')')
END AS [Target_DATATYPE]
, CASE isc.IS_NULLABLE
WHEN 'YES' THEN 'NULL'
WHEN 'NO' THEN 'NOT NULL'
END AS [Target_Nullable]
, isc.COLUMN_DEFAULT AS [Target_Default]
FROM @Target_DB.INFORMATION_SCHEMA.COLUMNS isc
WHERE isc.TABLE_NAME = @Target_Table AND isc.TABLE_SCHEMA = @Target_Schema
) b ON a.Source_COLUMN_NAME = b.Target_COLUMN_NAME
WHERE a.Source_DATATYPE <> b.Target_DATATYPE OR
a.Source_Nullable <> b.Target_Nullable OR
a.Source_Default <> b.Target_Default
理想的结果是我可以让 SQL 查询工作,但它可能证明这是在动态查询之外无法完成的事情,从我的角度来看,这不会导致问题,因为代码会被保留在文本文件中(与所有其他模板化查询一起),并且在输入参数之前不会运行。
【问题讨论】:
-
“我不想为此走动态 SQL 路线,但我正在寻找解决问题的方法” 你不能不这样做。您不能用表达式或参数/变量替换对象的名称。它们必须是文字值。
SELECT * FROM @DBName.dbo.MyTable;会产生错误Incorrect syntax near '.'. -
如果您使用的是该副本,请查看使用
QUOTENAME的示例(并且被赞成),而不是接受的答案。 -
对于这种特殊情况还有另一种解决方案,它涉及使用相关信息架构列的
UNION ALL创建一个跨数据库视图。您必须维护每个数据库的创建或删除视图(使用服务器级触发器)。 -
有一个没有使用SQLCMD脚本变量的动态SQL的解决方案。不幸的是,这个问题被关闭了,所以我无法提供答案。
-
@DanGuzman 现在营业了
标签: sql-server sqlcmd