我还是SQL的新手,并且围绕整个子查询聚合来展示一些结果,并且正在寻找一些建议:
表格可能类似于:
Customer: (custID, name, address)
Account: (accountID, reward_balance)
Shop: (shopID, name, address)
关系表:
Holds (custID*, accountID*)
With (accountID*, shopID*)
如何找到奖励平衡最少的商店? (此时不需要客户信息)
我试过了:
SELECT accountID AS ACCOUNT_ID, shopID AS SHOP_ID, MIN(reward_balance) AS LOWEST_BALANCE
FROM Account, Shop, With
WHERE With.accountID = Account.accountID
AND With.shopID=Shop.shopID
GROUP BY
Account.accountID,
Shop.shopID
ORDER BY MIN(reward_balance);
这是以无意的方式工作:
ACCOUNT_ID | SHOP_ID | LOWEST_BALANCE
1 | 1 | 10
2 | 2 | 40
3 | 3 | 100
4 | 4 | 1000
5 | 4 | 5000
正如您所见,Shop_ID 4实际上有6000(1000 + 5000)的余额,因为有两个客户注册了它。我认为我需要根据他们的余额来衡量商店的最低余额,并从低位显示它。
我一直在尝试在显示之前聚合数据,但这是我解开的地方:
SELECT shopID AS SHOP_ID, MIN(reward_balance) AS LOWEST_BALANCE
FROM (SELECT accountID, shopID, SUM(reward_balance)
FROM Account, Shop, With
WHERE
With.accountID = Account.accountID
AND With.shopID=Shop.shopID
GROUP BY
Account.accountID,
Shop.shopID;
当我运行类似于此语句的内容时,我收到无效的标识符错误。
Error at Command Line : 1 Column : 24
Error report -
SQL Error: ORA-00904: "REWARD_BALANCE": invalid identifier
00904. 00000 - "%s: invalid identifier"
所以我认为我的加入条件可能不正确,汇总排序不正确,非常感谢任何一般建议。
感谢您阅读冗长!
答案 0 :(得分:1)
一步一步地解决这个问题。
我们将假设(并且我们应该检查一下)至少使用reward_balance,它指的是与商店相关的所有reward_balance的总。而且我们不只是寻找具有最低个人奖励余额的商店。
首先,获得每个商店的所有个人“reward_balance”。看起来查询需要涉及三个表...
SELECT s.shop_id
, a.reward_balance
FROM `shop` s
LEFT
JOIN `with` w
ON w.shop_id = s.shop_id
LEFT
JOIN `account` a
ON a.account_id = w.account_id
这将为我们提供详细信息行,每个商店以及与商店相关的个人奖励平衡金额(如果有的话)。 (我们正在使用外部联接进行此查询,因为我们没有看到任何商店与至少一个帐户相关的保证。即使这个用例也是如此,在更一般的情况下并不总是这样。情况)。
一旦我们获得了单独的金额,下一步就是为每个商店计算总额。我们可以使用GROUP BY
子句和SUM()
聚合来实现这一点。
SELECT s.shop_id
, SUM(a.reward_balance) AS tot_reward_balance
FROM `shop` s
LEFT
JOIN `with` w
ON w.shop_id = s.shop_id
LEFT
JOIN `account` a
ON a.account_id = w.account_id
GROUP BY s.shop_id
此时,使用MySQL,我们可以添加ORDER BY
子句以按tot_reward_balance的升序排列行,如果我们只想返回单行,则添加LIMIT 1
子句。当tot_reward_balance为NULL时,我们也可以处理这种情况,指定零代替NULL。
SELECT s.shop_id
, IFNULL(SUM(a.reward_balance),0) AS tot_reward_balance
FROM `shop` s
LEFT
JOIN `with` w
ON w.shop_id = s.shop_id
LEFT
JOIN `account` a
ON a.account_id = w.account_id
GROUP BY s.shop_id
ORDER BY tot_reward_amount ASC, s.shop_id ASC
LIMIT 1
如果有两个(或更多)商店具有相同的最小值tot_reward_amount,则此查询仅返回其中一个商店。
Oracle没有像MySQL这样的LIMIT子句,但我们可以使用分析函数(在MySQL中不可用)获得相同的结果。我们还将MySQL IFNULL()函数替换为Oracle等效的NVL()函数......
SELECT v.shop_id
, v.tot_reward_balance
, ROW_NUMBER() OVER (ORDER BY v.tot_reward_balance ASC, v.shop_id ASC) AS rn
FROM (
SELECT s.shop_id
, NVL(SUM(a.reward_balance),0) AS tot_reward_balance
FROM shop s
LEFT
JOIN with w
ON w.shop_id = s.shop_id
LEFT
JOIN account a
ON a.account_id = w.account_id
GROUP BY s.shop_id
) v
HAVING rn = 1
与MySQL查询一样,即使两个或两个以上的商店总共拥有相同的“最少”的reward_balance,也会返回最多一行。
如果我们想要返回所有具有最低tot_reward_balance的商店,我们需要采取略微不同的方法。
构建查询的最佳方法是逐步完善;在这种情况下,首先获得每个商店的所有个人reward_amount。下一步是将个人reward_amount聚合为总数。接下来的步骤是挑选总奖励金额最低的行。
答案 1 :(得分:0)
在SQL Server中,您可以尝试使用CTE:
;with cte_minvalue as
(
select rank() over (order by Sum_Balance) as RowRank,
ShopId,
Sum_Balance
from (SELECT Shop.shopID, SUM(reward_balance) AS Sum_Balance
FROM
With
JOIN Shop ON With.ShopId = Shop.ShopId
JOIN Account ON With.AccountId = Account.AccountId
GROUP BY
Shop.shopID)ShopSum
)
select ShopId, Sum_Balance from cte_minvalue where RowRank = 1