sql - 使用子查询模拟 ROW_NUMBER、RANK 和 DENSE_RANK

标签 sql firebird self-join firebird2.5

我想在我的 JasperReport 查询之一上使用 DENSE_RANK() 函数,但它不适用于 Firebird 2.5。但有一个example on the firebirdfaq.org site使用聚合函数和上下文变量或生成器来模拟此函数。即

SELECT p.name, p.score, COUNT(DISTINCT others.score) + 1 AS "dense_rank"
FROM players p
LEFT JOIN players others ON others.score > p.score
GROUP BY 1, 2
ORDER BY "dense_rank"

所以这是玩家的 self 加入。

我的问题是我没有像“玩家”这样的已定义表来进行自连接,但我的查询使用两个表。我尝试创建别名并使用子查询进行自连接,但没有成功。

SELECT  x.DateCompleted, x.TimeCompleted, x.numOfBatches, COUNT(DISTINCT others.DateCompleted) + 1 AS "dense_rank"
FROM 
     (SELECT  floor(PRODUCEDH.COMPLETE_TIME)+cast('30.12.1899' AS TIMESTAMP) AS DateCompleted,
              (ABS(PRODUCEDH.COMPLETE_TIME) - FLOOR(ABS(PRODUCEDH.COMPLETE_TIME)))+cast('30.12.1899' AS TIMESTAMP) AS TimeCompleted,
              COMMODITIES.CODE,
              COMMODITIES.NAME AS COMMODITY_NAME,
              (SUM(PRODUCEDH.MIXSIZE) / 100) as numOfBatches
        FROM  
              "PRODUCEDH" "PRODUCEDH",
              "COMMODITIES" "COMMODITIES"
        WHERE
                PRODUCEDH."COMMODITYID" = COMMODITIES."COMMODITYID"
                AND ((PRODUCEDH."STATUS" IN ('C','X')))
                AND PRODUCEDH.COMPLETE_TIME IS NOT NULL
                AND COALESCE(PRODUCEDH."COMPLETE_TIME",PRODUCEDH."CREATETIME")+CAST('30.12.1899'AS TIMESTAMP) >= '05-01-2018'
                AND COALESCE(PRODUCEDH."COMPLETE_TIME",PRODUCEDH."CREATETIME")+CAST('30.12.1899'AS TIMESTAMP) <= '06-13-2018'
        GROUP BY
                DateCompleted,
                TimeCompleted,
                COMMODITIES.code,
                COMMODITIES.NAME
        ORDER BY
                DateCompleted,
                TimeCompleted
                ASC
        ) x
LEFT JOIN  x others ON others.DateCompleted > x.DateCompleted  <------ Error points here
GROUP BY x.DateCompleted, x.TimeCompleted
ORDER BY "dense_rank"

我不知道我做错了什么,但它无法选择表“X”并抛出错误,即SQL错误代码= -204表未知X

最佳答案

最好的解决方案是升级到 Firebird 3,因为它内置了对 window functions like DENSE_RANK() 的支持。 .

无论如何,查询的问题在于您无法基于联接左侧的子查询定义表x,然后使用该 >x 也在右手。相反,您需要使用 Common Table Expression ,在 Firebird 2.1 中引入:

WITH x AS (
    SELECT  floor(PRODUCEDH.COMPLETE_TIME)+cast('30.12.1899' AS TIMESTAMP) AS DateCompleted,
          (ABS(PRODUCEDH.COMPLETE_TIME) - FLOOR(ABS(PRODUCEDH.COMPLETE_TIME)))+cast('30.12.1899' AS TIMESTAMP) AS TimeCompleted,
          COMMODITIES.CODE,
          COMMODITIES.NAME AS COMMODITY_NAME,
          (SUM(PRODUCEDH.MIXSIZE) / 100) as numOfBatches
    FROM  
          "PRODUCEDH" "PRODUCEDH",
          "COMMODITIES" "COMMODITIES"
    WHERE
            PRODUCEDH."COMMODITYID" = COMMODITIES."COMMODITYID"
            AND ((PRODUCEDH."STATUS" IN ('C','X')))
            AND PRODUCEDH.COMPLETE_TIME IS NOT NULL
            AND COALESCE(PRODUCEDH."COMPLETE_TIME",PRODUCEDH."CREATETIME")+CAST('30.12.1899'AS TIMESTAMP) >= '05-01-2018'
            AND COALESCE(PRODUCEDH."COMPLETE_TIME",PRODUCEDH."CREATETIME")+CAST('30.12.1899'AS TIMESTAMP) <= '06-13-2018'
    GROUP BY
            DateCompleted,
            TimeCompleted,
            COMMODITIES.code,
            COMMODITIES.NAME
    ORDER BY
            DateCompleted,
            TimeCompleted
            ASC
    )
SELECT  x.DateCompleted, x.TimeCompleted, x.numOfBatches, COUNT(DISTINCT others.DateCompleted) + 1 AS "dense_rank"
FROM x
LEFT JOIN x others ON others.DateCompleted > x.DateCompleted
GROUP BY x.DateCompleted, x.TimeCompleted
ORDER BY "dense_rank"

警告一句:我还没有检查这个解决方案本身是否正确;它只是解决了尝试引用 x 两次的问题。

关于sql - 使用子查询模拟 ROW_NUMBER、RANK 和 DENSE_RANK,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50856695/

相关文章:

MySQL 重用子查询

firebird - Zend_Auth 和 Firebird DB

sql - firebird 数据库中的 MINUS 代数运算符集

sql - SQL 中的项目顺序是否为 : WHERE IN () matter?

sql - 从数据库表中选择重复条目

java - 一次以固定数量的结果流式传输 MySql ResultSet

sql - 如何从 SQL 转换为 NoSQL/MapReduce?

php - 如何在没有while循环的情况下查看表值?

sql - 汇总列值相同的MySQL计算字段

sql - 如何交换同一张表中同一列的值