SQL Server 从所有表的所有日期时间列中获取最高日期

问题描述 投票:0回答:1

我有一堆表,有些表有日期时间列,有些则没有。对于包含日期时间列的所有表,我想找到最大值并输出它。到目前为止我所做的是:

DECLARE @AllTables TABLE(TableNumber INT, TableName NVARCHAR(255))
DECLARE @AllColumns TABLE(ColumnNumber INT, ColumnName NVARCHAR(255), TableName NVARCHAR(255))
DECLARE @OrderedColumns TABLE(EntryNumber INT, ColumnName NVARCHAR(255), TableName NVARCHAR(255))
DECLARE @I INT = 1
DECLARE @J INT = 1
DECLARE @TableCount INT
DECLARE @ColumnCount INT
DECLARE @CurrentTableName NVARCHAR(255)
DECLARE @CurrentColumnName NVARCHAR(255)
DECLARE @HighestDate DATETIME
DECLARE @TotalHighestDate DATETIME = '1970-01-01'
DECLARE @SQL NVARCHAR(MAX)
DECLARE @CurrentDate DATETIME = CURRENT_TIMESTAMP

--List all relevant tables
INSERT INTO @AllTables
    SELECT ROW_NUMBER() OVER(ORDER BY TABLE_NAME) AS Row, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
    WHERE TABLE_NAME LIKE 'XYZ%' AND TABLE_TYPE = 'BASE TABLE'

SET @TableCount = (SELECT COUNT(*) FROM @AllTables)

--Loop through all the tables and get the column names for datetime columns
WHILE @I <= @TableCount
BEGIN
    SET @CurrentTableName = (SELECT TableName FROM @AllTables WHERE TableNumber = @I)
    INSERT INTO @AllColumns
        SELECT ROW_NUMBER() OVER(ORDER BY COLUMN_NAME) AS Row, COLUMN_NAME, TABLE_NAME FROM INFORMATION_SCHEMA.COLUMNS
        WHERE DATA_TYPE LIKE 'datetime%' AND TABLE_NAME = @CurrentTableName
    SET @I = @I + 1
END

--Order the columns so they can be looped through
INSERT INTO @OrderedColumns
    SELECT ROW_NUMBER() OVER(ORDER BY TableName,ColumnName) AS Row, ColumnName, TableName FROM @AllColumns

SET @ColumnCount = (SELECT COUNT(*) FROM @OrderedColumns)

--Get the highest date for each column and update the total highest date if the date we found is higher than the current record holder
WHILE @J <= @ColumnCount
BEGIN
    SET @CurrentColumnName = (SELECT ColumnName FROM @OrderedColumns WHERE EntryNumber = @J)
    SET @CurrentTableName = (SELECT TableName FROM @OrderedColumns WHERE EntryNumber = @J)
    SET @SQL = 'SELECT @HighestDateOUTPUT = MAX(' + @CurrentColumnName + ') FROM [dbo].[' + @CurrentTableName +']'
    EXECUTE sp_executesql @SQL,N'@HighestDateOUTPUT DATETIME OUTPUT',@HighestDateOUTPUT = @HighestDate OUTPUT

    --Ignore any results that are in the future, that data is incorrect and should be fixed at the source, not here
    IF (@HighestDate > @TotalHighestDate AND @TotalHighestDate < @CurrentDate AND @HighestDate < @CurrentDate)
    BEGIN
        SET @TotalHighestDate = @HighestDate
    END
    SET @J = @J + 1
END

PRINT @TotalHighestDate

这运行良好并正确输出所有列中的最高日期。问题是,当我将其作为存储过程运行时,过程是

CREATE OR ALTER PROCEDURE [dbo].[MyHighestDateProcedure]

    AS
    BEGIN
        -- SET NOCOUNT ON added to prevent extra result sets from interfering with SELECT statements.
        SET NOCOUNT ON;
        ...
        --The above code block
        ...
    END

失败并出现错误

Msg 156, Level 15, State 1, Line 3
Incorrect syntax near the keyword 'AS'.

大约四分之一的人会尝试它正确运行,但这是奇怪的部分。我的同事说“在存储过程中使用动态 sql 是一场噩梦,你在玩火,sql 缓存执行计划这可能是这些东西的问题”所以如果我的方法可以通过避免动态 SQL 来改进那么我是所有的耳朵。

编辑:澄清一下,我想从所有不同的日期时间列中找到单个最高日期,而不是每列的最高日期,结果应该是一个日期时间输出。

sql-server stored-procedures dynamic-sql sql-server-2019
1个回答
1
投票

很可能是因为列名包含空格或特殊字符。您可以在列名上使用

quotename()
来处理这种情况

将动态查询更改为

SET @SQL = 'SELECT @HighestDateOUTPUT = MAX(' + quotename(@CurrentColumnName) + ') FROM [dbo].[' + @CurrentTableName +']'.
© www.soinside.com 2019 - 2024. All rights reserved.