简体   繁体   English

如何使用动态 SQL 在 Azure Synapse 中的表列表上循环 SELECT 语句?

[英]How to loop a SELECT statement on a list of tables in Azure Synapse using Dynamic SQL?

I often have to find out what is the latest date of a record count of multiple tables.我经常需要找出多个表的记录计数的最新日期。 Currently I'm trying to find out the maximum loaddate from a list of tables.目前我正在尝试从表列表中找出最大加载日期。

I have the below list of example tables:我有以下示例表列表:

TableA
TableB
TableC
TableD

So far I'm able to declare a variable and pass the single table name as a parameter into my SQL statemen as follows:到目前为止,我能够声明一个变量并将单个表名作为参数传递到我的 SQL 状态表中,如下所示:

DECLARE @SQLstmnt varchar(500)
 
DECLARE @tname varchar(200)
SET @tname = 'TableA'
 
SET @SQLstmnt = 'SELECT MAX(loaddate) FROM ' + @tname
 
EXEC (@SQLstmnt)

But I don't know how to pass my entire table name list (TableA, TableB, TableC, TableD) and loop the above SELECT statement on each of those tables in the list.但我不知道如何传递我的整个表名列表(TableA, TableB, TableC, TableD)并在列表中的每个表上循环上面的 SELECT 语句。

I searched for a solution but I just don't seem to find the one that suits my case.我搜索了一种解决方案,但我似乎找不到适合我的情况的解决方案。

Can someone please help?有人可以帮忙吗?

You could build a dynamic union query for all tables and execute it this way:您可以为所有表构建一个动态联合查询并以这种方式执行它:

DECLARE @SQL NVARCHAR(MAX);
SELECT  @SQL = CONCAT('SELECT TableName, Date FROM (',
                STRING_AGG(CONCAT('SELECT TableName = ''', t.Name, ''',  Date = MAX(', c.name, ') 
                                  FROM ', QUOTENAME(s.name), '.', QUOTENAME(t.name)), ' UNION ALL '),
                ') AS t;')
FROM    sys.columns AS c
        INNER JOIN sys.tables AS t
            ON t.object_id = c.object_id
        INNER JOIN sys.schemas AS s
            ON s.schema_id = t.schema_id
WHERE   c.name = 'LoadDate' -- Check Column Exists
AND     t.name IN ('TableA', 'TableB', 'TableC', 'TableD') -- Limit to required tables;
HAVING COUNT(*) > 0

PRINT @sql
EXECUTE sp_executesql @SQL;

This will build a SQL Statement something like this for your example:这将为您的示例构建一个类似这样的 SQL 语句:

SELECT TableName, Date 
FROM (SELECT TableName = 'TableA',  Date = MAX(LoadDate) FROM dbo.TableA
     UNION ALL 
     SELECT TableName = 'TableB',  Date = MAX(LoadDate) FROM dbo.TableB
     UNION ALL
     SELECT TableName = 'TableC',  Date = MAX(LoadDate) FROM dbo.TableC
     UNION ALL
     SELECT TableName = 'TableD',  Date = MAX(LoadDate) FROM dbo.TableD
    ) AS t;

And return all tables/dates as a single set:并将所有表/日期作为一个集合返回:

If you really did want to iterate over the tables then I would still use the system views as a starting to point to verify that (a) the table exists and (b) contains the load date column, but use a CURSOR to execute the statement against each table rather than building a single statement:如果您真的想遍历表,那么我仍然会使用系统视图作为起点来验证 (a) 表是否存在并且 (b) 包含加载日期列,但使用CURSOR来执行语句针对每个表而不是构建单个语句:

DECLARE TableCursor CURSOR LOCAL STATIC FORWARD_ONLY READ_ONLY
FOR
    SELECT  CONCAT(QUOTENAME(s.name), '.', QUOTENAME(t.name))
    FROM    sys.columns AS c
            INNER JOIN sys.tables AS t
                ON t.object_id = c.object_id
            INNER JOIN sys.schemas AS s
                ON s.schema_id = t.schema_id
    WHERE   c.name = 'LoadDate'
    AND     t.name IN ('TableA', 'TableB', 'TableC', 'TableD') -- Limit to required tables;

DECLARE @TableName SYSNAME;
OPEN TableCursor;
FETCH NEXT FROM TableCursor INTO @TableName;

WHILE @@FETCH_STATUS = 0
BEGIN
    DECLARE @SQL NVARCHAR(MAX) = CONCAT('SELECT TableName = ''', @TableName, ''', Date = MAX(LoadDate) FROM ', @TableName);

    EXECUTE sp_executesql @SQL;
    FETCH NEXT FROM TableCursor INTO @TableName;

END

CLOSE TableCursor;
DEALLOCATE TableCursor;

Super simple... just use a WHILE loop超级简单...只需使用一个WHILE循环

DECLARE @MyTable TABLE ([Name] varchar(256), Done bit default(0));

INSERT INTO @MyTable ([Name])
VALUES
('TableA'),
('TableB'),
('TableC'),
('TableD');

DECLARE @SQLstmnt nvarchar(max), @tname varchar(200);

WHILE EXISTS (SELECT 1 FROM @MyTable WHERE Done = 0) BEGIN
    SELECT TOP 1 @tname = [Name]
    FROM @MyTable
    WHERE Done = 0;
  
    SET @SQLstmnt = 'SELECT MAX(loaddate) FROM ' + @tname + ';';
 
    -- This is the best practice way to execute dynamic SQL
    -- EXEC sp_executesql @SQLstmnt;
    -- Debug the dynamic SQL
    PRINT(@SQLstmnt);

    UPDATE @MyTable SET Done = 1 WHERE [Name] = @tname;
END;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM