简体   繁体   中英

Mysql case join query assistance

I'm trying to create a query which gets all columns and a case column which denotes availablity, however I need to include a one to many relationship in the mix and it's messing with my head.

My query without the relationship:

SELECT storage_rooms.*,
    CASE
        WHEN release_date <= CURDATE() THEN 1
        WHEN release_date <= ADDDATE(CURDATE(), INTERVAL 30 DAY) THEN release_date
        ELSE 0 
    END AS available
FROM storage_rooms

Which is fine and returns something like this:

在此处输入图片说明

Now I need to check if it is already booked. To give you an idea of what I'm thinking (doesn't work):

SELECT storage_rooms.*,
    (SELECT
    CASE
        WHEN release_date <= CURDATE() OR orders.status_id IN (3, 4) THEN 1
        WHEN release_date <= ADDDATE(CURDATE(), INTERVAL 30 DAY) THEN release_date
        ELSE 0 
    END AS available
    FROM storage_rooms
    LEFT OUTER JOIN orders
    ON storage_rooms.id = orders.storage_room_id)
FROM storage_rooms 

I gather I might need another subquery with a groupBy? I don't find joins super intuitive and I'm a bit lost so any assistance would be welcome.

I'm not totally sure it will work but you can try this:

SELECT storage_rooms.*,
    CASE
        WHEN release_date <= CURDATE() OR availibility.order_status_id IN (3, 4) THEN 1
        WHEN release_date <= ADDDATE(CURDATE(), INTERVAL 30 DAY) THEN release_date
        ELSE 0 
    END AS available
FROM storage_rooms
LEFT JOIN 
    ( SELECT id AS order_id, status_id AS order_status_id, storage_room_id AS order_storage_room_id
          FROM orders WHERE status_id IN (3, 4)
          GROUP BY storage_room_id
    ) availibility
    ON (storage_rooms.id = availibility.order_storage_room_id)

The thing here is that the LEFT JOIN is adding to the results the columns needed to check your availability. But the trick is you need a subquery so that the table joined contains only one entry for each room or else the results are duplicated. The subquery must be limited to the positive matches you want to take in consideration with a WHERE , because the GROUP BY will only keep the first row found and you don't want this information lost in the grouping.

FROM OP'S COMMENTS THE FINAL QUERY IS:

SELECT storage_rooms.*,
    CASE
        WHEN release_date <= CURDATE() OR aggregate.order_status_id IS NULL THEN 1
        WHEN release_date <= ADDDATE(CURDATE(), INTERVAL 30 DAY) THEN release_date
        ELSE 0
    END AS available
FROM storage_rooms
LEFT JOIN
    (SELECT storage_room_id, order_status_id
        FROM orders WHERE order_status_id IN (1, 2)
        GROUP BY storage_room_id, order_status_id
    ) aggregate
    ON storage_rooms.id = aggregate.storage_room_id

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