使用 MS SQL 服务器搜索具有已知值范围的 table 和列名称

Search table and column names having some known range of values using MS SQL server

环境:SQL Server 2016 (v13.00.4259),其中我有只读权限(基本上只是来自多个 table 的 SELECT)。

用例:我想从数据库中查找所有 table 和列名,其中列类型为 datetime 并且列名中包含 %END%,并且任何发现值(在 table.column 中)介于某个时间范围(在本例中为一天)之间。

我可以使用以下命令从数据库中找到所有 table 和列名:

SELECT TABLE_NAME as tab, COLUMN_NAME as col
FROM INFORMATION_SCHEMA.COLUMNS
WHERE DATA_TYPE = 'datetime' and COLUMN_NAME like '%END%';

我想我需要一个动态查询,因为 table 和列名在静态 SQL 查询中应该是静态的,所以:

WITH enddates AS 
(
    SELECT TABLE_NAME AS tab, COLUMN_NAME AS col
    FROM INFORMATION_SCHEMA.COLUMNS
    WHERE DATA_TYPE = 'datetime' AND  COLUMN_NAME LIKE '%END%'
)
exec('select tab, col 
      from enddates
      where ' + tab + '.' + col + ' >= ''2019-10-21'' and ' 
        + tab + '.' + col + '< ''2019-10-22'' ')

  -- would want it to eval to:
  -- SELECT tab, col FROM enddates 
  -- WHERE $tab.$col >= '2019-10-21' AND $tab.$col < '2019-10-22'

想要获取 table 和列名称的列表,其中某些 %END% 日期时间在 2019-10-21。

但是不行:

"SQL Error [156] [S1000]: Incorrect syntax near the keyword 'exec'."

一个原因可能是,EXEC 中没有看到子查询的 'enddates' 别名,但我认为这不是唯一的问题。为了清楚起见,我认为它显示了我所追求的。

我更多地使用 PostgreSQL,但现在我需要从具有只读访问权限的 SQL 服务器检索此类数据,因此不能在那里制作玩具数据 tables去测试,也没有意见。当然首先创建一个 table 那些有趣的 table.column 对并避免需要子查询会更简单。但是我不知道如何从那些 table 和列名然后在 SQL 服务器中进行动态查询。

编辑:另一个语义上更正确的 "pseudo-code" 想法,使用之前的 WITH-子查询:

SELECT tab, col 
FROM enddates 
WHERE EXEC('select ' + tab + '.' + col + ' >= ''2019-10-21'' and ' + tab + '.' + col + ' < ''2019-10-22''') = True

一种可能的方法是生成并执行动态语句:

-- Dynamic statement
DECLARE @stm nvarchar(max) = N''

SELECT @stm = CONCAT(
    @stm,
    CASE WHEN @stm = N'' THEN N'' ELSE N' UNION ALL ' END,
    N'SELECT ''',
    QUOTENAME(TABLE_NAME),
    N''' AS Tab, ''',
    QUOTENAME(COLUMN_NAME),
    N''' AS Col, COUNT(*) AS Cnt FROM ',
    QUOTENAME(TABLE_NAME),
    N' WHERE ',
    QUOTENAME(COLUMN_NAME),
    N' >= ''20191021'' AND ',
    QUOTENAME(COLUMN_NAME),
    N' < ''20191022'' ',
    N'HAVING COUNT(*) > 0'
)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE DATA_TYPE = 'datetime' and COLUMN_NAME LIKE '%END%'

-- Validate and execute
PRINT @stm
EXEC sp_executesql @stm