使用动态查询循环遍历 Db 以获取截断语句

Djo*_*oe1 2 sql-server truncate

请在下面对我的 SQL 查询提供任何帮助,我们将不胜感激。我不熟悉如何循环数据库来截断表。我尝试过的内容如下:

DECLARE @DynamicSQL AS VARCHAR(MAX) = '';
DECLARE @dbName     nvarchar(1000) ='SP_%%';


SELECT @DynamicSQL = @DynamicSQL + 'Use' + QUOTENAME(NAME) + ';  '
FROM sys.databases
WHERE NAME LIKE  'SP_%%';

SELECT @DynamicSQL = @DynamicSQL + 'TRUNCATE TABLE ' + QUOTENAME(NAME) + '; '
FROM sys.tables
WHERE name LIKE 'log%'


PRINT @DynamicSQL
--EXEC (@DynamicSQL)
Run Code Online (Sandbox Code Playgroud)

我得到的结果如下:

Use[SP__20180314];  Use[SPAUT__06092018];
Run Code Online (Sandbox Code Playgroud)

但我想要这样的东西:

Use[SP_20180314] Truncate Table log;  Use[SPAUT_06092018] Truncate Table log;
Run Code Online (Sandbox Code Playgroud)

我正在尝试从 SQL Server 2016 上的数据库中截断日志表。谢谢

Geo*_*son 5

正如 Jacob H 在评论中提到的,您需要sys.tables使用适当的USE语句为每个数据库进行查询,或者通过显式使用数据库的三部分语法{database}.sys.tables进行查询。

一种方法是查询所有数据库,并在这样做时聚合查询sys.tables该数据库的字符串。由于您没有指定 SQL Server 的版本,我将使用STRING_AGG()SQL Server 2017 中现在可用的功能。在早期的 SQL Server 版本上,您可以使用您选择的方法,例如(官方未记录和不支持的)用于@DynamicSQL您的问题的变量连接。

-- Print the first 8,000 bytes of TRUNCATE TABLE statements for each database
-- (Comment out the PRINT and enable the EXEC if you want to execute)
DECLARE @sql NVARCHAR(MAX) = ''
SELECT @sql = 'DECLARE @truncateTableSql NVARCHAR(MAX)
        ' + STRING_AGG('
        USE ' + CONVERT(NVARCHAR(MAX), QUOTENAME(name)) + '
        SET @truncateTableSql = NULL
        SELECT @truncateTableSql = STRING_AGG(
            CONVERT(NVARCHAR(MAX),''TRUNCATE TABLE '') +
            QUOTENAME(DB_NAME()) + ''.'' +
            QUOTENAME(SCHEMA_NAME(schema_id)) + ''.'' +
            QUOTENAME(name), 
            CHAR(10))
        FROM sys.tables
        WHERE is_ms_shipped = 0 /* Avoid Microsoft-provided tables */
            AND name LIKE ''log%''
        -- Note that PRINT will truncate the string to the first 8,000 bytes
        PRINT(@truncateTableSql)
        --EXEC(@truncateTableSql)
    ', CHAR(10))
FROM sys.databases
WHERE state = 0 /* ONLINE */
    AND is_read_only = 0
    AND name NOT IN ('master','model','msdb','tempdb')

EXEC(@sql)
Run Code Online (Sandbox Code Playgroud)

跨数据库的单个表的简化查询

更新听起来好像只有dbo.log表需要被截断。如果您只需要定位具有已知名称的单个表,则可以大大简化脚本。例如:

-- Print the first 8,000 bytes of TRUNCATE TABLE statements
-- (Comment out the PRINT and enable the EXEC if you want to execute)
DECLARE @sql NVARCHAR(MAX) = ''
SELECT @sql = STRING_AGG('TRUNCATE TABLE ' + QUOTENAME(name) + '.dbo.log', CHAR(10))
FROM sys.databases
WHERE state = 0 /* ONLINE */
    AND is_read_only = 0
    AND name NOT IN ('master','model','msdb','tempdb')
    AND OBJECT_ID(name + '.dbo.log') IS NOT NULL
PRINT(@sql)
--EXEC(@sql)
Run Code Online (Sandbox Code Playgroud)

在早期版本的 SQL Server 中跨数据库的单个表的简化查询

在 SQL Server 中有许多连接字符串的方法,许多博客文章探索并积极讨论这些选项。STRING_AGG()如果您使用的是 SQL Server 2017 或更高版本,我更喜欢,但如果您无法升级到 SQL Server 2017,则使用 XML 连接字符串是一种选择。例如:

-- Print the first 8,000 bytes of TRUNCATE TABLE statements
-- (Comment out the PRINT and enable the EXEC if you want to execute)
DECLARE @sql NVARCHAR(MAX) = ''
SELECT @sql = CONVERT(NVARCHAR(MAX), (
    SELECT CONVERT(NVARCHAR(MAX), 'TRUNCATE TABLE ') + QUOTENAME(name) + '.dbo.log; '
    FROM sys.databases
        WHERE state = 0 /* ONLINE */
        AND is_read_only = 0
        AND name NOT IN ('master','model','msdb','tempdb')
        AND OBJECT_ID(name + '.dbo.log') IS NOT NULL 
    FOR XML PATH('')
))
PRINT(@sql)
--EXEC(@sql)
Run Code Online (Sandbox Code Playgroud)