sql-server - 使用 while 循环在 SQL Server 实例上创建数据库表和表信息
问题描述
我想知道为什么我不能在以下 while 循环中用 DB 名称替换变量 @DBNAME:
我可以将变量用作 DB_NAME,但它不会让我用数据库名称替换 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。 CROSS APPLY
如果您可以将所有动态 SQL 逻辑移动到存储过程,您也可以使用。
- ...因此您必须使用动态 SQL(即在字符串值中构建查询并将其传递给
尝试这个:
- 顺便说一句,我将您的
WHILE
循环更改为使用 a来避免您对'工作STATIC READ_ONNLY CURSOR
方式的假设(例如,如果仅列出这 4 个值怎么办?您的循环将浪费时间检查)。sys.databases
database_id
sys.databases
database_id
1, 2, 99997, 99998
WHILE
3, 4, 5, 6, ..., 99996
- 我还使用表变量而不是临时表,因为与临时表相比,表变量的范围和生命周期更容易推理。也就是说,与 TT 相比,TV 并没有真正的性能优势(尽管您可以将 TV 作为表值参数传递,这很好,而且通常比使用 TT 将数据传递给存储过程要好得多)。
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;
我可以将此查询复制+粘贴到 SSMS 中,并在我的 SQL Server 2017 框中运行它而无需修改,它会返回预期的结果。
推荐阅读
- vue.js - 如何在 vue csp 中的“方法”对象中放入更多对象或类?
- php - 由于冲突,我无法访问以占位符为前缀的路由
- python - 如何根据 keras 中的概率对激活输出进行排序?
- css - 移动菜单 - 汉堡图标 - “悬停”颜色不变,“聚焦”链接不起作用
- python - 如何抑制张量流显示每个类的检测分数以使我的边界框预测可读
- .net-core - 使用 HeroCards 作为选择提示:无法选择选项
- apache-kafka - 对于 Multi-Broker kafka 设置,listeners 和adverted.listeners 的值应该是多少?
- c# - 无法通过 REST API 创建客户付款方式
- python - 如何在 Tensorflow 中获得 LSTM 的测试准确度
- position - A 帧:制作
始终“在屏幕上”固定