MySQL:一对一加入
MySQL: JOINs on 1-to-1 basis
我认为,这个问题属于更高级的 SQL 类别(在本例中为 MySQL):我有两个表(TABLE_FRUIT
、TABLE_ORIGIN
- 只是示例名称),其中包含可以连接的列(fruit_name
)。
考虑下图:
TABLE_FRUIT
fruit_id|fruit_name |variety
--------|----------------------
1|Orange |sweet
2|Orange |large
3|Lemon |wild
4|Apple |red
5|Apple |yellow
6|Pear |early
etc...
TABLE_ORIGIN
fuit_id |fruit_name|Origin
---------|----------|--------
1|Apple | Italy
2|Pear | Portugal
3|Grape | Italy
4|Orange | Spain
5|Orange | Portugal
6|Orange | Italy
etc...
Desired Result:
TABLE_FRUIT_ORIGIN
fuit_id |fruit_name|Origin
---------|----------|--------
1|Orange | Spain
2|Orange | Portugal
3|Apple | Italy
4|Pear | Portugal
这些表在构成连接的列中有多个相同的值 (fruit_name
)。尽管如此,我还是需要在一对一的基础上加入这些价值观。也就是说,"Orange"值在TABLE_FRUIT
中有2次,在TABLE_ORIGIN
中有3次。我正在寻找两场比赛的结果,一场是西班牙,一场是葡萄牙。必须忽略来自 TABLE_ORIGIN
的意大利值,因为 TABLE_FRUIT
中没有可用的第三个橙色值来匹配 TABLE_ORIGIN
中的橙色值。
我尽我所能,但在 Google 上找不到任何相关内容。例如,我尝试添加一列 record_used
并尝试 UPDATE
但没有成功。
TABLE_ORIGIN
fuit_id |fruit_name|origin |record_used
---------|----------|-----------|-----------
1|Apple | Italy |
2|Pear | Portugal |
3|Grape | Italy |
4|Orange | Spain |
5|Orange | Portugal |
6|Orange | Italy |
etc...
UPDATE
TABLE_FRUIT t1
INNER JOIN
TABLE_ORIGIN t2
ON
(t1.fruit_name = t2.fruit_name)
AND
(t2.record_used IS NULL)
SET
t2.record_used = 1;
总结:
- 以一对一的方式(可能是JOIN)查找两个表之间的匹配记录
- 对于
TABLE_FRUIT
中的每条记录,仅在 TABLE_ORIGIN
中找到一条(下一条)匹配记录
- 如果
TABLE_ORIGIN
中的记录已经与 TABLE_FRUIT
中的记录匹配一次,则可能不会在同一查询中再次考虑 运行。
条目数和条目顺序之间存在任意关系,因此请使用技巧来匹配条目数和条目顺序。在支持 "window functions" dense_rank()
和 row_number()
的 MariaDB v10 中,这相对容易:
select
row_number() over(order by fn.fruit_id) as fruit_id
, fn.fruit_name, o.Origin, fn.variety
from (
select fruit_name, variety, fruit_id
, dense_rank() over(partition by fruit_name order by fruit_id) rnk
from table_fruit
) fn
inner join (
select fruit_name, Origin
, dense_rank() over(partition by fruit_name order by fruit_id) rnk
from table_origin
) o on fn.fruit_name = o.fruit_name and fn.rnk = o.rnk
fruit_id | fruit_name | Origin | variety
-------: | :--------- | :------- | :------
1 | Orange | Spain | sweet
2 | Orange | Portugal | large
3 | Apple | Italy | red
4 | Pear | Portugal | early
dbfiddle here
纯 MySQL 解决方案有点复杂,因为它需要使用 @variables 来替代那些 window 函数。
这是我对 RANK 函数的想法。发表评论后,我意识到 mysql 没有内置的 RANK over GROUP BY 函数,因此必须找到解决方法。
SELECT *
FROM (SELECT fruit_name,
@f_rank := IF(@f_name = fruit_name, @f_rank + 1, 1) AS rank,
@f_name := fruit_name
FROM table_fruit
ORDER BY fruit_name DESC) f
INNER JOIN (SELECT fruit_name,
@f_rank := IF(@f_name = fruit_name, @f_rank + 1, 1) AS
rank,
@f_name := fruit_name
FROM table_origin
ORDER BY fruit_name DESC) o
ON f.fruit_name = o.fruit_name
AND f.rank = o.rank;
说明:对每个水果在 table 中对每个项目进行排名。因此,第一个 table 中的 Orange 将排名 1 和 2,Apple 也是如此。在第二个table中,Orange会有1、2、3的rank,其他的只有1。然后在按名字加入table的时候,也可以按rank加入,这样,您将获得橙色排名 1 和 2 匹配,但排名 3 的橙色将不匹配。
这是基于我对问题的理解。让我知道要求是否与我在这里给出的有所不同。
我认为,这个问题属于更高级的 SQL 类别(在本例中为 MySQL):我有两个表(TABLE_FRUIT
、TABLE_ORIGIN
- 只是示例名称),其中包含可以连接的列(fruit_name
)。
考虑下图:
TABLE_FRUIT
fruit_id|fruit_name |variety
--------|----------------------
1|Orange |sweet
2|Orange |large
3|Lemon |wild
4|Apple |red
5|Apple |yellow
6|Pear |early
etc...
TABLE_ORIGIN
fuit_id |fruit_name|Origin
---------|----------|--------
1|Apple | Italy
2|Pear | Portugal
3|Grape | Italy
4|Orange | Spain
5|Orange | Portugal
6|Orange | Italy
etc...
Desired Result:
TABLE_FRUIT_ORIGIN
fuit_id |fruit_name|Origin
---------|----------|--------
1|Orange | Spain
2|Orange | Portugal
3|Apple | Italy
4|Pear | Portugal
这些表在构成连接的列中有多个相同的值 (fruit_name
)。尽管如此,我还是需要在一对一的基础上加入这些价值观。也就是说,"Orange"值在TABLE_FRUIT
中有2次,在TABLE_ORIGIN
中有3次。我正在寻找两场比赛的结果,一场是西班牙,一场是葡萄牙。必须忽略来自 TABLE_ORIGIN
的意大利值,因为 TABLE_FRUIT
中没有可用的第三个橙色值来匹配 TABLE_ORIGIN
中的橙色值。
我尽我所能,但在 Google 上找不到任何相关内容。例如,我尝试添加一列 record_used
并尝试 UPDATE
但没有成功。
TABLE_ORIGIN
fuit_id |fruit_name|origin |record_used
---------|----------|-----------|-----------
1|Apple | Italy |
2|Pear | Portugal |
3|Grape | Italy |
4|Orange | Spain |
5|Orange | Portugal |
6|Orange | Italy |
etc...
UPDATE
TABLE_FRUIT t1
INNER JOIN
TABLE_ORIGIN t2
ON
(t1.fruit_name = t2.fruit_name)
AND
(t2.record_used IS NULL)
SET
t2.record_used = 1;
总结:
- 以一对一的方式(可能是JOIN)查找两个表之间的匹配记录
- 对于
TABLE_FRUIT
中的每条记录,仅在TABLE_ORIGIN
中找到一条(下一条)匹配记录
- 如果
TABLE_ORIGIN
中的记录已经与TABLE_FRUIT
中的记录匹配一次,则可能不会在同一查询中再次考虑 运行。
条目数和条目顺序之间存在任意关系,因此请使用技巧来匹配条目数和条目顺序。在支持 "window functions" dense_rank()
和 row_number()
的 MariaDB v10 中,这相对容易:
select row_number() over(order by fn.fruit_id) as fruit_id , fn.fruit_name, o.Origin, fn.variety from ( select fruit_name, variety, fruit_id , dense_rank() over(partition by fruit_name order by fruit_id) rnk from table_fruit ) fn inner join ( select fruit_name, Origin , dense_rank() over(partition by fruit_name order by fruit_id) rnk from table_origin ) o on fn.fruit_name = o.fruit_name and fn.rnk = o.rnk
fruit_id | fruit_name | Origin | variety -------: | :--------- | :------- | :------ 1 | Orange | Spain | sweet 2 | Orange | Portugal | large 3 | Apple | Italy | red 4 | Pear | Portugal | early
dbfiddle here
纯 MySQL 解决方案有点复杂,因为它需要使用 @variables 来替代那些 window 函数。
这是我对 RANK 函数的想法。发表评论后,我意识到 mysql 没有内置的 RANK over GROUP BY 函数,因此必须找到解决方法。
SELECT *
FROM (SELECT fruit_name,
@f_rank := IF(@f_name = fruit_name, @f_rank + 1, 1) AS rank,
@f_name := fruit_name
FROM table_fruit
ORDER BY fruit_name DESC) f
INNER JOIN (SELECT fruit_name,
@f_rank := IF(@f_name = fruit_name, @f_rank + 1, 1) AS
rank,
@f_name := fruit_name
FROM table_origin
ORDER BY fruit_name DESC) o
ON f.fruit_name = o.fruit_name
AND f.rank = o.rank;
说明:对每个水果在 table 中对每个项目进行排名。因此,第一个 table 中的 Orange 将排名 1 和 2,Apple 也是如此。在第二个table中,Orange会有1、2、3的rank,其他的只有1。然后在按名字加入table的时候,也可以按rank加入,这样,您将获得橙色排名 1 和 2 匹配,但排名 3 的橙色将不匹配。
这是基于我对问题的理解。让我知道要求是否与我在这里给出的有所不同。