[英]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_date
, menu_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.