Php MySQL查询以获取最后N笔失败的付款

Php MySQL查询以获取最后N笔失败的付款,php,mysql,Php,Mysql,我的数据库有两个表:用户表和付款表。用户和付款之间存在一对多关系:每个用户可以有o个或多个付款,并且付款属于一个用户。此外,每次付款可以是成功的,也可以是失败的 我需要编写一个查询,以获取所有在最近N次付款中失败的用户 我发现了这个查询,在本例中,该查询允许支付N笔或更多款项的所有用户支付4笔或更多款项: SELECT x.user_id, count(*) as cnt FROM ( SELECT a.user_id, a.date, a.status FROM payment AS

我的数据库有两个表:用户表和付款表。用户和付款之间存在一对多关系:每个用户可以有o个或多个付款,并且付款属于一个用户。此外,每次付款可以是成功的,也可以是失败的

我需要编写一个查询,以获取所有在最近N次付款中失败的用户

我发现了这个查询,在本例中,该查询允许支付N笔或更多款项的所有用户支付4笔或更多款项:

SELECT x.user_id, count(*) as cnt 
FROM (
    SELECT a.user_id, a.date, a.status FROM payment AS a WHERE 
        (SELECT COUNT(*) FROM payment AS b 
         WHERE b.user_id = a.user_id AND b.date >= a.date) <= 4 
         ORDER BY a.user_id ASC, a.date DESC) AS x 
WHERE x.status = 'failed' 
GROUP BY x.user_id
HAVING cnt >=4;

我已经用一个更简单的SQL语句更新了您的SQL FIDLE,它可以生成正确的结果。如果您只想要具有特定失败付款计数的用户,请将>=更改为=

MySQL 5.6架构设置:

问题1:

问题2:

:


测试不充分。。。并且,如前所述,专门针对8.0之前的MySQL版本

SELECT u.*
  FROM users u
  LEFT 
  JOIN
     ( SELECT user_id
            , status
            , CASE WHEN @prev = user_id THEN @i:=@i+1 ELSE @i:=1 END i
            , @prev:=user_id 
         FROM payments
            , (SELECT @prev:=null,@i:=0) vars 
        ORDER 
           BY user_id
            , date DESC
     ) x 
    ON x.user_id = u.id
   AND (status = 'success' AND i <= 4) OR (status = 'failed' AND i=5)
 WHERE x.user_id IS NULL;

您想要的是那些上次未失败的用户是5次付款之前的用户,和/或那些只有4次付款的用户,所有付款都失败了。谢谢您的回复@草莓。我想所有用户的最后N次付款最近N次付款失败。因此,在这个例子中,如果我想要一个最后4次付款失败的用户列表,唯一满足该要求的用户是用户4用户4的所有付款:成功,成功,失败,失败,失败,失败。最后4个失败了,所以我希望它出现在结果集中,我很困惑。用户id 2为0失败,用户id 3为3失败,4为4失败,5为5失败!?!感谢您的回复@Sloan Thrasher。确实,用户2有4次付款失败。但是,如果我们检查用户2最近的4次付款,我们会得到:失败、失败、失败和成功。我的目的是得到最后或最近4次失败的付款。因此,用户2不应该是结果集的一部分。我有MySQL 5.7.21那么这很幸运
CREATE TABLE users
    (`id` int, `name` varchar(6), `email` varchar(7), `password` varchar(10), `created_at` timestamp, `updated_at` timestamp)
;

INSERT INTO users
    (`id`, `name`, `email`, `password`)
VALUES
    (1, 'name 1', 'email 1', 'password 1'),
    (2, 'name 2', 'email 2', 'password 2'),
    (3, 'name 3', 'email 3', 'password 3'),
    (4, 'name 4', 'email 4', 'password 4'),
    (5, 'name 5', 'email 5', 'password 5')
;


CREATE TABLE payments
    (`id` int, `date` varchar(10), `status` varchar(7), `user_id` int ,`created_at` timestamp, `updated_at` timestamp)
;

INSERT INTO payments
    (`id`, `date`, `status`, `user_id`)
VALUES
    (1, '2019-01-01', 'success', 1),
    (2, '2019-01-01', 'failed', 2),
    (3, '2019-01-01', 'failed', 3),
    (4, '2019-01-01', 'success', 4),
    (5, '2019-01-01', 'success', 5),
    (6, '2019-01-02', 'success', 1),
    (7, '2019-01-02', 'success', 2),
    (8, '2019-01-02', 'success', 3),
    (9, '2019-01-02', 'success', 4),
    (10, '2019-01-02', 'success', 5),
    (11, '2019-01-03', 'success', 1),
    (12, '2019-01-03', 'failed', 2),
    (13, '2019-01-03', 'success', 3),
    (14, '2019-01-03', 'failed', 4),
    (15, '2019-01-03', 'failed', 5),
    (16, '2019-01-04', 'success', 1),
    (17, '2019-01-04', 'failed', 2),
    (18, '2019-01-04', 'failed', 3),
    (19, '2019-01-04', 'failed', 4),
    (20, '2019-01-04', 'failed', 5),
    (21, '2019-01-05', 'success', 1),
    (22, '2019-01-05', 'failed', 2),
    (23, '2019-01-05', 'failed', 3),
    (24, '2019-01-05', 'failed', 4),
    (25, '2019-01-05', 'failed', 5),
    (26, '2019-01-06', 'success', 1),
    (27, '2019-01-06', 'success', 2),
    (28, '2019-01-06', 'failed', 3),
    (29, '2019-01-06', 'failed', 4),
    (30, '2019-01-06', 'failed', 5),
    (31, '2019-01-07', 'failed', 5)
;
SELECT x.user_id, count(*) as cnt 
FROM (
    SELECT a.user_id, a.date, a.status FROM payments AS a WHERE 
        (SELECT COUNT(*) FROM payments AS b 
         WHERE b.user_id = a.user_id AND b.date >= a.date) <= 4 
         ORDER BY a.user_id ASC, a.date DESC) AS x 
WHERE x.status = 'failed' 
GROUP BY x.user_id
HAVING cnt >=4
| user_id | cnt |
|---------|-----|
|       4 |   4 |
|       5 |   4 |
SELECT `user_id`, count(*) as `cnt`
FROM `payments` 
WHERE `status` = 'failed'
GROUP BY `user_id`
HAVING cnt >= 4
ORDER BY `cnt`
| user_id | cnt |
|---------|-----|
|       2 |   4 |
|       3 |   4 |
|       4 |   4 |
|       5 |   5 |
SELECT u.*
  FROM users u
  LEFT 
  JOIN
     ( SELECT user_id
            , status
            , CASE WHEN @prev = user_id THEN @i:=@i+1 ELSE @i:=1 END i
            , @prev:=user_id 
         FROM payments
            , (SELECT @prev:=null,@i:=0) vars 
        ORDER 
           BY user_id
            , date DESC
     ) x 
    ON x.user_id = u.id
   AND (status = 'success' AND i <= 4) OR (status = 'failed' AND i=5)
 WHERE x.user_id IS NULL;