如果列存在则条件 WHERE

cam*_*ech 2 sql-server t-sql

我有几个表,通常具有可为空的“CreatedDate”和/或“ModifiedDate”日期时间列。我想要一个查询,可以从任何单个表中进行选择,其中一个、两个或都不存在日期时间列,并且每列都BETWEEN提供(单独的)范围。

这是一个粗略的(非工作的)示例。这尝试用来COL_LENGTH确定列是否存在。但是,如果一列不存在,则会引发错误,我相信是因为WHERE仍在评估整个列。

SELECT * FROM tableName
WHERE 1=1 AND
(COL_LENGTH(tableName, 'CreatedDate') IS NULL OR CreatedDate BETWEEN @CreatedFrom AND @CreatedTo) AND
(COL_LENGTH(tableName, 'ModifiedDate') IS NULL OR ModifiedDate BETWEEN @ModifiedFrom AND @ModifiedTo)
Run Code Online (Sandbox Code Playgroud)

这可以通过动态 SQL 来解决。但是,在这种情况下,我仅限于以读取为中心的权限。所以没有 EXEC、CREATE 或 INSERT。

这可以用静态 SQL 实现吗?

示例表

两列:

DECLARE @Table1 table
(
    Id int NOT NULL,
    CreatedDate datetime NULL,
    ModifiedDate datetime NULL
);

INSERT @Table1
    (Id, CreatedDate, ModifiedDate)
VALUES
    (1, NULL, NULL),
    (2, NULL, '20230101 01:23:45.678'),
    (3, '20230101 02:34:56.789', NULL),
    (4, '20230101 03:45:00.891', '20230101 04:56:00.789');

DECLARE 
    @CreatedFrom datetime = {TS '2023-01-01 01:30:00.000'},
    @CreatedTo datetime = {TS '2023-12-31 23:30:00.000'},
    @ModifiedFrom datetime = {TS '2023-01-01 06:00:00.000'},
    @ModifiedTo datetime = {TS '2023-12-31 18:00:00.000'};
Run Code Online (Sandbox Code Playgroud)

用一列:

DECLARE @Table2 table
(
    Id int NOT NULL,
    CreatedDate datetime NULL
);

INSERT @Table2
    (Id, CreatedDate)
VALUES
    (1, NULL),
    (2, '20230101 02:34:56.789');

DECLARE 
    @CreatedFrom datetime = {TS '2023-01-01 01:30:00.000'},
    @CreatedTo datetime = {TS '2023-12-31 23:30:00.000'};
Run Code Online (Sandbox Code Playgroud)

感谢@PaulWhite 提供的最初示例

ype*_*eᵀᴹ 6

是的,这个棘手的问题可以用简单的 SQL 来解决,方法是相当晦涩难懂。

有关更详细的解释和最初的想法,请参阅 Andriy M 和我在两个类似问题中的答案:
为什么我不能使用 case 语句来查看列是否存在而不是从中进行选择?
如果列存在,如何选择特定行;如果列不存在,如何选择所有行

在你的情况下 - 以及假设

  • 两列(当它们存在时)不可为空并且
  • 当没有任何列存在时,我们想要返回所有行
  • 当两列之一存在时,我们仅对该列应用条件

这会起作用:

SELECT x.*
FROM 
    ( SELECT NULL AS CreatedDate,
             NULL AS ModifiedDate
    ) AS dummy
  CROSS APPLY
    ( SELECT t.*
      FROM dbo.tableName AS t
      WHERE ( CreatedDate BETWEEN @Date1 AND @Date2    -- the columns should
           OR CreatedDate IS NULL )                    -- be referenced
        AND ( ModifiedDate BETWEEN @Date3 AND @Date4   -- WITHOUT
           OR ModifiedDate IS NULL )                   -- a table prefix here
    ) AS x ;
Run Code Online (Sandbox Code Playgroud)