Sql 如何在多个表中获取日期列的最大日期值

Sql 如何在多个表中获取日期列的最大日期值,sql,sql-server,Sql,Sql Server,例如,我在数据库中有两个表。 前任: 表T: declare @t table (name varchar(20),DOB date) Insert into @t (name,DOB) values ('Mohan','2001-07-19') Insert into @t (name,DOB) values ('Minu','1998-06-19') 表:TT declare @tt table (name varchar(20),DOB date) Insert into @tt (na

例如,我在数据库中有两个表。 前任: 表T:

declare @t table (name varchar(20),DOB date)
Insert into @t (name,DOB) values ('Mohan','2001-07-19')
Insert into @t (name,DOB) values ('Minu','1998-06-19')
表:TT

declare @tt table (name varchar(20),DOB date)
Insert into @tt (name,DOB) values ('Raju','2010-07-19')
Insert into @tt (name,DOB) values ('Rani','2001-06-19')
现在我有了一个查询,可以根据日期类型过滤器获取多个表的表名和列名

SELECT   C.TABLE_SCHEMA, c.TABLE_NAME,c.COLUMN_NAME
FROM     INFORMATION_SCHEMA.COLUMNS c 
         JOIN sys.objects o ON o.name = c.TABLE_NAME   
WHERE    o.type = 'U' AND C.DATA_TYPE = 'Datetime'
输出:

T_Schema    T_name T_column
  dbo         T      DOB   
  dbo         TT     DOB
但如何获得两个表的最大日期,如以下输出:

  T_Schema  T_name T_column  Max_dt
  dbo         T      DOB     2001-07-19
  dbo         TT     DOB     2010-07-19

建议我实现这一点的最佳方法。

这里有一些动态SQL,可以通过光标实现您想要的功能

如果您有很多表,或者先在测试中运行这个,我会警告您使用它。一般来说,游标不是很好的执行器。您可以对系统数据库(如master)运行此操作,因为它的值较少,无法查看其工作方式

create table #MaxDate (tname varchar(256), cname varchar(256), mdate datetime)

declare cur cursor local fast_forward
for 
    SELECT   C.TABLE_SCHEMA, c.TABLE_NAME,c.COLUMN_NAME
    FROM     INFORMATION_SCHEMA.COLUMNS c 
             JOIN sys.objects o ON o.name = c.TABLE_NAME   
    WHERE    o.type = 'U' AND C.DATA_TYPE = 'Datetime'

declare @schema varchar(64), @table varchar(256), @column varchar(256)
declare @sql varchar(max)

open cur
fetch next from cur into @schema, @table, @column 
while @@FETCH_STATUS = 0

begin
    set @sql = 'select ''' + @table + '''' + ',''' + '' + @column + '''' + ',' +  'max(' + @column + ') from ' + @schema + '.' + @table
    print @sql

    insert into #MaxDate
    exec (@sql)
    fetch next from cur into @schema, @table, @column
end

close cur
deallocate cur

select * from #MaxDate
drop table #MaxDate

下面是一个使用游标、动态SQL和临时表的答案:

DECLARE table_cursor CURSOR LOCAL FAST_FORWARD FOR
SELECT
    C.TABLE_SCHEMA,
    c.TABLE_NAME,
    c.COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS c
JOIN sys.objects o
    ON o.name = c.TABLE_NAME
WHERE o.type = 'U'
AND C.DATA_TYPE = 'Datetime'

DECLARE @schema SYSNAME
DECLARE @table SYSNAME
DECLARE @column SYSNAME
DECLARE @sql NVARCHAR(1000)

CREATE TABLE #Data (SchemaName SYSNAME, TableName SYSNAME, ColumnName SYSNAME, MaxDate DATETIME)

OPEN table_cursor
FETCH NEXT FROM table_cursor INTO @schema, @table, @column

WHILE @@FETCH_STATUS = 0
BEGIN
    SET @sql = 'INSERT INTO #Data (SchemaName, TableName, ColumnName, MaxDate) SELECT '''+@schema+''', '''+@table+''', '''+@column+''', MAX(['+@column+']) FROM ['+@schema+'].['+@table+']'
    EXEC sp_executesql @sql

    FETCH NEXT FROM table_cursor INTO @schema, @table, @column
END

CLOSE table_cursor
DEALLOCATE table_cursor

SELECT * FROM #Data
DROP TABLE #Data

SQL为您构建SQL

DECLARE @SQL as nvarchar(max) ='';
select @SQL = @SQL + 'SELECT ' + Column_Name + ' adate, ''' + Column_Name + ''' colname, ''' + Table_name + ''' tabname  FROM ' +  Table_name + ' UNION ' FROM   INFORMATION_SCHEMA.COLUMNS where data_type like '%date%'
select @SQL = 'SELECT TOP 100 * FROM (' + LEFT(@SQL, LEN(@SQL) -6) + ') IQ  WHERE IQ.adate IS NOT null ORDER BY IQ.adate DESC';

 --cut n paste the sql below, see what it does for you
select @SQL
mark II—为您执行sql,并用空格对名称进行排序

DECLARE @SQL as nvarchar(max) ='';
select @SQL = @SQL + 'SELECT [' + Column_Name + '] adate, ''' + Column_Name + ''' colname, ''' + Table_name + ''' tabname  FROM [' +  Table_name + '] UNION ' FROM   INFORMATION_SCHEMA.COLUMNS where data_type like '%date%'
select @SQL = 'SELECT TOP 100 * FROM (' + LEFT(@SQL, LEN(@SQL) -6) + ') IQ  WHERE IQ.adate IS NOT null ORDER BY IQ.adate DESC';

select @SQL;
EXEC sp_executesql @sql;

这里还有一个不使用光标的选项。从性能的角度来看,我怀疑它是否会更好,因为您仍然需要为每一行提供一个子查询。但我真的很讨厌诅咒者。我还使用了系统表而不是信息模式视图,因为这些视图有时可能有点奇怪


@RyanWilson问题是如何动态执行,即查询所有表关于某个动态SQL?因此,您希望为数据库中的每个datetime列返回一行,该行为您提供架构、表名、列名和最大日期?基本上,您所拥有的查询将获得99%,您只需将其设置为动态sql,就可以了。您可以友好地构建一个查询字符串并执行它。我最好为此创建一个存储过程@ZorgoZ为什么存储过程是一种更好的方法?这里的版本更好,因为您在变量上使用了sysname:Dapart from cursor any otherway@scsimon不知道我把sysname从哪里拖过来的,一些来自许多卫星的被压抑的记忆@mohan111 Sean Lange说他将发布一个没有光标的方法。。。它可能会有一个while循环或一个递归CTE。@mohan111有什么区别?虽然循环、游标、动态构造的联合——它们都是相同的,但您必须将读取多个表的结果汇总在一起。呃……让我来修复大小写。我通常比那更好。特别是因为我们最大的系统使用了区分大小写的环境。尽管内置函数名不区分大小写,即使是在区分大小写的排序规则中也是如此。但是否从内存中删除?我过去非常喜欢将其用作基本排序规则,让您保持警觉。@DavidG这是我们ERP使用的排序规则。仍然不关心内置函数名的大小写敏感度。但它确实让事情变得有趣。
declare @SQL nvarchar(max) = N''

select @SQL = @SQL + 
    N'select SCHEMA_NAME = ''' + QUOTENAME(s.name) + ''', TABLE_NAME = ''' 
        + QUOTENAME(o.name) + ''', COLUMN_NAME = '''
        + QUOTENAME(c.name) + ''', MaxDate = '
        + '(select MAX(' + QUOTENAME(c.name) + ') from  ' + QUOTENAME(s.name) + '.' + QUOTENAME(o.name) + ') UNION ALL '
from sys.columns c
join sys.systypes st on st.type = c.system_type_id
join sys.objects o on o.object_id = c.object_id and o.type = 'U'
join sys.schemas s on s.schema_id = o.schema_id
where st.name = 'datetime'
order by s.name
    , o.name
    , c.name

set @SQL = left(@SQL, len(@SQL) - 10) --removes final UNION ALL

select @SQL

--uncomment below when you are satisfied the dynamic sql is correct
--exec sp_executesql @SQL