2016-07-08 4 views
0

MySQL 문제와 관련하여 도움이 필요합니다. 나는 두 테이블을 가지고 있는데 하나는 subscription이고 다른 하나는 payment입니다. 모든 구독에는 여러 개의 지불이 있습니다. 일부 지급금이 시작되지 않고 (0), 일부 지급 실패 (1)와 일부 지급 실패 (2)가 있습니다.MySQL - regexp를 사용하여 행 수를 계산할 수 있습니까?

모든 구독은 성공적인 구독을 얻을 때까지 여러 번의 지불 시도를 생성 할 수 있습니다. 예를 들어 :

  • 첫 번째 시도는 네트워크 연결 문제를 가지고 있으며 status = 0
  • 두 번째 시도가 지불 API하지만 신용 카드 데이터가 잘못하거나 status = 1
  • 세 번째 시도가 얻을 수 있도록 충분한 자금이, 거기에 도달 얻는다 성공 그것은 이렇게 볼 수 사실, 처음 두가이보다 더 될 수 status = 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 

하지만 : 0

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 자신의 상태를 식별 할 수 있습니다 물론 여러 구독이 있기 때문에 지불 행은 데이터베이스에 혼합되어 있습니다. 연결하는 유일한 것은 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 당 지불 순서를 어떻게 계산합니까 (예 : seq1 : 0,2 및 seq2 : 1,2 subscription_id = 1 인 경우), 2 회 지불이 아닌 2 회 지불을 각각 2 회 받았음을 어떻게 알 수 있습니까? 3 회 1 회 시도. db에서 당신은 0,1,2,2 –

+0

당신의 질문은 http://stackoverflow.com/questions/9231447/how-to-count-the-number-of-groups-returned-by와 유사 할 수 있습니다. -a-group-by –

답변

0

언급 한 바와 같이 실제로 여러 개의 지불 시도를 그룹화하기 위해 하나의 지불 ID/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; 

두 번째 쿼리를 사용하여 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과 같을 것이다. 당신이 누락 된 관계를 추가하면 첫 번째 쿼리는 단순히 1 초 동안 유사

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

'invoice_no' 칼럼에'NULL '을 추가하여 마지막에 결제가 성공적이지 않은 시퀀스를 추가했습니다. 이제 데이터를 쉽게 선택할 수 있습니다! 협조 해 주셔서 감사합니다. –

관련 문제