Reputation: 1718
I have an order_transactions table with 3 relevant columns. id
(unique id for the transaction attempt), order_id
(the id of the order for which the attempt is being made), and success
an int which is 0 if failed, and 1 if successful.
There can be 0 or more failed transactions before a successful transaction, for each order_id
.
The question is, how do I find:
I realize this is some combination of distinct, group by, maybe a subselect, etc, I'm just not well versed in this enough. Thanks.
Upvotes: 0
Views: 434
Reputation: 108480
You want "counts" of orders that meet specific conditions over multiple rows, so I'd start with a GROUP BY order_id
SELECT ...
FROM mytable t
GROUP BY t.order_id
To find out if a particular order ever had a failed transaction, etc. we can use aggregates on expressions that "test" for conditions.
For example:
SELECT MAX(t.success=1) AS succeeded
, MAX(t.success=0) AS failed
, IF(MAX(t.success=1),0,1) AS never_succeeded
FROM mytable t
GROUP BY t.order_id
The expressions in the SELECT list of that query are MySQL shorthand. We could use longer expressions (MySQL IF() function or ANSI CASE expressions) to achieve an equivalent result, e.g.
CASE WHEN t.success = 1 THEN 1 ELSE 0 END
We could include the `order_id` column in the SELECT list for testing. We can compare the results for each order_id to the rows in the original table, to verify that the results returned meet the specification.
To get "counts" of orders, we can reference the query as an inline view, and use aggregate expressions in the SELECT list.
For example:
SELECT SUM(r.succeeded) AS cnt_succeeded
, SUM(r.failed) AS cnt_failed
, SUM(r.never_succeeded) AS cnt_never_succeeded
FROM (
SELECT MAX(t.success=1) AS succeeded
, MAX(t.success=0) AS failed
, IF(MAX(t.success=1),0,1) AS never_succeeded
FROM mytable t
GROUP BY t.order_id
) r
Since the expressions in the SELECT list return either 0, 1 or NULL, we can use the SUM() aggregate to get a count. To make use of a COUNT() aggregate, we would need to return NULL in place of a 0 (FALSE) value.
SELECT COUNT(IF(r.succeeded,1,NULL)) AS cnt_succeeded
, COUNT(IF(r.failed,1,NULL)) AS cnt_failed
, COUNT(IF(r.never_succeeded,1,NULL)) AS cnt_never_succeeded
FROM (
SELECT MAX(t.success=1) AS succeeded
, MAX(t.success=0) AS failed
, IF(MAX(t.success=1),0,1) AS never_succeeded
FROM mytable t
GROUP BY t.order_id
) r
If you want a count of all order_id, add a COUNT(1) expression in the outer query. If you need percentages, do the division and multiply by 100,
For example
SELECT SUM(r.succeeded) AS cnt_succeeded
, SUM(r.failed) AS cnt_failed
, SUM(r.never_succeeded) AS cnt_never_succeeded
, SUM(1) AS cnt_all_orders
, SUM(r.failed)/SUM(1)*100.0 AS pct_with_a_failure
, SUM(r.succeeded)/SUM(1)*100.0 AS pct_succeeded
, SUM(r.never_succeeded)/SUM(1)*100.0 AS pct_never_succeeded
FROM (
SELECT MAX(t.success=1) AS succeeded
, MAX(t.success=0) AS failed
, IF(MAX(t.success=1),0,1) AS never_succeeded
FROM mytable t
GROUP BY t.order_id
) r
(The percentages here are a comparison to the count of distinct order_id values, not as the total number of rows in the table).
Upvotes: 1
Reputation: 72185
To get the number of orders which never had a successful transaction you can use:
SELECT COUNT(*)
FROM (
SELECT order_id
FROM transactions
GROUP BY order_id
HAVING COUNT(CASE WHEN success = 1 THEN 1 END) = 0) AS t
The number of orders which had a transaction with a failure (eventually successful or not) can be obtained using the query:
SELECT COUNT(*)
FROM (
SELECT order_id
FROM transactions
GROUP BY order_id
HAVING COUNT(CASE WHEN success = 0 THEN 1 END) > 0) AS t
Finally, to get the number of orders which never had a failed transaction (success only):
SELECT COUNT(*)
FROM (
SELECT order_id
FROM transactions
GROUP BY order_id
HAVING COUNT(CASE WHEN success = 0 THEN 1 END) = 0) AS t
Upvotes: 1
Reputation: 133380
successful order
select count(*) from
( select distinct order_id from my_table where success = 1 ) as t;
unsuccessful order
select count(*) from
( select distinct order_id from my_table where success = 0 ) as t;
never filed transaction
select count(*) from
( select distintc order_id from my_table where id not in
(select distinct order_id from my_table where success = 0) ) as t;
Upvotes: 0