所以,假设我有一个客户列表,我想为所有客户选择详细信息,以及从特定类别的产品中购买最多的产品。即使他们没有购买这些产品中的一种,我也想选择客户的详细信息,而只是为他们从该类购买的产品中显示null。
我将从以下开始作为CTE或临时表:
SELECT
CUST_NUMBER
,PRODUCT
,ROW_NUMBER() OVER (PARTITION BY CUST_NUMBER ORDER BY COUNT(ORDER_NUM) DESC) [ProdRank]
FROM ORDERS
WHERE PROD_CLASS = 'x'
GROUP BY
CUST_NUMBER
,PRODUCT
事情是这样的 - 在这个产品类中可以有许多不同的产品,我只对选择ProdRank = 1的位置感兴趣。但是你可能知道,我不能在ProdRank的WHERE或HAVING子句中指定到= 1。
我收到错误消息“窗口函数只能出现在SELECT或ORDER BY子句中。”
由于许多客户可能尚未在产品类别中订购任何产品,因此情况进一步复杂化。因此我不能简单地将客户列表加入到上面并指定WHERE ProdRank = 1,否则它模仿内部联接并且我放弃任何ProdRank为空的客户。
为了解决这个问题,我提出的方法是首先使用上面的代码创建一个临时表作为#Products,其中包括客户和具有相应排名的每个产品。然后我创建了一个名为#TopProducts的第二个临时表,其中我只是:
SELECT * FROM
#Products WHERE
ProdRank = 1
之后我就离开了来自我的Customers表的#TopProducts。
似乎应该有一种更简单的方法来解决这个问题。有没有什么办法可以在一步中选择ROW_NUMBER()或RANK()的顶级分区结果,而不是创建两个临时表?
答案 0 :(得分:2)
WITH topProducts AS (
SELECT
CUST_NUMBER
,PRODUCT
,ROW_NUMBER() OVER (PARTITION BY CUST_NUMBER ORDER BY COUNT(ORDER_NUM) DESC) [ProdRank]
FROM ORDERS
WHERE PROD_CLASS = 'x'
GROUP BY
CUST_NUMBER
,PRODUCT
)
SELECT *
FROM CustomerDetails c
LEFT JOIN TopProducts p ON (ProdRank = 1 AND c.CUST_NUMBER = p.CUST_NUMBER)
使用子查询:
SELECT *
FROM CustomerDetails c
LEFT JOIN (
SELECT
CUST_NUMBER
,PRODUCT
,ROW_NUMBER() OVER (PARTITION BY CUST_NUMBER ORDER BY COUNT(ORDER_NUM) DESC) [ProdRank]
FROM ORDERS
WHERE PROD_CLASS = 'x'
GROUP BY
CUST_NUMBER
,PRODUCT
) p ON (ProdRank = 1 AND c.CUST_NUMBER = p.CUST_NUMBER)
答案 1 :(得分:0)
我会在你的场景中使用外部应用和顶部。那有意义吗? 这里很少有例子Real life example, when to use OUTER / CROSS APPLY in SQL
我会写一段代码,但是我在移动设备上并且真的不舒服......