简体   繁体   中英

SQL getting a column to match multiple conditions in CASE

Presented with the following snippet of SQL:

CASE
    WHEN (YEAR('2018-12-31') - YEAR(`StartDateTCDR`) - (DATE_FORMAT('2018-12-31', '%m%d') < DATE_FORMAT(`StartDateTCDR`, '%m%d')) >= 30) THEN '>= 30 (inclusive)'
    WHEN (YEAR('2018-12-31') - YEAR(`StartDateTCDR`) - (DATE_FORMAT('2018-12-31', '%m%d') < DATE_FORMAT(`StartDateTCDR`, '%m%d')) >= 20) THEN '>= 20 (inclusive)'
    WHEN (YEAR('2018-12-31') - YEAR(`StartDateTCDR`) - (DATE_FORMAT('2018-12-31', '%m%d') < DATE_FORMAT(`StartDateTCDR`, '%m%d')) >= 10) THEN '>= 10 (inclusive)'
    ELSE '< 10'
END

(The full query is below, the snippet above is just to highlight the problem)

The above current results in exclusive matches:

 (30 <= date_diff) = '>= 30'
 (20 <= date_diff <= 30) = '>= 20'
 (10 <= date_diff <= 20) = '>= 10'
 (date_diff < 10) = '< 10'

But what I need is inclusive matches:

 (30 <= date_diff <= 0) = '>= 30'
 (20 <= date_diff <= 0) = '>= 20'
 (10 <= date_diff <= 0) = '>= 10'
 (date_diff < 10) = '< 10'

So - if a record is older than 30 years, it must be categorized in in >= 10 , >= 20 as well as >= 30 , and so on.

FULL QUERY

    SELECT
        COUNT(*) AS `RecordCount`, `ExistingPlanned`, `ResponsibleOrg`, `StartDateTCDR`, `EndDateTCDR`, `SpecificEndDate`, `ResponsibleOrgOut`,
        (CASE
            WHEN (`EndDateTCDR` < '1001-01-01' AND `SpecificEndDate` = 0) THEN '2018-12-31'
            WHEN (`EndDateTCDR` < '1001-01-01' AND `SpecificEndDate` = 1) THEN '-'
            ELSE `EndDateTCDR`
        END) AS `EndDate`,
        (CASE
            WHEN (`StartDateTCDR` < '1001-01-01') THEN '-'
            ELSE `StartDateTCDR`
        END) AS `StartDate`,
        (CASE
            WHEN (`StartDateTCDR` < '1001-01-01') THEN '-'
            WHEN (`StartDateTCDR` > '1001-01-01' AND `EndDateTCDR` < '1001-01-01' AND `SpecificEndDate` = 1) THEN '-'
            WHEN (`StartDateTCDR` > '1001-01-01' AND `EndDateTCDR` < '1001-01-01' AND `SpecificEndDate` = 0) THEN (
                CASE
                    WHEN (YEAR('2018-12-31') - YEAR(`StartDateTCDR`) - (DATE_FORMAT('2018-12-31', '%m%d') < DATE_FORMAT(`StartDateTCDR`, '%m%d')) >= 30) THEN '>= 30 (inclusive)'
                    WHEN (YEAR('2018-12-31') - YEAR(`StartDateTCDR`) - (DATE_FORMAT('2018-12-31', '%m%d') < DATE_FORMAT(`StartDateTCDR`, '%m%d')) >= 20) THEN '>= 20 (inclusive)'
                    WHEN (YEAR('2018-12-31') - YEAR(`StartDateTCDR`) - (DATE_FORMAT('2018-12-31', '%m%d') < DATE_FORMAT(`StartDateTCDR`, '%m%d')) >= 10) THEN '>= 10 (inclusive)'
                    ELSE '< 10'
                END
            )
            WHEN (`StartDateTCDR` > '1001-01-01' AND `EndDateTCDR` > '1001-01-01') THEN (
                CASE
                    WHEN (YEAR(`EndDateTCDR`) - YEAR(`StartDateTCDR`) - (DATE_FORMAT(`EndDateTCDR`, '%m%d') < DATE_FORMAT(`StartDateTCDR`, '%m%d')) >= 30) THEN '>= 30 (inclusive)'
                    WHEN (YEAR(`EndDateTCDR`) - YEAR(`StartDateTCDR`) - (DATE_FORMAT(`EndDateTCDR`, '%m%d') < DATE_FORMAT(`StartDateTCDR`, '%m%d')) >= 20) THEN '>= 20 (inclusive)'
                    WHEN (YEAR(`EndDateTCDR`) - YEAR(`StartDateTCDR`) - (DATE_FORMAT(`EndDateTCDR`, '%m%d') < DATE_FORMAT(`StartDateTCDR`, '%m%d')) >= 10) THEN '>= 10 (inclusive)'
                    ELSE '< 10'
                END
            )
        END) AS `TCDRLength`,
        (CASE
            WHEN (`StartDateTCDR` < '1001-01-01') THEN '-'
            WHEN (`StartDateTCDR` > '1001-01-01' AND `EndDateTCDR` < '1001-01-01' AND `SpecificEndDate` = 1) THEN '-'
            WHEN (`StartDateTCDR` > '1001-01-01' AND `EndDateTCDR` < '1001-01-01' AND `SpecificEndDate` = 0) THEN (
                ROUND((DATEDIFF('2018-12-31', `StartDateTCDR`) / 365), 2)
            )
            WHEN (`StartDateTCDR` > '1001-01-01' AND `EndDateTCDR` > '1001-01-01') THEN (
                ROUND((DATEDIFF(`EndDateTCDR`, `StartDateTCDR`) / 365), 2)
            )
        END) AS `ActualLength`
    FROM `data_records`
    LEFT JOIN `RespOrgLUT`
        ON `ResponsibleOrgIn` = `ResponsibleOrg`
    GROUP BY `ExistingPlanned`, `ResponsibleOrg`, `StartDateTCDR`, `EndDateTCDR`, `SpecificEndDate`, `ResponsibleOrgOut`, `StartDate`, `EndDate`, `ActualLength`, `TCDRLength`
    ORDER BY `ResponsibleOrg` ASC, `RecordCount` DESC, `ResponsibleOrgOut` ASC, `ActualLength` DESC, `TCDRLength` DESC
    LIMIT 0, 2000

EDIT 1

Using the suggestion by @Barmar, my query now looks like this, resulting in an error: #1248 - Every derived table must have its own alias , so I clearly implemented it wrong, so any further assistance will be appreciated.

    SELECT
        COUNT(*) AS `RecordCount`, `ExistingPlanned`, `ResponsibleOrg`, `StartDateTCDR`, `EndDateTCDR`, `SpecificEndDate`, `ResponsibleOrgOut`,
        (CASE
            WHEN (`EndDateTCDR` < '1001-01-01' AND `SpecificEndDate` = 0) THEN '2018-12-31'
            WHEN (`EndDateTCDR` < '1001-01-01' AND `SpecificEndDate` = 1) THEN '-'
            ELSE `EndDateTCDR`
        END) AS `EndDate`,
        (CASE
            WHEN (`StartDateTCDR` < '1001-01-01') THEN '-'
            ELSE `StartDateTCDR`
        END) AS `StartDate`,
        (CASE
            WHEN (`StartDateTCDR` < '1001-01-01') THEN '-'
            WHEN (`StartDateTCDR` > '1001-01-01' AND `EndDateTCDR` < '1001-01-01' AND `SpecificEndDate` = 1) THEN '-'
            WHEN (`StartDateTCDR` > '1001-01-01' AND `EndDateTCDR` < '1001-01-01' AND `SpecificEndDate` = 0) THEN (
                CASE
                    WHEN (YEAR('2018-12-31') - YEAR(`StartDateTCDR`) - (DATE_FORMAT('2018-12-31', '%m%d') < DATE_FORMAT(`StartDateTCDR`, '%m%d')) >= 30) THEN '>= 30 (inclusive)'
                    WHEN (YEAR('2018-12-31') - YEAR(`StartDateTCDR`) - (DATE_FORMAT('2018-12-31', '%m%d') < DATE_FORMAT(`StartDateTCDR`, '%m%d')) >= 20) THEN '>= 20 (inclusive)'
                    WHEN (YEAR('2018-12-31') - YEAR(`StartDateTCDR`) - (DATE_FORMAT('2018-12-31', '%m%d') < DATE_FORMAT(`StartDateTCDR`, '%m%d')) >= 10) THEN '>= 10 (inclusive)'
                    ELSE '< 10'
                END
            )
            WHEN (`StartDateTCDR` > '1001-01-01' AND `EndDateTCDR` > '1001-01-01') THEN (
                CASE
                    WHEN (YEAR(`EndDateTCDR`) - YEAR(`StartDateTCDR`) - (DATE_FORMAT(`EndDateTCDR`, '%m%d') < DATE_FORMAT(`StartDateTCDR`, '%m%d')) >= 30) THEN '>= 30 (inclusive)'
                    WHEN (YEAR(`EndDateTCDR`) - YEAR(`StartDateTCDR`) - (DATE_FORMAT(`EndDateTCDR`, '%m%d') < DATE_FORMAT(`StartDateTCDR`, '%m%d')) >= 20) THEN '>= 20 (inclusive)'
                    WHEN (YEAR(`EndDateTCDR`) - YEAR(`StartDateTCDR`) - (DATE_FORMAT(`EndDateTCDR`, '%m%d') < DATE_FORMAT(`StartDateTCDR`, '%m%d')) >= 10) THEN '>= 10 (inclusive)'
                    ELSE '< 10'
                END
            )
        END) AS `TCDRLength`,
        (CASE
            WHEN (`StartDateTCDR` < '1001-01-01') THEN '-'
            WHEN (`StartDateTCDR` > '1001-01-01' AND `EndDateTCDR` < '1001-01-01' AND `SpecificEndDate` = 1) THEN '-'
            WHEN (`StartDateTCDR` > '1001-01-01' AND `EndDateTCDR` < '1001-01-01' AND `SpecificEndDate` = 0) THEN (
                ROUND((DATEDIFF('2018-12-31', `StartDateTCDR`) / 365), 2)
            )
            WHEN (`StartDateTCDR` > '1001-01-01' AND `EndDateTCDR` > '1001-01-01') THEN (
                ROUND((DATEDIFF(`EndDateTCDR`, `StartDateTCDR`) / 365), 2)
            )
        END) AS `ActualLength`
    FROM `data_records`
    LEFT JOIN `RespOrgLUT` ON `ResponsibleOrgIn` = `ResponsibleOrg`
    LEFT JOIN (
        SELECT `category`, COUNT(*)
        FROM `data_records` dr
        JOIN (
            SELECT '< 10' AS `category`
            UNION
            SELECT '>= 10'
            UNION
            SELECT '>= 20'
            UNION
            SELECT '>= 30'
        ) AS c
            ON (`category` = '>= 30' AND (YEAR('2018-12-31') - YEAR(`dr`.`StartDateTCDR`) - (DATE_FORMAT('2018-12-31', '%m%d') < DATE_FORMAT(`dr`.`StartDateTCDR`, '%m%d')) >= 30))
            OR (`category` = '>= 20' AND (YEAR('2018-12-31') - YEAR(`dr`.`StartDateTCDR`) - (DATE_FORMAT('2018-12-31', '%m%d') < DATE_FORMAT(`dr`.`StartDateTCDR`, '%m%d')) >= 20))
            OR (`category` = '>= 10' AND (YEAR('2018-12-31') - YEAR(`dr`.`StartDateTCDR`) - (DATE_FORMAT('2018-12-31', '%m%d') < DATE_FORMAT(`dr`.`StartDateTCDR`, '%m%d')) >= 10))
            OR (`category` = '< 10' AND (YEAR('2018-12-31') - YEAR(`dr`.`StartDateTCDR`) - (DATE_FORMAT('2018-12-31', '%m%d') < DATE_FORMAT(`dr`.`StartDateTCDR`, '%m%d')) < 10))
    )
    GROUP BY `ExistingPlanned`, `ResponsibleOrg`, `StartDateTCDR`, `EndDateTCDR`, `SpecificEndDate`, `ResponsibleOrgOut`, `StartDate`, `EndDate`, `ActualLength`, `TCDRLength`
    ORDER BY `ResponsibleOrg` ASC, `RecordCount` DESC, `ResponsibleOrgOut` ASC, `ActualLength` DESC, `TCDRLength` DESC
    LIMIT 0, 2000

Join your table with a subquery that returns all the categories, then check whether the row fits the category. Here's a simplification showing just that part of the query, I don't have time right now to fill in your entire query.

SELECT category, COUNT(*)
FROM ...
JOIN (
    SELECT '< 10' AS category
    UNION
    SELECT '>= 10'
    UNION
    SELECT '>= 20'
    UNION
    SELECT '>= 30'
) AS c ON (category = '>= 30' AND (YEAR('2018-12-31') - YEAR(`StartDateTCDR`) - (DATE_FORMAT('2018-12-31', '%m%d') < DATE_FORMAT(`StartDateTCDR`, '%m%d')) >= 30))
        OR (category = '>= 20' AND (YEAR('2018-12-31') - YEAR(`StartDateTCDR`) - (DATE_FORMAT('2018-12-31', '%m%d') < DATE_FORMAT(`StartDateTCDR`, '%m%d')) >= 20))
        OR (category = '>= 10' AND (YEAR('2018-12-31') - YEAR(`StartDateTCDR`) - (DATE_FORMAT('2018-12-31', '%m%d') < DATE_FORMAT(`StartDateTCDR`, '%m%d')) >= 10))
        OR (category = '< 10' AND (YEAR('2018-12-31') - YEAR(`StartDateTCDR`) - (DATE_FORMAT('2018-12-31', '%m%d') < DATE_FORMAT(`StartDateTCDR`, '%m%d')) < 10))
GROUP BY Category, `ExistingPlanned`, `ResponsibleOrg`, `StartDateTCDR`, `EndDateTCDR`, `SpecificEndDate`, `ResponsibleOrgOut`, `StartDate`, `EndDate`, `ActualLength`, `TCDRLength`

Another way to do it would be a UNION of 4 queries, which each test for the age in their WHERE clauses.

In this case, the solution was not necessary to be done with a single query where the processing was done on SQL side. I opted for a broader query that got all the data at one shot, then processed the result set with PHP to get to the results I need.

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