SQL:查找在某个类别中没有支出的客户
Posted
技术标签:
【中文标题】SQL:查找在某个类别中没有支出的客户【英文标题】:SQL: Finding customers with no spend in a category 【发布时间】:2013-06-02 03:31:45 【问题描述】:我认为我在这方面工作的时间太长了,因为我很难回答一个非常简单的问题:在零售环境中,哪些客户没有在我提供优惠券的类别上花钱?
考虑以下数据:
-- The offer ID and the category for which it is valid.
select * from t_offers
OFFER CAT_NBR
foo34 34
xxx30 30
baz60 60
bar50 50
-- The customer ID (HH) and their total spending by all
-- categories (not just the ones for which coupons are being offered).
-- PLEASE NOTE that when a customer has zero spend, there will NOT be an
-- entry in this table for that category.
select * from t_catspend
HH CAT_NBR SPEND
1 30 5
1 60 7
2 34 8
我想要得到的是:对于t_offers
中的每个优惠,每个在该优惠类别中没有支出的客户的HH
ID。例如,对于优惠 foo34,我应该得到 HH #1,因为 HH #1 没有显示该类别的任何支出(HH #1 的类别 34 没有条目)。
因此,查找空数据时的第一直觉是外连接。所以我在cat_nbr
上尝试了左连接。但这只会让我有消费的客户;我不知道如何告诉我在该类别中没有消费的客户的 ID。
如果重要的话,这在 Netezza 上。
非常感谢您的任何帮助。
【问题讨论】:
【参考方案1】:SELECT a.HH
FROM t_catspend a
WHERE NOT EXISTS
(
SELECT null
FROM t_offers b
INNER JOIN t_catspend c
ON c.CAT_NBR = b.CAT_NBR
WHERE b.offer = 'foo34' AND
a.HH = c.HH
)
GROUP BY a.HH
SQLFiddle Demo
SQLFiddle Demo (an offer that spends on all HH returns empty)
输出
╔════╗
║ HH ║
╠════╣
║ 1 ║
╚════╝
更新
SELECT b.*, a.*
FROM t_offers a
CROSS JOIN (SELECT HH FROM t_catspend GROUP BY HH) b
LEFT JOIN t_catspend x
ON a.CAT_NBR = x.CAT_NBR AND
b.HH = x.HH
WHERE x.CAT_NBR IS NULL
-- AND a.offer = 'foo34' -- <<== specific OFFER
ORDER BY b.HH
SQLFiddle Demo
输出
╔════╦═══════╦═════════╗
║ HH ║ OFFER ║ CAT_NBR ║
╠════╬═══════╬═════════╣
║ 1 ║ bar50 ║ 50 ║
║ 1 ║ foo34 ║ 34 ║
║ 2 ║ baz60 ║ 60 ║
║ 2 ║ bar50 ║ 50 ║
║ 2 ║ xxx30 ║ 30 ║
╚════╩═══════╩═════════╝
由于您提到您有一个非常大的表,添加复合 INDEX
将导致更快的查询执行。
ALTER TABLE t_catspend ADD INDEX (HH, CAT_NBR)
如果可能,t_catspend.CAT_NBR
必须引用 t_offers.CAT_NBR
。
希望这会有所帮助。
【讨论】:
这看起来不错!有没有办法让它对所有优惠通用,而不是为 foo34 定制?理想情况下,我会取回每件符合条件的事物的优惠代码和 hh ID(即“符合条件”,即该类别中没有支出)。 我已更新答案以获取所有用户的状态。您需要在此使用CROSS JOIN
将所有报价与所有hh
值配对。无论如何,请不要犹豫。 :)
【参考方案2】:
你在找这个吗?
SELECT b.cat_nbr, b.hh
FROM
(
SELECT cat_nbr, hh
FROM t_offers CROSS JOIN
(
SELECT DISTINCT hh FROM t_catspend
) a
) b LEFT JOIN t_catspend s
ON b.cat_nbr = s.cat_nbr AND b.hh = s.hh
WHERE s.spend IS NULL
GROUP BY b.cat_nbr, b.hh
基于提供的样本数据的输出:
| CAT_NBR | HH |
----------------
| 30 | 2 |
| 34 | 1 |
| 50 | 1 |
| 50 | 2 |
| 60 | 2 |
这里是SQLFiddle
【讨论】:
你将如何过滤记录foo34
?
@SkyDrive OP 的确切词 For each offer in t_offers,HH ID for each customer在该优惠类别中的支出。并且可以通过在...) a WHERE cat_nbr = 34 ...
之后添加轻松过滤
谢谢,彼得。当我决定跳到 *** 时,我正沿着笛卡尔加入路径走……这很不幸,因为大约有 30MM 客户和一百个左右的类别。不是世界末日,而是大!我会让你知道这是怎么回事。
@Chris 恕我直言,在您的情况下,您必须以一种或另一种方式使用CROSS JOIN
。 JW 的更新答案支持它。【参考方案3】:
我认为您在正确的轨道上,可能缺少 WHERE 标准?
SELECT *
FROM t_catspend spend
LEFT JOIN t_offers offers
ON spend.CAT_NBR = offers.CAT_NBR
WHERE offers.CAT_NBR IS NULL
【讨论】:
【参考方案4】:不知道这是否有效但有效。
SELECT DISTINCT HH, offer FROM t_offers, t_catspend
WHERE (HH, offer) NOT IN
(SELECT HH, offer FROM t_offers t1, t_catspend t2
WHERE t1.cat_nbr = t2.cat_nbr)
【讨论】:
以上是关于SQL:查找在某个类别中没有支出的客户的主要内容,如果未能解决你的问题,请参考以下文章