MySQL从特定的相关记录获取所有数据
我正在寻找一种在MySQL中为表中的每条记录输出所选相关记录的方法。我会进一步解释 我有两张表,分别是货币和汇率。这些表由一个货币代码字段连接,每个货币记录都有多个相关的汇率记录,每个汇率记录代表不同的一天。因此,货币和汇率之间存在着1:1的关系 我想从MySQL从特定的相关记录获取所有数据,mysql,join,Mysql,Join,我正在寻找一种在MySQL中为表中的每条记录输出所选相关记录的方法。我会进一步解释 我有两张表,分别是货币和汇率。这些表由一个货币代码字段连接,每个货币记录都有多个相关的汇率记录,每个汇率记录代表不同的一天。因此,货币和汇率之间存在着1:1的关系 我想从exchange\u rates表中检索每种货币的完整记录,但能够定义要选择的相关记录的特定条件。不仅是每种货币的最新汇率,还可能是每种货币的最新汇率记录,该记录包含标准\u x=NULL 很遗憾,您不能在派生表中使用LIMIT,否则类似的内容将
exchange\u rates
表中检索每种货币的完整记录,但能够定义要选择的相关记录的特定条件。不仅是每种货币的最新汇率,还可能是每种货币的最新汇率
记录,该记录包含标准\u x=NULL
很遗憾,您不能在派生表中使用LIMIT
,否则类似的内容将是一个简洁易读的解决方案
SELECT `currencies`.`currency_code`, `currencies`.`country`, `exchange_rates`.`id`,
FROM_UNIXTIME(`exchange_rates`.`datestamp`), `rate`
FROM `currencies`
INNER JOIN (
SELECT `id`, `currency_code`, `invoice_id`, `datestamp`, `rate`
FROM `exchange_rates`
WHERE `criteria_x`=NULL AND `criteria_y` LIKE 'A'
ORDER BY `datestamp` DESC
LIMIT 0, 1
) AS `exchange_rates` ON `currencies`.`currency_code`=`exchange_rates`.`currency_code`
ORDER BY `currencies`.`country`
LIMIT
子句应用于父查询,而不是派生表
这是我找到的唯一方法
SELECT `currencies`.`currency_code`, `currencies`.`country`,
FROM_UNIXTIME( SUBSTRING_INDEX( SUBSTRING_INDEX(`exchange_rates`.`concat`, '-', 1), '-', -1)) AS `datestamp`,
SUBSTRING_INDEX( SUBSTRING_INDEX(`exchange_rates`.`concat`, '-', 2), '-', -1) AS `id`,
SUBSTRING_INDEX( SUBSTRING_INDEX(`exchange_rates`.`concat`, '-', 3), '-', -1) AS `rate`
FROM `currencies`
INNER JOIN (
SELECT `currency_code`, MAX(CONCAT_WS('-', `datestamp`, `id`, `rate`)) AS `concat`
FROM `exchange_rates`
WHERE `criteria_x`=NULL AND `criteria_y` LIKE 'A'
GROUP BY `exchange_rates`.`currency_code`
) AS `exchange_rates` ON `currencies`.`currency_code`=`exchange_rates`.`currency_code`
ORDER BY `currencies`.`country`
因此,将一组字段连接在一起,并在其上运行MAX()
,以获取组内的排序顺序,然后使用子字符串\u INDEX()
在父查询中解析这些字段。问题是,只有当我可以在连接字段上使用MIN()
或MAX()
时,此方法才有效。如果我想对一个字符串进行排序,或者按多个条件进行排序,但仅限于一条记录,那就不太理想了
此外,为了从关系数据库中获取所需的数据,不得不求助于可怕的字符串操作,这也给我带来了生理上的痛苦——必须有更好的方法
有人对更好的方法有什么建议吗?试试这个查询。它预计工作良好,但如果你提供一些数据,我将能够做得很好
SELECT `currencies`.`currency_code` as `CurrencyCode`,
`currencies`.`country`,
FROM_UNIXTIME( SUBSTRING_INDEX( SUBSTRING_INDEX(`exchange_rates`.`concat`, '-', 1), '-', -1)) AS `datestamp`,
SUBSTRING_INDEX( SUBSTRING_INDEX(`exchange_rates`.`concat`, '-', 2), '-', -1) AS `id`,
SUBSTRING_INDEX( SUBSTRING_INDEX(`exchange_rates`.`concat`, '-', 3), '-', -1) AS `rate`,
(SELECT
MAX(CONCAT_WS('-', `datestamp`, `id`, `rate`)) AS `concat`
FROM `exchange_rates`
WHERE `criteria_x`= NULL
AND `criteria_y` LIKE 'A'
GROUP BY `exchange_rates`.`currency_code`
HAVING `exchange_rates`.`currency_code` =`CurrencyCode`
) as `Concat`
FROM `currencies`
ORDER BY `currencies`.`country`
如果我正确理解了您的问题,您只需自行加入
汇率
即可选择利率:
SELECT currencies.currency_code,
currencies.country,
exchange_rates.id,
FROM_UNIXTIME(exchange_rates.datestamp),
exchange_rates.rate
FROM currencies
JOIN (
SELECT currency_code, MAX(datestamp) AS datestamp
FROM exchange_rates
WHERE criteria_x IS NULL AND criteria_y LIKE 'A'
GROUP BY currency_code
) AS exchange_wantd USING (currency_code)
JOIN exchange_rates USING (currency_code, datestamp)
ORDER BY currencies.country
在尝试提供答案之前,有几个一般性问题需要(简要)讨论 您的第一个查询是:
SELECT `currencies`.`currency_code`, `currencies`.`country`, `exchange_rates`.`id`,
FROM_UNIXTIME(`exchange_rates`.`datestamp`), `rate`
FROM `currencies`
INNER JOIN (
SELECT `id`, `currency_code`, `invoice_id`, `datestamp`, `rate`
FROM `exchange_rates`
WHERE `criteria_x`=NULL AND `criteria_y` LIKE 'A'
ORDER BY `datestamp` DESC
LIMIT 0, 1
) AS `exchange_rates` ON `currencies`.`currency_code`=`exchange_rates`.`currency_code`
ORDER BY `currencies`.`country`
标准\u x=NULL
符号;应该写为标准\u x为空
。MySQL可能会允许它;只要您知道它是非标准的,您就可以使用它不包含元字符(%
或
在标准SQL中),则该标准是不合理的。你最好用简单的等式:='A'
你的问题是: 我想从
exchange\u rates
表中检索每种货币的完整记录,但能够定义要选择的相关记录的特定条件。不仅是每种货币的最新汇率,还可能是具有条件\u x字段的每种货币的最新汇率为NULL
因此,您希望为满足所需其他条件的每种货币选择最新的汇率记录。我们可以假设在汇率表中,currency\u code
和datestamp
的组合存在唯一的约束;这意味着将始终最多有一个匹配行。您没有指定在没有匹配行的情况下应该显示什么;当然,内部联接不会列出该货币
对于SQL查询,我通常分步骤构建和测试整个查询,向先前开发的查询中添加额外的材料,这些查询可以正常工作并产生正确的输出。如果它很简单和/或我收集了太多的傲慢,我会先尝试一个复杂的查询,但当(复仇女神)它不起作用时,我会回到构建和测试过程。将其视为测试驱动(查询)开发
第1阶段:符合指定标准的汇率记录
阶段2:符合指定标准的每种货币的最近汇率时间
阶段3:符合指定条件的每种货币的最近汇率时间的汇率记录
阶段4:符合指定条件的每种货币的货币信息和最近汇率时间的汇率记录
这需要将货币表与上一个查询的输出连接起来:
SELECT c.currency_code, c.country, r.id,
FROM_UNIXTIME(r.datestamp), r.rate
FROM currencies AS c
JOIN (SELECT x.id, x.currency_code, x.invoice_id, x.datestamp, x.rate
FROM exchange_rates AS x
JOIN (SELECT currency_code, MAX(datestamp) AS datestamp
FROM exchange_rates
WHERE criteria_x IS NULL AND criteria_y = 'A'
GROUP BY currency_code
) AS m
ON x.currency_code = m.currency_code AND x.datestamp = m.datestamp
) AS r
ON c.currency_code = r.currency_code
ORDER BY c.country
除了Oracle只允许将“)r
”而不是“)作为r
”用于表别名和使用来自_UNIXTIME()的,我相信这应该可以正确地用于您提到的几乎所有SQL DBMS的当前版本
由于最终查询中未返回发票ID,因此我们可以从中间查询的选择列表中删除该ID。一个好的优化器可能会自动做到这一点
如果要查看货币信息,即使没有与条件匹配的汇率,也需要将最外层查询中的联接更改为左联接(也称为左外部联接)。如果只想查看货币的子集,则可以在最后(最外层)查询阶段应用该筛选器,或者(如果筛选器基于汇率表中的可用信息,例如货币代码)在最内层子查询(效率最高)或中间子查询应用该筛选器(除非优化器意识到它可以将过滤器向下推到最里面的子查询,否则效率不高)
正确性通常是首要标准;性能是次要标准。但是,问题中提到了性能。第一条规则是测量此处显示的“简单”查询。只有当这证明太慢时,您才需要进一步担心。当您确实需要担心时,您会检查查询计划,以查看是否存在,例如
SELECT currency_code, MAX(datestamp)
FROM exchange_rates
WHERE criteria_x IS NULL AND criteria_y = 'A'
GROUP BY currency_code
SELECT x.id, x.currency_code, x.invoice_id, x.datestamp, x.rate
FROM exchange_rates AS x
JOIN (SELECT currency_code, MAX(datestamp) AS datestamp
FROM exchange_rates
WHERE criteria_x IS NULL AND criteria_y = 'A'
GROUP BY currency_code
) AS m
ON x.currency_code = m.currency_code AND x.datestamp = m.datestamp
SELECT c.currency_code, c.country, r.id,
FROM_UNIXTIME(r.datestamp), r.rate
FROM currencies AS c
JOIN (SELECT x.id, x.currency_code, x.invoice_id, x.datestamp, x.rate
FROM exchange_rates AS x
JOIN (SELECT currency_code, MAX(datestamp) AS datestamp
FROM exchange_rates
WHERE criteria_x IS NULL AND criteria_y = 'A'
GROUP BY currency_code
) AS m
ON x.currency_code = m.currency_code AND x.datestamp = m.datestamp
) AS r
ON c.currency_code = r.currency_code
ORDER BY c.country
SELECT currency_code, MAX(datestamp) AS datestamp FROM exchange_rates GROUP BY currency_code
(SELECT currency_code, MAX(datestamp) AS datestamp FROM exchange_rates GROUP BY currency_code) AS dates_we_want
(SELECT currency_code, MAX(datestamp) AS datestamp FROM exchange_rates GROUP BY currency_code) AS dates_we_want, currencies AS c, exchange_rates AS er
er.*
SELECT er.*
FROM
(SELECT currency_code, MAX(datestamp) AS datestamp
FROM exchange_rates GROUP BY currency_code
) AS dates_we_want,
currencies AS c, exchange_rates AS er
WHERE
dates_we_want.currency_code=er.currency_core
AND
dates_we_want.currency_code=c.currency_core
AND
dates_we_want.datestamp=er.datestamp
AND
`criteria_x`=NULL AND `criteria_y` LIKE 'A'