SQL查询联合最佳实践

时间:2014-04-17 08:37:48

标签: mysql sql

我正在尝试对数据进行分类,因为我从表中提取数据。数据具有通过每行中的“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

2 个答案:

答案 0 :(得分:1)

如果没有多看,你肯定会在最后的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;

BTW:请不要使用旧的连接语法,列出所有以逗号分隔的表。它容易出错,这就是为什么从1992年开始有一种“新”语法的原因。

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

还有一句话:当联合集合是不同的(你的是由于不同的状态字母)时,使用UNION ALL,而不是UNION。 UNION用于删除重复项。为什么dbms会在您知道没有重复项时检查所有记录?

答案 1 :(得分:0)

如果您不需要一次性执行此操作,我建议将第一步提取到一个临时表中,然后将第二步定义为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;