简体   繁体   中英

Very complicated SQL query

I am using MySql and supposed to create a very complicated report that shows events state.

For example:

event_id   |  state        |  create_time
----------------------------------------------------
1          |    PENDING    | 2019-04-21 12:55:59.312
1          |   COMPLETED   | 2019-04-21 12:55:59.339
2          |   PENDING     | 2019-04-21 11:40:21.699
3          |   PENDING     | 2019-04-21 11:40:21.699
3          |   FAILED      | 2019-04-21 11:40:21.600
3          |   COMPLETED   | 2019-04-21 11:40:21.578

I need to select rows according to states preferences:

  • FAILED + COMPLETED + PENDING -> FAILED
  • COMPLETED + PENDING -> COMPLETED
  • PENDING alone -> PENDING

This should be paginated using OFFSET and SIZE.

Each event will be shown once.

expected result:

event_id   |  state        |  create_time
----------------------------------------------------
1          |   COMPLETED   | 2019-04-21 12:55:59.339
2          |   PENDING     | 2019-04-21 11:40:21.699
3          |   FAILED      | 2019-04-21 11:40:21.600

How can I do this in a single SQL query.

Regards, Ido

I suspect you want aggregation with some conditional logic, like this:

select event_id,
       (case when sum(state = 'FAILED') > 0 then 'FAILED'
             when sum(state = 'COMPLETED') > 0 then 'COMPLETED'
             when sum(state = 'PENDING') > 0 then 'PENDING'
        end) as new_state
from t
group by event_id;

You can do aggregation with coalesce() :

select event_id,
       coalesce(max(case when state = 'FAILED' then 'FAILED' end),
                max(case when state = 'COMPLETED' then 'COMPLETED' end),
                'PENDING'     
               )
from table t
group by event_id;

A other option is handling those states preferences as bitmasks.

Note This method assumes that there are no duplicated stats for a event_id.

Query

SELECT 
 t.*
FROM (

SELECT 
   t.event_id
 , SUM(bitmask_table.bitmask) AS total_bitmask
FROM (
  SELECT
    DISTINCT 
       state
     , CASE 
        WHEN state = 'PENDING'
        THEN 2

        WHEN state = 'COMPLETED'
        THEN 4

        WHEN state = 'FAILED'
        THEN 8
       END AS bitmask
  FROM
   t 
) AS bitmask_table
INNER JOIN 
 t
ON
 t.state = bitmask_table.state
GROUP BY 
 t.event_id

) AS group_bitmasked
INNER JOIN 
 t
ON
  group_bitmasked.event_id = t.event_id
AND
 t.state = CASE
    WHEN group_bitmasked.total_bitmask & 8 AND group_bitmasked.total_bitmask & 4 AND  group_bitmasked.total_bitmask & 2
    THEN 'FAILED'

    WHEN group_bitmasked.total_bitmask & 4 AND group_bitmasked.total_bitmask & 2
    THEN 'COMPLETED'  

    WHEN group_bitmasked.total_bitmask & 2
    THEN 'PENDING'      
   END

Result

| event_id | state     | create_time             |
| -------- | --------- | ----------------------- |
| 1        | COMPLETED | 2019-04-21 12:55:59.339 |
| 2        | PENDING   | 2019-04-21 11:40:21.699 |
| 3        | FAILED    | 2019-04-21 11:40:21.600 |

see demo

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM