【问题标题】:SQL: How to add GROUP BY/ORDER BY clauses in a query with an enclosed case statementSQL:如何在包含 case 语句的查询中添加 GROUP BY/ORDER BY 子句
【发布时间】:2020-01-21 21:13:09
【问题描述】:
SELECT DISTINCT *
FROM 
    (SELECT dbtables.[name] as 'back_end_name', 
            CASE
                WHEN dbtables.[name] LIKE '_Result%' AND CAST(RIGHT(dbtables.[name], LEN(dbtables.[name]) - 7) AS int) = CalculationID
                THEN Calculation.Name
                WHEN dbtables.[name] LIKE '_History%' 
                THEN
                    CASE
                        WHEN LEN(dbtables.[name]) = 9 AND CAST(RIGHT(dbtables.[name], 1) AS int) = HistoryID
                        THEN HistoryMap.TableName
                        WHEN LEN(dbtables.[name]) = 10 AND CAST(RIGHT(dbtables.[name], 2) AS int) = HistoryID
                        THEN HistoryMap.TableName
                        WHEN LEN(dbtables.[name]) = 11 AND CAST(RIGHT(dbtables.[name], 3) AS int) = HistoryID
                        THEN HistoryMap.TableName
                        ELSE 'N/A'
                    END 
                ELSE 'N/A'
            END AS front_end_name,
            indexstats.avg_fragmentation_in_percent,
            indexstats.page_count,
            indexstats.record_count
        FROM Calculation, HistoryMap, sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL, NULL, 'Sampled') AS indexstats
        INNER JOIN sys.tables dbtables on dbtables.[object_id] = indexstats.[object_id]
        INNER JOIN sys.schemas dbschemas on dbtables.[schema_id] = dbschemas.[schema_id]
        INNER JOIN sys.indexes AS dbindexes ON dbindexes.[object_id] = indexstats.[object_id]
        AND indexstats.index_id = dbindexes.index_id
        WHERE indexstats.database_id = DB_ID() AND indexstats.avg_fragmentation_in_percent >= 30) tmp
WHERE front_end_name NOT LIKE '%N/A%'

我有以下有效的查询,但是当我只需要 1 个实例时,“front_end_name”中的一些数据重复,所以我在最后添加了“GROUP BY front_end_name”,但它返回错误“Column 'tmp.back_end_name ' 在选择列表中无效,因为它不包含在聚合函数或 GROUP BY 子句中”。为什么现在说 back_end_name?

当我在第一个 WHERE 子句之后添加 GROUP BY 时,在封闭查询的末尾,它说 front_end_name 是无效的列名。

另外,我想按 indexstats.avg_fragmentation_in_percent 排序。显然,我不能在查询的最后执行此操作,因为 indexstats 在封闭的查询中是本地的。当我尝试在封闭查询的末尾执行此操作时,它告诉我“ORDER BY 子句在视图、内联函数、派生表、子查询和公用表表达式中无效,除非还指定了 TOP、OFFSET 或 FOR XML 。”

关于如何将 GROUP BY front_end_name 和 ORDER BY indexstats.avg_fragmentation_in_percent 添加到现有查询的任何提示? SQL 还是很新的,所以我正在学习。我试图避免多次编写 case 语句。

谢谢!

【问题讨论】:

  • Edit 问题并通过发布相关的CREATE TABLE 语句向我们展示架构,该表的示例数据为INSERT INTO 语句,预期结果为表格文本,不要忘记标记您正在使用的 DBMS 及其版本。

标签: sql group-by subquery sql-order-by case


【解决方案1】:

不要简单地在任何地方添加GROUP BY 来删除重复项。这主要用于聚合目的。退后一步,想想你的需求。

  • 首先,问问自己:当 front_end_name 重复时,其他列(back_end_nameavg_fragmentation_in_percentpage_countrecord_count)是否重复也重复?由于您的外部查询使用DISTINCT,因此它们可能不会重复。

  • 现在,考虑一下您的数据。如何处理每个重复front_end_name 的非重复列?这可能是由于连接表的粒度所致,CalculationHistoryMapsys.tables 等根据您计算的 front_end_name 可能具有一对多或多对多关系

使用 CTE 保存您的原始基础结果,考虑聚合其他列以避免重复名称

WITH base AS (
     SELECT dbtables.[name] AS back_end_name, 
            CASE
                WHEN dbtables.[name] LIKE '_Result%' AND CAST(RIGHT(dbtables.[name], LEN(dbtables.[name]) - 7) AS int) = CalculationID
                THEN Calculation.Name
                WHEN dbtables.[name] LIKE '_History%' 
                THEN
                    CASE
                        WHEN LEN(dbtables.[name]) = 9 AND CAST(RIGHT(dbtables.[name], 1) AS int) = HistoryID
                        THEN HistoryMap.TableName
                        WHEN LEN(dbtables.[name]) = 10 AND CAST(RIGHT(dbtables.[name], 2) AS int) = HistoryID
                        THEN HistoryMap.TableName
                        WHEN LEN(dbtables.[name]) = 11 AND CAST(RIGHT(dbtables.[name], 3) AS int) = HistoryID
                        THEN HistoryMap.TableName
                        ELSE 'N/A'
                    END 
                ELSE 'N/A'
            END AS front_end_name,
            indexstats.avg_fragmentation_in_percent,
            indexstats.page_count,
            indexstats.record_count
        FROM Calculation, HistoryMap, sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL, NULL, 'Sampled') AS indexstats
        INNER JOIN sys.tables dbtables on dbtables.[object_id] = indexstats.[object_id]
        INNER JOIN sys.schemas dbschemas on dbtables.[schema_id] = dbschemas.[schema_id]
        INNER JOIN sys.indexes AS dbindexes ON dbindexes.[object_id] = indexstats.[object_id]
        AND indexstats.index_id = dbindexes.index_id
        WHERE indexstats.database_id = DB_ID() AND indexstats.avg_fragmentation_in_percent >= 30
)

SELECT back_end_name,
       front_end_name,
       AVG(avg_fragmentation_in_percent) AS avg_page_count,   -- ADJUST AGG FUNCTION TO NEEDS
       SUM(page_count) AS sum_page_count,                     -- ADJUST AGG FUNCTION TO NEEDS
       SUM(record_count) AS sum_record_count                  -- ADJUST AGG FUNCTION TO NEEDS
FROM base
GROUP BY back_end_name,               -- GROUP BY REQUIRES ALL NON-AGG COLUMNS PRESENT IN CLAUSE
         front_end_name
ORDER BY AVG(avg_fragmentation_in_percent)

或者,如果您知道重复的原因,请聚合 front_end_name

WITH base AS (
    ...
)

SELECT back_end_name,
       MAX(front_end_name) AS front_end_name,
       AVG(avg_fragmentation_in_percent) AS sum_page_count,   -- ADJUST AGG FUNCTION TO NEEDS
       SUM(page_count) AS sum_page_count,                     -- ADJUST AGG FUNCTION TO NEEDS
       SUM(record_count) AS sum_record_count                  -- ADJUST AGG FUNCTION TO NEEDS
FROM base
GROUP BY back_end_name
ORDER BY AVG(avg_fragmentation_in_percent)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-10
    • 1970-01-01
    • 2020-10-26
    • 2013-11-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多