MySQL:一对一加入

MySQL: JOINs on 1-to-1 basis

我认为,这个问题属于更高级的 SQL 类别(在本例中为 MySQL):我有两个表(TABLE_FRUITTABLE_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;

总结:

条目数和条目顺序之间存在任意关系,因此请使用技巧来匹配条目数和条目顺序。在支持 "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 的橙色将不匹配。

这是基于我对问题的理解。让我知道要求是否与我在这里给出的有所不同。