【问题标题】:How to avoid function repetition in SELECT, GROUP BY, and ORDER BY in SQL如何避免 SQL 中 SELECT、GROUP BY 和 ORDER BY 中的函数重复
【发布时间】:2021-11-01 13:50:50
【问题描述】:

我正在编写一个统计查询,其中值在SELECTGROUP BYORDER BY 中重复。必须重复相同的值使得读取和修改查询变得困难。

如何避免在下面的查询中重复FLOOR(COALESCE(LEN(Body), 0) / 100) 3-4 次。

SELECT FLOOR(COALESCE(LEN(Body), 0) / 100) * 100 as BodyLengthStart,
    (FLOOR(COALESCE(LEN(Body), 0) / 100) + 1) * 100 - 1 as BodyLengthEnd,
    COUNT(*) as MessageCount
FROM [Message]
GROUP BY FLOOR(COALESCE(LEN(Body), 0) / 100)
ORDER BY FLOOR(COALESCE(LEN(Body), 0) / 100)

查询的输出是消息的数量,由它们拥有的数百个字符组成。

BodyLengthStart BodyLengthEnd MessageCount
0 99 130
100 199 76
200 299 36

【问题讨论】:

  • 如果可能,请提供少量样本数据和预期输出。
  • 交叉申请....

标签: sql sql-server tsql dry


【解决方案1】:

一个选项可能是 CTE(通用表表达式),类似于以下内容:

WITH x AS
(
    SELECT FLOOR(COALESCE(LEN(Body), 0) / 100) AS BodyLength
    FROM [Message]
)
SELECT BodyLength * 100 AS BodyLengthStart,
       (BodyLength + 1) * 100 - 1 AS BodyLengthEnd,
       COUNT(*) as MessageCount
FROM x
GROUP BY BodyLength
ORDER BY BodyLength 

附带说明 - 如果在此之前的语句不以分号 (;) 结尾,这将无法按预期工作。

【讨论】:

    【解决方案2】:

    使用交叉应用

    SELECT  BodyLengthStart,
            BodyLengthEnd,
            COUNT(*)
    FROM  [Message]
    CROSS APPLY (
       VALUES 
          (FLOOR(COALESCE(LEN(Body), 0) / 100)) 
       ) a1(v)
    CROSS APPLY (
       VALUES
          (v * 100, (v + 1) * 100 - 1)
       ) a2(BodyLengthStart, BodyLengthEnd)
    GROUP BY BodyLengthStart,
             BodyLengthEnd
    

    【讨论】:

    • SELECT 中没有完成第二个交叉应用的转换是否有原因?
    • @Redline, .. 绝对可以在select 中完成。只是想展示第二个cross apply 如何使用前一个的结果。
    【解决方案3】:

    使用子选择:

    SELECT  BodyLengthStart,
            BodyLengthEnd,
            COUNT(*)
    FROM (SELECT FLOOR(COALESCE(LEN(Body), 0) / 100) * 100 as BodyLengthStart,
                (FLOOR(COALESCE(LEN(Body), 0) / 100) + 1) * 100 - 1 as BodyLengthEnd
            FROM [Message]) as a
    GROUP BY BodyLengthStart,
             BodyLengthEnd
    

    你可以在FROM之后定义一个SELECT;通过这种方式,您可以预先详细说明您的数据。

    【讨论】:

    • 又名派生表.
    【解决方案4】:

    您可以使用公用表表达式:

    WITH cte AS 
    (
    SELECT FLOOR(COALESCE(LEN(Body), 0) / 100) * 100 as BodyLengthStart,
        (FLOOR(COALESCE(LEN(Body), 0) / 100) + 1) * 100 - 1 as BodyLengthEnd
    FROM [Message]
    )
    SELECT BodyLengthStart,BodyLengthEnd,COUNT(*)
    FROM cte
    GROUP BY BodyLengthStart,BodyLengthEnd
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-20
      • 1970-01-01
      相关资源
      最近更新 更多