尝试在 sql 测试脚本中参数化数据库
Trying to parameterize the database in a sql test script
我正在尝试创建一组可供我的测试人员使用的查询,这些查询可以被重复table,当然还有 "parameter" 驱动。
我的一项测试涉及将一个 table 的数据类型与另一个进行比较,并且我尝试将查询参数化到使使用该查询的人只需要修改查询的顶部区域的程度, 但我有一个问题,数据库名称。
我不想为此走动态 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 查询正常工作,但这可能证明这是在动态查询之外无法完成的事情,从我的角度来看这不会引起问题因为代码将保存在文本文件中(与所有其他模板化查询一起),并且在输入参数之前不会 运行。
T-SQL 语句中的标识符不能参数化。但是,您可以使用 SQLCMD scripting variables 以便在编译和执行 T-SQL 查询之前替换变量,在功能上类似于文本 search/replace.
下面的示例使用 SQLCMD 脚本变量而不是 T-SQL variables/parameters。带有 SQLCMD 变量的脚本可以在 SQLCMD 模式(查询-->选项-->SQLCMD 模式)下从 SSMS 运行 或通过 SQLCMD 命令行实用程序。
:SETVAR SOURCE_DB YourSourceDatabase
:SETVAR TARGET_DB YourTargetDatabase
DECLARE
@Source_Table nvarchar(128) = 'SourceTable'
, @Source_Schema nvarchar(128) = 'SS'
, @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;
使用 SQLCMD 实用程序,您可以选择使用 -v
参数在命令行而不是在脚本本身中传递所需的值。
我正在尝试创建一组可供我的测试人员使用的查询,这些查询可以被重复table,当然还有 "parameter" 驱动。
我的一项测试涉及将一个 table 的数据类型与另一个进行比较,并且我尝试将查询参数化到使使用该查询的人只需要修改查询的顶部区域的程度, 但我有一个问题,数据库名称。
我不想为此走动态 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 查询正常工作,但这可能证明这是在动态查询之外无法完成的事情,从我的角度来看这不会引起问题因为代码将保存在文本文件中(与所有其他模板化查询一起),并且在输入参数之前不会 运行。
T-SQL 语句中的标识符不能参数化。但是,您可以使用 SQLCMD scripting variables 以便在编译和执行 T-SQL 查询之前替换变量,在功能上类似于文本 search/replace.
下面的示例使用 SQLCMD 脚本变量而不是 T-SQL variables/parameters。带有 SQLCMD 变量的脚本可以在 SQLCMD 模式(查询-->选项-->SQLCMD 模式)下从 SSMS 运行 或通过 SQLCMD 命令行实用程序。
:SETVAR SOURCE_DB YourSourceDatabase
:SETVAR TARGET_DB YourTargetDatabase
DECLARE
@Source_Table nvarchar(128) = 'SourceTable'
, @Source_Schema nvarchar(128) = 'SS'
, @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;
使用 SQLCMD 实用程序,您可以选择使用 -v
参数在命令行而不是在脚本本身中传递所需的值。