如果在UNION ALL查询中未找到任何行,则返回默认值

时间:2015-01-14 18:05:51

标签: mysql join

方案

我有一个从这个question开发的查询,优化的一部分是创建一个MySql视图,用于为用户和销售生成统计信息,问题是当没有结果时从结果表中省略SELECT行。

问题

如果找不到任何SELECT的行,如何告诉MySql设置默认值(例如0)?

代码

这是用于创建视图的代码

CREATE OR REPLACE VIEW user_events AS
    SELECT 'Complete profiles' AS type, created_at
        FROM users
        WHERE completed_registration = 1

    UNION ALL SELECT 'Incomplete profiles', created_at
        FROM users
        WHERE completed_registration = 0 AND verified_email = 1

    UNION ALL SELECT 'Unverified profiles', created_at
        FROM users
        WHERE verified_email = 0

    UNION ALL SELECT 'Onsite Teachers', created_at
        FROM onsite_teachers

    UNION ALL SELECT 'Onsite Teachers hired', created_at
        FROM purchases
            INNER JOIN purchased_profiles
                ON purchased_profiles.purchase_id = purchases.id
                 AND purchased_profiles.profile_type = 'onsite_teacher'
        WHERE purchases.transaction_status = 'completed'

    UNION ALL SELECT 'Translators', created_at
        FROM translators

    UNION ALL SELECT 'Translators hired', created_at
        FROM purchases
            INNER JOIN purchased_profiles
                ON purchased_profiles.purchase_id = purchases.id
                AND purchased_profiles.profile_type = 'translator'
        WHERE purchases.transaction_status = 'completed'

    UNION ALL SELECT 'Interpreters', created_at
        FROM interpreters

    UNION ALL SELECT 'Interpreters hired', created_at
        FROM purchases
            INNER JOIN purchased_profiles
                ON purchased_profiles.purchase_id = purchases.id
                AND purchased_profiles.profile_type = 'interpreter'
        WHERE purchases.transaction_status = 'completed';

这是查询过去6个月(包括当月)总数的代码。

SELECT 
    type, 
    COUNT(CASE 
        WHEN created_at >= CAST(CURDATE() - INTERVAL (DAYOFMONTH(CURDATE()) - 1) DAY AS DATETIME) 
        THEN 1 
    END) AS 0_month_ago, 

    COUNT(CASE 
        WHEN created_at BETWEEN CAST(CURDATE() - INTERVAL (DAYOFMONTH(CURDATE()) - 1) DAY - INTERVAL 1 MONTH AS DATETIME)
            AND CAST(LAST_DAY(CURDATE() - INTERVAL 1 MONTH) + INTERVAL 1 DAY AS DATETIME)
        THEN 1 
    END) AS 1_month_ago,

    COUNT(CASE 
        WHEN created_at BETWEEN CAST(CURDATE() - INTERVAL (DAYOFMONTH(CURDATE()) - 1) DAY - INTERVAL 2 MONTH AS DATETIME)
            AND CAST(LAST_DAY(CURDATE() - INTERVAL 2 MONTH) + INTERVAL 1 DAY AS DATETIME)
        THEN 1 
    END) AS 2_months_ago,

    COUNT(CASE 
        WHEN created_at BETWEEN CAST(CURDATE() - INTERVAL (DAYOFMONTH(CURDATE()) - 1) DAY - INTERVAL 3 MONTH AS DATETIME)
            AND CAST(LAST_DAY(CURDATE() - INTERVAL 3 MONTH) + INTERVAL 1 DAY AS DATETIME)
        THEN 1 
    END) AS 3_months_ago,

    COUNT(CASE 
        WHEN created_at BETWEEN CAST(CURDATE() - INTERVAL (DAYOFMONTH(CURDATE()) - 1) DAY - INTERVAL 4 MONTH AS DATETIME)
            AND CAST(LAST_DAY(CURDATE() - INTERVAL 4 MONTH) + INTERVAL 1 DAY AS DATETIME)
        THEN 1 
    END) AS 4_months_ago,

    COUNT(CASE 
        WHEN created_at BETWEEN CAST(CURDATE() - INTERVAL (DAYOFMONTH(CURDATE()) - 1) DAY - INTERVAL 5 MONTH AS DATETIME)
            AND CAST(LAST_DAY(CURDATE() - INTERVAL 5 MONTH) + INTERVAL 1 DAY AS DATETIME)
        THEN 1 
    END) AS 5_months_ago
FROM 
    user_events
GROUP BY 
    type;

当前输出

如果您仔细查看没有Interpreters hiredTranslators hired行,我希望设置这些行,如果它们返回null

则归零
+=========================+===============+===============+===============+==============+===============+===============+
|          type           |  0_month_ago  |  1_month_ago  |  2_month_ago  | 3_month_ago  |  4_month_ago  |  5_month_ago  |
+=========================+===============+===============+===============+==============+===============+===============+
|    Complete profiles    |       7       |      20       |      14       |      25      |      30       |       7       |
+-------------------------+---------------+---------------+---------------+--------------+---------------+---------------+
|   Incomplete profiles   |      12       |      27       |      56       |      45      |      48       |      23       |
+-------------------------+---------------+---------------+---------------+--------------+---------------+---------------+
|   Unverified profiles   |       3       |      16       |      23       |       5      |       0       |       9       |
+-------------------------+---------------+---------------+---------------+--------------+---------------+---------------+
|    Onsite Teachers      |      11       |      36       |       8       |      15      |      46       |      12       |
+-------------------------+---------------+---------------+---------------+--------------+---------------+---------------+
|  Onsite Teachers hired  |       0       |       0       |      12       |       9      |       3       |       0       |
+-------------------------+---------------+---------------+---------------+--------------+---------------+---------------+
|      Interpreters       |       4       |      21       |      27       |      46      |      45       |      28       |
+-------------------------+---------------+---------------+---------------+--------------+---------------+---------------+
|      Translators        |       7       |      20       |      19       |      27      |      19       |      42       |
+-------------------------+---------------+---------------+---------------+--------------+---------------+---------------+

1 个答案:

答案 0 :(得分:1)

user_events视图是一种日志,看起来像

type                  | created_at
======================+==============
Interpreters hired    | 2014-12-12
Interpreters hired    | 2014-12-14
Interpreters hired    | 2014-12-16
Interpreters hired    | 2015-01-02

但是,如果没有雇用过口译员,则不会有type = 'Interpreters hired'的行。在这种情况下,计数查询无法凭空创建Interpreters hired行。

解决方案是确保Interpreters hired视图中出现user_events行,无论如何。您可以创建没有created_at日期的虚构行。这样,总会有GROUP BY的内容,但不一定是COUNT()的内容。

CREATE OR REPLACE VIEW user_events AS
    SELECT 'Complete profiles' AS type, created_at
        FROM users
        WHERE completed_registration = 1

    UNION ALL SELECT 'Incomplete profiles', created_at
        FROM users
        WHERE completed_registration = 0 AND verified_email = 1

    UNION ALL SELECT 'Unverified profiles', created_at
        FROM users
        WHERE verified_email = 0

    UNION ALL SELECT 'Onsite Teachers', created_at
        FROM onsite_teachers

    UNION ALL SELECT 'Onsite Teachers hired', created_at
        FROM purchases
            INNER JOIN purchased_profiles
                ON purchased_profiles.purchase_id = purchases.id
                 AND purchased_profiles.profile_type = 'onsite_teacher'
        WHERE purchases.transaction_status = 'completed'
    UNION ALL SELECT 'Onsite Teachers hired', NULL

    UNION ALL SELECT 'Translators', created_at
        FROM translators

    UNION ALL SELECT 'Translators hired', created_at
        FROM purchases
            INNER JOIN purchased_profiles
                ON purchased_profiles.purchase_id = purchases.id
                AND purchased_profiles.profile_type = 'translator'
        WHERE purchases.transaction_status = 'completed'
    UNION ALL SELECT 'Translators hired', NULL

    UNION ALL SELECT 'Interpreters', created_at
        FROM interpreters

    UNION ALL SELECT 'Interpreters hired', created_at
        FROM purchases
            INNER JOIN purchased_profiles
                ON purchased_profiles.purchase_id = purchases.id
                AND purchased_profiles.profile_type = 'interpreter'
        WHERE purchases.transaction_status = 'completed'
    UNION ALL SELECT 'Interpreters hired', NULL;