MySQL:以1对1的方式加入

时间:2017-12-21 20:01:36

标签: mysql sql join relationship relationships

我认为,这个问题属于更高级的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)。尽管如此,我需要以1对1的方式加入这些值。换句话说,有" 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;

要点:

  • 在1对1的基础上查找两个表之间的匹配记录(可能是JOIN)
  • 对于TABLE_FRUIT中的每条记录,只需查找TABLE_ORIGIN
  • 中的一条(下一条)匹配记录
  • 如果TABLE_ORIGIN中的记录已与TABLE_FRUIT的记录匹配一次,则可能无法在同一查询运行中再次考虑该记录。

2 个答案:

答案 0 :(得分:2)

这是我对RANK功能的想法。评论之后,我意识到mysql没有内置RANK而不是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;

说明:为每个水果排序表中的每个项目。因此,第一个表中的Orange将排名第1和第2,Apple也是如此。在第二个表中,Orange将具有等级1,2和3,但是其他人将仅具有等级1.然后当基于名称加入表时,您还可以基于等级加入,这样,您将获得橙色等级1和2匹配,但橘子与等级3不匹配。

这是基于我对问题的理解。如果要求与我在此处提供的内容不同,请告诉我。

答案 1 :(得分:1)

条目数量与条目顺序之间存在任意关系,因此请使用技术来匹配项目数量和这些项目的顺序。在MariaDB v10中,支持"窗口功能" dense_rank()row_number()这相对容易:

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代替那些窗口函数。