1

大家晚上好

我整天都在和这个搏斗。

我正在尝试更新我的客户表中的一列,该列将显示他们成为订阅者的次数。该表是从一个大数据转储中创建的,该转储中每个客户都有单独的行,并且每个月他们都是订阅者(为每个月分配一个迭代编号)。名字是独一无二的。它看起来像这样,并显示(例如)Jane Doe 是期间 1000 的订户,但不是期间 1002。

Row_ID Customer_Name  Date_Code 
1      Jane Doe       1000      
2      Jane Doe       1001      
3      Jane Doe       1004      
4      Jane Doe       1005      
5      Ted Jones      1000      
6      Ted Jones      1001      
7      Ted Jones      1002      
etc...

在这种情况下,Jane Doe 是 1000-1001 的订阅者,离开了我们的订阅,然后从 1004-1005 回来。我有一个包含所有日期逻辑(开始日期、结束日期、日期代码等)的主表。它看起来大致是这样的:

Start_Date   End_Date    Date_Code
1990-01-01   1990-03-31  1000
1990-04-01   1990-06-30  1001
1990-07-01   1990-09-30  1002
1990-10-01   1990-12-31  1003
etc...

我正在尝试找到一种使输出类似于以下内容的方法:

Customer_Name  Subscription_Count
Jane Doe       2
Ted Jones      1

有没有人遇到过这样的事情?对我(作为一个人)来说,这些数字是(或不)连续的,并且是(或不是)整个样本的表示,但我不确定如何让 MYSQL 理解它,这对我来说很明显。我很欣赏任何想法。

*编辑 - 我尝试了 Join 和 Where Not Exists 替代方案,并且都在 10 分钟后超时。我相信这是由于主表的大小(约 100,000 行)。你有什么建议吗?再次感谢所有评论。

** 编辑 #2 - 添加索引并稍微调整我的表格后,两种解决方案都很好用。再次感谢您对解决此问题的支持。

4

2 回答 2

1

查询可能如下所示:

SELECT customer_name, count(*) AS subscriptions
FROM   tbl AS t
WHERE NOT EXISTS (
    SELECT *
    FROM tbl AS t1
    WHERE t1.customer_name = t.customer_name
    AND t1.date_code = t.date_code + 1
    )
GROUP BY customer_name;

这里的技巧是排除所有行,但每个客户的一系列 date_codes 除外,然后计数:只有每个块的最后一行没有后继 ( date_code + 1)。

我假设连续的 date_codes 形成一个订阅(根据我对该问题的第一条评论)。因此,不需要关于Start_Date和的附加信息。End_Date


表现

LEFT JOIN / IS NULL实际上应该比NOT EXISTSMySQL 快一点(如@nnichols 提供的那样)。
对性能来说更重要的是索引。为此,您需要 oncustomer_name和 on 的索引date_code。像这样:

CREATE INDEX tbl_customer_name ON tbl(customer_name);
CREATE INDEX tbl_date_code ON tbl(date_code);
于 2012-03-11T02:34:32.893 回答
1

我不能 100% 确定情况仍然如此,但 LEFT JOIN / IS NULL 通常比 MySQL 中的 NOT EXISTS 快 -

SELECT t1.customer_name, COUNT(*) AS subscriptions
FROM   tbl t1
LEFT JOIN tbl t2
    ON t1.customer_name = t2.customer_name
    AND t1.date_code + 1 = t2.date_code
WHERE t2.customer_name IS NULL
GROUP BY t1.customer_name

更新在这两个字段中添加复合索引而不是两个单列索引可以显着提高性能 -

CREATE UNIQUE INDEX `UQ_customer_date_code` ON tbl (customer_name, date_code);

我使用具有 160 万条记录的测试表(跨越 21 个日期代码的 10 万客户)进行了一些测试。添加此索引后,查询时间减少了约 80%。使用 LEFT JOIN 而不是 NOT EXISTS 只会减少大约 15% 的查询时间。

于 2012-03-11T03:07:20.653 回答