繁体   English   中英

SQL查询联合最佳实践

[英]SQL query union best practice

我试图从表中提取数据时对数据进行分类。 数据具有通过每行中的“ valid_from”和“ valid_to”日期字段保存的历史记录。

我想提取数据并对其进行如下限定:

NEW => WHERE CURRENT_DATE BETWEEN valid_from AND (valid_from + 1 MOTNH)
CURRENT => WHERE CURRENT_DATE > (valid_from + 1 MOTNH)
RETIRED => the rest of the rows, so the "dish_id" items not in the tables above, BUT 
           returning the values from the row containing MAX(valid_to) date.

我这样做是最好/更有效的方法吗? 提前致谢!

SELECT
    menu_table.dish_id,
    menu_table.dish_title,
    menu_table.marketing_desc,
    menu_table_status.rrp_inc_gst,
    menu_table_status.lowest_rrp,
    menu_table_status.highest_rrp,
    'n' as status
FROM 
    menu_table,
    menu_table_status
WHERE
    CURRENT_DATE BETWEEN menu_table_status.valid_from_date AND DATE_ADD(menu_table_status.valid_from_date, INTERVAL 1 MONTH) 
    AND CURRENT_DATE < menu_table_status.valid_to_date
    AND menu_table.dish_id = menu_table_status.dish_id
UNION
SELECT
    menu_table.dish_id,
    menu_table.dish_title,
    menu_table.marketing_desc,
    menu_table_status.rrp_inc_gst,
    menu_table_status.lowest_rrp,
    menu_table_status.highest_rrp,
    'c' as status
FROM 
    menu_table,
    menu_table_status
WHERE
    CURRENT_DATE > DATE_ADD(menu_table_status.valid_from_date, INTERVAL 1 MONTH) 
    AND CURRENT_DATE < menu_table_status.valid_to_date
    AND menu_table.dish_id = menu_table_status.dish_id              
UNION
SELECT
    menu_table.dish_id,
    menu_table.dish_title,
    menu_table.marketing_desc,
    menu_table_status.rrp_inc_gst,
    menu_table_status.lowest_rrp,
    menu_table_status.highest_rrp,
    'r' as status
FROM 
    menu_table,
    menu_table_status
WHERE
    menu_table_status.valid_to_date
    AND menu_table.dish_id NOT IN (SELECT inside_table1.dish_id
                       FROM menu_table_status AS inside_table1
                       WHERE CURRENT_DATE BETWEEN inside_table1.valid_from_date 
                                                          AND inside_table1.valid_to_date)
    AND menu_table_status.valid_to_date = (SELECT MAX(inside_table2.valid_to_date)
                           FROM menu_table_status AS inside_table2
                           WHERE inside_table2.dish_id = menu_table_status.dish_id)
    AND menu_table.dish_id = menu_table_status.dish_id

不用多看,您肯定会混淆最后一个where子句中的日期。 无论如何,您的陈述很复杂。 只需选择所有记录(无论您要如何执行),然后查看每个记录的日期来确定要提供的状态:

SELECT
  menu_table.dish_id,
  menu_table.dish_title,
  menu_table.marketing_desc,
  menu_table_status.rrp_inc_gst,
  menu_table_status.lowest_rrp,
  menu_table_status.highest_rrp,
  CASE 
    WHEN
      CURRENT_DATE BETWEEN menu_table_status.valid_from_date AND DATE_ADD(menu_table_status.valid_from_date, INTERVAL 1 MONTH) 
      AND CURRENT_DATE < menu_table_status.valid_to_date
    THEN 'n' 
    WHEN
      CURRENT_DATE > DATE_ADD(menu_table_status.valid_from_date, INTERVAL 1 MONTH) 
      AND CURRENT_DATE < menu_table_status.valid_to_date
    THEN 'c'
    ELSE 'r'
  END as status
FROM menu_table
INNER JOIN menu_table_status ON menu_table.dish_id = menu_table_status.dish_id;

顺便说一句:请不要在列出所有用逗号分隔的表时使用旧的联接语法。 容易出错,这就是为什么从1992年开始就有“新”语法可用的原因。

编辑:我发现了你的错误。 无需检查CURRENT_DATE < menu_table_status.valid_to_datemenu_table_status.valid_to_date仅检查menu_table_status.valid_to_date从而将日期视为布尔值,这在MySQL中是特殊的。

再说一遍:当合并不同的集合(您是由于状态字母不同而引起的)时,请使用UNION ALL,而不是UNION。 UNION用于删除重复项。 当您知道没有重复项时,为什么dbms会检查所有记录?

如果您不需要一口气执行此操作,建议您将第一步提取到临时表中,然后将第二步定义为该临时表在dish_id上的左连接,其中dish_id为NULL:

CREATE TEMPORARY TABLE step1 AS (
SELECT
    mt.dish_id,
    mt.dish_title,
    mt.marketing_desc,
    mts.rrp_inc_gst,
    mts.lowest_rrp,
    mts.highest_rrp,
    (
        if(CURRENT_DATE<DATE_ADD(mts.valid_from_date, INTERVAL 1 MONTH),
           'n', 'c')
    ) as status
FROM 
    menu_table mt 
    JOIN menu_table_status mts ON mt.dish_id=mts.dish_id 
    WHERE CURRENT_DATE BETWEEN mts.valid_from_date AND mts.valid_to_date-1
);

SELECT step1.*
UNION
SELECT
    mt.dish_id,
    mt.dish_title,
    mt.marketing_desc,
    mts.rrp_inc_gst,
    mts.lowest_rrp,
    mts.highest_rrp,
    'r' as status
FROM
    menu_table mt 
    LEFT JOIN step1 s1 on s1.dish_id=mt.dish_id WHERE s1.dish_id is NULL
    JOIN menu_table_status mts ON mt.dish_id=mts.dish_id;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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