如何缩短 T-SQL 中的 WHERE 子句

Posted

技术标签:

【中文标题】如何缩短 T-SQL 中的 WHERE 子句【英文标题】:How to shorten WHERE clause in T-SQL 【发布时间】:2021-12-27 13:53:14 【问题描述】:

我正在 SQL Server 2019 中为我的数据库编写以下视图,它工作正常。我觉得我的WHERE 子句太长了,也许你写的更短的子句会满足我的需要。 WHERE 子句也可以很好地过滤视图。这似乎太新手了,因此任何高级解决方案都值得赞赏。

CREATE VIEW dbo.View1 
AS 
    SELECT
        Table1.QNO,
        Table1.QRevNO,
        Table1.QID,
        Table1.LStatus AS Status,
        Table1.StatusCode AS [Status Code],
        CASE
            WHEN Table1.IsProject = 1 THEN 'Goods'
            WHEN Table1.IsProject = 2 THEN 'Services'
            ELSE 'Project'
        END AS [Product Type],
        Table2.ProductGroup AS [Group],
        Table2.TotalOfItem AS [Sales],
        Table3.CompanyName AS [Customer]
    FROM 
        dbo.Table1
    INNER JOIN 
        dbo.Table2 ON Table1.QID = Table2.QID
    INNER JOIN 
        dbo.Table3 ON Table3.CompanyID = Table1.CompanyID
    WHERE 
        Table1.RevActivated = 1
        AND ((DATEPART(YEAR, Table1.ORDate) = DATEPART(YEAR, GETDATE())
             OR (DATEPART(YEAR, Table1.PIDate) = DATEPART(YEAR, GETDATE())
        AND Table1.ORDate IS NULL)
             OR (DATEPART(YEAR, Table1.PODate) = DATEPART(YEAR, GETDATE())
        AND Table1.ORDate IS NULL
        AND Table1.PIDate IS NULL)
    OR (DATEPART(YEAR, Table1.BADate) = DATEPART(YEAR, GETDATE())
      AND Table1.ORDate IS NULL
      AND Table1.PIDate IS NULL
      AND Table1.PODate IS NULL)
    OR (DATEPART(YEAR, Table1.OCDate) = DATEPART(YEAR, GETDATE())
      AND Table1.ORDate IS NULL
      AND Table1.PIDate IS NULL
      AND Table1.PODate IS NULL
      AND Table1.BADate IS NULL)
    OR (DATEPART(YEAR, Table1.ShipDate) = DATEPART(YEAR, GETDATE())
      AND Table1.ORDate IS NULL
      AND Table1.PIDate IS NULL
      AND Table1.PODate IS NULL
      AND Table1.BADate IS NULL
      AND Table1.OCDate IS NULL)
    OR (DATEPART(YEAR, Table1.INVDate) = DATEPART(YEAR, GETDATE())
      AND Table1.ORDate IS NULL
      AND Table1.PIDate IS NULL
      AND Table1.PODate IS NULL
      AND Table1.BADate IS NULL
      AND Table1.OCDate IS NULL
      AND Table1.ShipDate IS NULL)
    OR (DATEPART(YEAR, Table1.PDDate) = DATEPART(YEAR, GETDATE())
      AND Table1.ORDate IS NULL
      AND Table1.PIDate IS NULL
      AND Table1.PODate IS NULL
      AND Table1.BADate IS NULL
      AND Table1.OCDate IS NULL
      AND Table1.ShipDate IS NULL
      AND Table1.INVDate IS NULL)))
GO

【问题讨论】:

似乎你有一个非规范化问题:你不应该有七个相似的日期列,而是你想要一个单独的事件表(外键为Table1),然后你可以做一个简单加入或exists 仅供参考,在WHERE 的列上使用DATEPART 之类的内容会导致您的查询不可搜索,从而导致性能下降。不是检查年份,而是检查日期是否在包含全年的日期范围内。例如>= '2021-01-01'< '2022-01'01' 【参考方案1】:

在 SQL 中,更紧凑的代码不一定是更好的代码。虽然以下内容可能更容易阅读:

...
WHERE t1.RevActivated = 1
  and coalesce(
    t1.ORDate,
    t1.PIDate,
    t1.PODate,
    t1.BADate,
    t1.OCDate,
    t1.ShipDate,
    t1.INVDate,
    t1.PDDate
  ) >= datefromparts(year(getdate()), 1, 1)
  and coalesce(
    t1.ORDate,
    t1.PIDate,
    t1.PODate,
    t1.BADate,
    t1.OCDate,
    t1.ShipDate,
    t1.INVDate,
    t1.PDDate
  ) < datefromparts(year(getdate()) + 1, 1, 1);

其中t1 是alias 的dbo.Table1 表。

即使在您的表格大小超过 Excel 电子表格支持的行数之后,要让这种混乱运行得足够快,这并不容易。您可以尝试使用包含所有 8 个 XyzDate 列的索引,其顺序与您的代码优先考虑它们的顺序完全相同。更好的方法是规范化您的数据模型,而不是使用数据源(当然,除非这不是 DWH)。

【讨论】:

以上是关于如何缩短 T-SQL 中的 WHERE 子句的主要内容,如果未能解决你的问题,请参考以下文章

关于 Where 子句的 T-Sql 多重标准

在t-sql中,子查询只能放在where子句中吗

测试 T-SQL 中的不等式

如何修复程序中的“歧义”where子句

如何修复where子句中的聚合?

如何正确分组 Laravel Query Builder 中的 where 子句