我需要MySQL问题的帮助。我有两个表,一个名为subscription
,另一个名为payment
。每个订阅都有多笔付款。某些付款未启动(0
),有些付款失败(1
),有些付款失败(2
)。
每个订阅都可以生成多次付款尝试,直到获得成功。例如:
status = 0
status = 1
status = 2
前两个可能超过两个,实际上它看起来像这样:
0, 1, 0, 0, 1, 1, 1, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 2, 0, 1, 2, 1, 0, 2, 0, 2, 1, 2, 2
因此,每个订阅都有多个付款顺序(每月或经常,没有必要的日期相关),可以通过这个正则表达式[0|1]*2
的状态来识别,得到类似的内容:
0, 1, 0, 0, 1, 1, 1, 1, 2, // 9
0, 0, 1, 2, // 4
1, 0, 1, 2, // 4
2, // 1
2, // 1
0, 1, 2, // 3
1, 0, 2, // 3
0, 2, // 2
1, 2, // 2
2 // 1
但是,当然,由于有多个订阅,付款行在数据库中混合,唯一连接它们的是subscription_id
。
我需要获得的是从首次尝试,第二次尝试,第三次尝试,第二次尝试,第10次尝试,10次尝试成功付款的订阅数量。
在上面的例子中,它应该是:
attempts count
9 1
4 2
3 2
2 2
1 3
这可能吗?
测试数据
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";
CREATE TABLE IF NOT EXISTS `payment` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`subscription_id` int(11) DEFAULT NULL,
`status` smallint(6) NOT NULL,
PRIMARY KEY (`id`),
KEY `IDX_6D28840D9A1887DC` (`subscription_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ROW_FORMAT=COMPRESSED AUTO_INCREMENT=36 ;
INSERT INTO `payment` (`id`, `subscription_id`, `status`) VALUES
(1, 1, 1),(2, 1, 2),(3, 1, 2),(4, 2, 2),(5, 3, 2),(6, 4, 2),(7, 5, 2),
(8, 6, 1),(9, 6, 2),(10, 7, 2),(11, 7, 2),(12, 8, 0),(13, 8, 1),(14, 8, 2),
(15, 8, 2),(16, 9, 1),(17, 9, 2),(18, 9, 2),(19, 9, 1),(20, 9, 2),(21, 10, 0),
(22, 10, 1),(23, 10, 1),(24, 10, 1),(25, 10, 1),(26, 11, 0),(27, 11, 0),(28, 11, 1),
(29, 11, 1),(30, 11, 1),(31, 8, 0),(32, 8, 1),(33, 8, 2),(34, 10, 1),(35, 10, 2);
CREATE TABLE IF NOT EXISTS `subscription` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`status` smallint(6) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ROW_FORMAT=COMPRESSED AUTO_INCREMENT=12 ;
INSERT INTO `subscription` (`id`, `status`) VALUES
(1, 1),(2, 1),(3, 1),(4, 1),(5, 1),(6, 1),(7, 1),
(8, 1),(9, 1),(10, 0),(11, 0);
ALTER TABLE `payment`
ADD CONSTRAINT `sub_id` FOREIGN KEY (`subscription_id`) REFERENCES `subscription` (`id`);
注意:测试数据与上面的示例不同。对于测试数据,结果应如下所示:
subscription_id cntAttempts [attempts counted]
1 2 1, 2,
1 1 2,
2 1 2,
3 1 2,
4 1 2,
5 1 2,
6 2 1, 2,
7 1 2,
7 1 2,
8 3 0, 1, 2,
8 1 2,
9 2 1, 2,
9 1 2,
9 2 1, 2,
10 7 0, 1, 1, 1, 1, 1, 2
11 5 0, 0, 1, 1, 1,
8 3 0, 1, 2,
对于subscription_id = 10
,最后两笔付款是在11
和8
之后插入的。
预期的最终结果:
paymentAttemptsCount count
1 9
2 5
3 1
4 0
5 1
6 0
7 1
8 0
9 0
10 0
注意:id = 11
的订阅无法成功付款。
答案 0 :(得分:0)
如上所述,您实际上应该为paymentid / invoicenumber(它将是发票表的外键)添加一列,以便将多个付款尝试组合在一起 - 因为它们属于一起而您的数据模型应该代表该逻辑。您的问题似乎更复杂,因为您缺少这些数据。
您可以在运行时计算该ID(至少如果您按顺序添加它们,并且没有为同一subscription_id
混合付款,例如因为发票可能在下个月仍然打开,您现在尝试两个发票)。对于您的第一个查询,您可以例如使用
select subscription_id,
count(*) as cntAttempts,
group_concat(status order by id) as attempts_counted
from
(SELECT id, subscription_id, status,
@pid := CASE WHEN @last_status = 2 or subscription_id <> @last_id
THEN @pid + 1 else @pid END as pid,
@last_id := subscription_id,
@last_status := status
from (select @last_id := 0, @pid := 0, @last_status := 0) init, payment
order by subscription_id, id
) as payment_grpd
group by pid, subscription_id;
您的第二个查询需要再次对此结果进行分组,例如
select cntAttempts,
count(*) as count
from
(select pid,
count(*) as cntAttempts
from
(SELECT id, subscription_id, status,
@pid := CASE WHEN @last_status = 2 or subscription_id <> @last_id
THEN @pid + 1 else @pid END as pid,
@last_id := subscription_id,
@last_status := status
from (select @last_id := 0, @pid := 0, @last_status := 0) init, payment
order by subscription_id, id
) as payment_grpd
group by pid, subscription_id
) as subcounts
group by cntAttempts;
子查询payment_grpd
将重新计算您的ID。如果添加缺少的关系,则第一个查询看起来就像
select subscription_id,
count(*) as cntAttempts,
group_concat(status order by id) as attempts_counted
from payment
group by pid, subscription_id;
和第二个类似。为了规范化,可能必须将subscription_id
移动到参考表。