2016-07-08 65 views
0

我需要帮助解决MySQL问题。我有两张桌子,一张叫做subscription,另一张叫做payment。每个订阅都有多个付款。有些付款未启动(0),有些付款失败(1),有些付款成功(2)。MySQL - 是否可以使用正则表达式对行进行计数?

每个订阅都可以产生多次付款尝试,直到获得成功。例如:

  • 第一次尝试网络连接问题,并得到status = 0
  • 第二次尝试到达支付A​​PI,但信用卡数据错误,或没有足够的资金,所以它得到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最后两笔款项分别后118那些在最后插入。

预期的最终结果:

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

如何计算每次订阅的付款顺序,例如,如果您对subscription_id = 1有seq1:0,2和seq2:1,2,您怎么知道您有2次付款,每次付款2次,而不是2次付款分别有3次和1次尝试。在分贝你会hava 0,1,2,2 –

+0

您的问题可能类似于http://stackoverflow.com/questions/9231447/how-to-count-the-number-of-groups-returned-by -a-group-by –

回答

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; 

你的第二个查询将需要组这一结果再次,e.g和看起来像

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移至参考表。

+0

添加了一个'NULL'的invoice_no'列,用于序列的最终付款不成功,现在选择数据很简单!感谢您的支持。 –

相关问题