尝试在 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 参数在命令行而不是在脚本本身中传递所需的值。