用于组中任何非特定值的SQL聚合函数

时间:2013-01-09 00:55:47

标签: sql oracle

是否有一个agregate函数可以返回组中的任何值。我可以使用MINMAX,但如果可能的话,我宁愿避免开销,因为它是一个文本字段。

我的情况是错误日志摘要。错误按错误类型分组,并显示每个组的错误文本示例。使用哪个错误消息作为示例并不重要。

SELECT
    ref_code,
    log_type,
    error_number,
    COUNT(*) AS count,
    MIN(data) AS example
FROM data
GROUP BY
    ref_code,
    log_type,
    error_number

我可以用MIN(data)代替什么,而不必比较100,000的varchar(2000)值?

3 个答案:

答案 0 :(得分:4)

你可以使用MIN加上KEEP,如下所示:

MIN(data) keep (dense_rank first order by rowid) AS EXAMPLE

这背后的想法是数据库引擎将通过ROWID而不是VARCHAR(2000)值对数据进行排序,理论上应该更快。您可以使用主键值替换ROWID,并检查它是否更快

答案 1 :(得分:3)

根据提议的答案,MIN(data)(或MAX(data))似乎是达到我想要的最快方式。我试图不必要地进行过度优化。

我可以尝试在访问此数据库时出现的任何其他答案,但与此同时,这也是最重要的。

感谢大家的努力!

答案 2 :(得分:2)

好吧,既然你问过OVER PARTITION和ORDER BY,下面是一个版本,你的GROUP BY,但是也使用ROW_NUMBER()和OVER和PARTITION AND ORDER BY来编号第一个ref_code, log_type, error_num组合它出现在行号1(任何数据列都在1)。然后它从1开始重新编号,找到它找到的下一个不同的ref_code, log_type, error_num组合(无论发生在那里的任何数据列)。因此,您可以简单地将第1行的数据字段作为给定ref_code, log_type, error_num的代表性数据字段。

它还缺少某些东西。如果我没有双遍(一次用于聚合,一次用于row_number()),它会更优雅;然而,它可能表现得非常好。我将不得不考虑更多,看看我是否可以消除双通。

但它避免了对大数据字段的任何比较。它代表了一种方法来做你所要求的:从数据字段中提取1个代表性样本与聚合字段相关联。

SELECT
    t.ref_code,
    t.log_type,
    t.error_number,
    t.count,
    d.data
FROM
(
    SELECT
        ref_code,
        log_type,
        error_number,
        COUNT(*) as count
    FROM data
    GROUP BY
        ref_code,
        log_type,
        error_number
) t
INNER JOIN 
(
    SELECT
        ref_code,
        log_type,
        error_number,
        data,
        ROW_NUMBER() OVER
        (
            PARTITION BY
                ref_code,
                log_type,
                error_number
            ORDER BY
                ref_code,
                log_type,
                error_number
        ) as row_number
    FROM data
) d on
    d.ref_code = t.ref_code and
    d.log_type = t.log_type and
    d.error_number = t.error_number and
    row_number = 1

最后的警告:我没有Oracle试试这个。但我确实从阅读Oracle文档中把它放在一起。


在我进一步思考如何消除GROUP BY之后,我添加了以下内容,我在那里只有COUNT(*)。不知道它是否更快。

SELECT *
FROM
(
    SELECT
        ref_code,
        log_type,
        error_number,
        data,
        ROW_NUMBER() OVER
        (
            PARTITION BY
                ref_code,
                log_type,
                error_number
            ORDER BY
                ref_code,
                log_type,
                error_number
        ) as row_number,
        COUNT(*) OVER
        (
            PARTITION BY
                ref_code,
                log_type,
                error_number
            ORDER BY
                ref_code,
                log_type,
                error_number
        ) as count 

    FROM data
) t
WHERE row_number = 1