Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/variables/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 使用while循环在SQL Server实例上创建数据库表和表信息_Sql Server_Variables_While Loop - Fatal编程技术网

Sql server 使用while循环在SQL Server实例上创建数据库表和表信息

Sql server 使用while循环在SQL Server实例上创建数据库表和表信息,sql-server,variables,while-loop,Sql Server,Variables,While Loop,我想知道为什么在下面的while循环中不能用DB名称替换变量@DBNAME: 我可以使用变量作为DB_名称,但它不允许我将DB名称替换为sys.tables 它给了我以下错误:“.”附近的语法不正确 DROP TABLE #TABLE_INFO; CREATE TABLE #TABLE_INFO ( DB_NAME VARCHAR(100), TABLE_NAME VARCHAR(100), CREATE_DATE DATE ); DECLARE @CO

我想知道为什么在下面的while循环中不能用DB名称替换变量@DBNAME:

我可以使用变量作为DB_名称,但它不允许我将DB名称替换为sys.tables

它给了我以下错误:“.”附近的语法不正确

DROP TABLE #TABLE_INFO;
CREATE TABLE #TABLE_INFO
    (
    DB_NAME VARCHAR(100),
    TABLE_NAME VARCHAR(100),
    CREATE_DATE DATE
    );

DECLARE @COUNT AS INT = 1
DECLARE @DBNAME AS VARCHAR(100)

WHILE @COUNT < (SELECT MAX(DATABASE_ID) +1 FROM SYS.DATABASES)
BEGIN
    SET @DBNAME = (SELECT NAME FROM SYS.DATABASES WHERE DATABASE_ID = @COUNT)

    INSERT INTO #TABLE_INFO
    SELECT
        @DBNAME AS DB_NAME,
        A1.NAME AS TABLE_NAME,
        A1.CREATE_DATE
    FROM @DBNAME.SYS.TABLES A1

    SET @COUNT = @COUNT+1
END

SELECT * FROM #TABLE_INFO;
T-SQL不允许对数据库对象标识符进行参数化。 …因此您必须使用动态SQL,即在字符串值内建立查询并将其传递给sp_executesql。 显然,这是危险的,因为存在SQL注入的风险,或者只是忘记正确转义名称使用QUOTENAME,这可能会导致意外的数据丢失,例如,如果有人实际将表命名为[DELETE FROM Users]。 因此,尽可能少地使用动态SQL非常重要。 您可以使用INSERT INTO@tableVariable EXECUTE sp_executesql@query将存储过程(或任何动态SQL)的结果存储到表变量或临时表中,而无需直接输出到客户端连接,然后使用非动态SQL处理结果。 如果可以将所有动态SQL逻辑移动到存储过程中,也可以使用交叉应用。 试试这个:

顺便说一句,我将您的WHILE循环更改为使用静态只读游标,这避免了您对sys.databases的数据库id如何工作的假设,例如,如果sys.databases仅列出这4个数据库id值1、2、99997、99998会怎么样?您的WHILE循环将浪费时间检查3、4、5、6、…、99996。 我还使用表变量而不是临时表,因为与临时表相比,表变量的作用域和生存期更容易推理。也就是说,虽然可以将TV作为表值参数传递,但TV与TTs相比实际上没有任何性能优势,这很好,而且通常比使用TTs将数据传递给存储过程要好得多。 我能够将此查询复制并粘贴到SSMS中,并在我的SQL Server 2017框中运行它,而无需修改,它将返回预期结果

T-SQL不允许对数据库对象标识符进行参数化。 …因此您必须使用动态SQL,即在字符串值内建立查询并将其传递给sp_executesql。 显然,这是危险的,因为存在SQL注入的风险,或者只是忘记正确转义名称使用QUOTENAME,这可能会导致意外的数据丢失,例如,如果有人实际将表命名为[DELETE FROM Users]。 因此,尽可能少地使用动态SQL非常重要。 您可以使用INSERT INTO@tableVariable EXECUTE sp_executesql@query将存储过程(或任何动态SQL)的结果存储到表变量或临时表中,而无需直接输出到客户端连接,然后使用非动态SQL处理结果。 如果可以将所有动态SQL逻辑移动到存储过程中,也可以使用交叉应用。 试试这个:

顺便说一句,我将您的WHILE循环更改为使用静态只读游标,这避免了您对sys.databases的数据库id如何工作的假设,例如,如果sys.databases仅列出这4个数据库id值1、2、99997、99998会怎么样?您的WHILE循环将浪费时间检查3、4、5、6、…、99996。 我还使用表变量而不是临时表,因为与临时表相比,表变量的作用域和生存期更容易推理。也就是说,虽然可以将TV作为表值参数传递,但TV与TTs相比实际上没有任何性能优势,这很好,而且通常比使用TTs将数据传递给存储过程要好得多。
我可以将此查询复制并粘贴到SSMS中,并在我的SQL Server 2017框中运行它,而无需修改,它将返回预期结果。

T-SQL不支持数据库对象标识符的参数化数据库名称、表名称、列名等,只能参数化值。实际上,我不知道有哪种SQL方言允许对数据库对象标识符进行参数化。唯一的解决方法是使用动态SQL。这是否回答了您的问题?T-SQL不支持数据库对象标识符的参数化数据库名称、表名、列名等,只能参数化值。实际上,我不知道有哪种SQL方言允许对数据库对象标识符进行参数化。唯一的解决方法是使用动态SQL。这是否回答了您的问题?谢谢你,戴,第二个答案正是我想要的结果,第一个建议给了我一些关于我所面临问题的背景知识。非常感谢!谢谢你,戴,第二个答案正是我想要的结果,第一个建议给了我一些关于我所面临问题的背景知识。非常感谢!
DECLARE @results TABLE (
    DatabaseName nvarchar(100) NOT NULL,
    SchemaName   nvarchar(50)  NOT NULL,
    TableName    nvarchar(100) NOT NULL,
    Created      datetime      NOT NULL
);

DECLARE @dbName nvarchar(100);

DECLARE c CURSOR STATIC READ_ONLY FOR
    SELECT QUOTENAME( [name] ) FROM sys.databases;

OPEN c;

FETCH NEXT FROM c INTO @dbName;

WHILE @@FETCH_STATUS = 0
BEGIN
    
    DECLARE @dbQuery nvarchar(1000) = N'

SELECT
    ''' + @dbName + N''' AS DatabaseName,
    s.[name]      AS SchemaName,
    t.[name]      AS TableName,
    t.create_date AS Created
FROM
    ' + @dbName + N'.sys.tables AS t
    INNER JOIN sys.schemas AS s ON t.schema_id = s.schema_id
ORDER BY
    s.[name],
    t.[name]
';

    INSERT INTO @results
        ( DatabaseName, SchemaName, TableName, Created )
    EXECUTE sp_executesql @dbQuery;
    
    
    FETCH NEXT FROM c INTO @dbName;
    
END;
CLOSE c;
DEALLOCATE c;

--------------------------

SELECT
    *
FROM
    @results
ORDER BY
    DatabaseName,
    SchemaName,
    TableName;