当表之间没有物理连接时优化 SQL 查询
Optimized SQL query when there's no physical connection between tables
当 table 之间没有逻辑联系时,我需要帮助编写更优化的 SQL 查询。我写了一些子查询,但我对它不满意,因为我重复了两次几乎相同的子查询。
方案是这样的:
create table rate (
rate_date date,
value decimal(10,2),
multiplier integer,
name varchar(3)
);
create table amount (
amount decimal(10,2),
amount_year date,
rate_name varchar(3)
);
我希望 AMOUNT
table 中的每个金额都使用 RATE
table 中的乘数和比率值来计算,就像这样 amount / multiplier * rate
。 table 的共同点是名称(一些代码标识符)和日期。这些应该用于收集数据。仅考虑 amount_year 的最新汇率。
如果您愿意提供帮助,可以查看此 fiddle。这是我的尝试。
select am.amount /
(
select ra.multiplier
from rate ra
where ra.rate_date = (select max(rate_date)
from rate
where year(rate_date) = year(am.amount_year) and name = am.rate_name)
and ra.name = am.rate_name
) * (
select ra.value
from rate ra
where ra.rate_date = (select max(rate_date)
from rate
where year(rate_date) = year(am.amount_year) and name = am.rate_name)
and ra.name = am.rate_name
) as calculated_amount
from amount am;
你的子查询是一样的,所以你可以合二为一:
select am.amount /
(select ra.multiplier * ra.value
from rate ra
where ra.rate_date = (select max(rate_date)
from rate
where year(rate_date) = year(am.amount_year) and name = am.rate_name) and ra.name = am.rate_name
)
) as calculated_amount
from amount am;
或者这可以表述为:
select am.amount /
(select ra.multiplier * ra.value
from rate ra
where year(ra.rate_date) = year(am.amount_year) and name = am.rate_name
order by ra.rate_date desc
limit 1
) as calculated_amount
from amount am;
如果您愿意,可以将此作为带有 where
子句的 join
执行:
select (am.amount / ra.multiplier * ra.value) as calculated_amount
from amount am join
rate ra
on ra.name = am.name and
year(rate_date) = year(am.amount_year)
where ra.date = (select max(r2.rate_date)
from rate r2
where year(r2.rate_date) = year(r.rate_date) and
r2.name = ra.name
);
为了性能,从 rate(name, rate_date, multiplier, value)
上的索引开始。对于任一查询。
为了获得更好的性能,您可能需要将 "year" 作为单独的列存储在 table 中。
您可以使用单个子查询获取每年的最新乘数和值。然后将其与 amount
table 一起进行除法。
SELECT am.amount / (r2.multiplier * r2.value) AS calculated_amount
FROM amount AS am
JOIN (SELECT YEAR(rate_date) AS year, MAX(rate_date) AS maxdate
FROM rate
GROUP BY year) AS r1 ON YEAR(am.rate_date) = r1.year
JOIN rate AS r2 ON r1.maxdate = r2.rate_date
当 table 之间没有逻辑联系时,我需要帮助编写更优化的 SQL 查询。我写了一些子查询,但我对它不满意,因为我重复了两次几乎相同的子查询。
方案是这样的:
create table rate (
rate_date date,
value decimal(10,2),
multiplier integer,
name varchar(3)
);
create table amount (
amount decimal(10,2),
amount_year date,
rate_name varchar(3)
);
我希望 AMOUNT
table 中的每个金额都使用 RATE
table 中的乘数和比率值来计算,就像这样 amount / multiplier * rate
。 table 的共同点是名称(一些代码标识符)和日期。这些应该用于收集数据。仅考虑 amount_year 的最新汇率。
如果您愿意提供帮助,可以查看此 fiddle。这是我的尝试。
select am.amount /
(
select ra.multiplier
from rate ra
where ra.rate_date = (select max(rate_date)
from rate
where year(rate_date) = year(am.amount_year) and name = am.rate_name)
and ra.name = am.rate_name
) * (
select ra.value
from rate ra
where ra.rate_date = (select max(rate_date)
from rate
where year(rate_date) = year(am.amount_year) and name = am.rate_name)
and ra.name = am.rate_name
) as calculated_amount
from amount am;
你的子查询是一样的,所以你可以合二为一:
select am.amount /
(select ra.multiplier * ra.value
from rate ra
where ra.rate_date = (select max(rate_date)
from rate
where year(rate_date) = year(am.amount_year) and name = am.rate_name) and ra.name = am.rate_name
)
) as calculated_amount
from amount am;
或者这可以表述为:
select am.amount /
(select ra.multiplier * ra.value
from rate ra
where year(ra.rate_date) = year(am.amount_year) and name = am.rate_name
order by ra.rate_date desc
limit 1
) as calculated_amount
from amount am;
如果您愿意,可以将此作为带有 where
子句的 join
执行:
select (am.amount / ra.multiplier * ra.value) as calculated_amount
from amount am join
rate ra
on ra.name = am.name and
year(rate_date) = year(am.amount_year)
where ra.date = (select max(r2.rate_date)
from rate r2
where year(r2.rate_date) = year(r.rate_date) and
r2.name = ra.name
);
为了性能,从 rate(name, rate_date, multiplier, value)
上的索引开始。对于任一查询。
为了获得更好的性能,您可能需要将 "year" 作为单独的列存储在 table 中。
您可以使用单个子查询获取每年的最新乘数和值。然后将其与 amount
table 一起进行除法。
SELECT am.amount / (r2.multiplier * r2.value) AS calculated_amount
FROM amount AS am
JOIN (SELECT YEAR(rate_date) AS year, MAX(rate_date) AS maxdate
FROM rate
GROUP BY year) AS r1 ON YEAR(am.rate_date) = r1.year
JOIN rate AS r2 ON r1.maxdate = r2.rate_date