MySQL: СОЕДИНЕНИЯ на основе 1 к 1

0

Я думаю, эта проблема имеет более продвинутую категорию 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). Несмотря на это, мне нужно присоединиться к значениям 1-к-1. Другими словами, значение "Оранжевое" 2 раза в TABLE_FRUIT и 3 раза в TABLE_ORIGIN. Я ищу результат двух матчей, один для Испании, один для Португалии. Значение Italy из TABLE_ORIGIN должно быть проигнорировано, потому что нет третьего значения Orange в 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, она не может считаться снова в том же запуске запроса.
Теги:
join
relationships
relationship

2 ответа

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;

Объяснение: ранжируйте каждый элемент в таблице для каждого фрукта. Итак, оранжевый в первой таблице будет иметь ранг 1 и 2, а также Apple. Во второй таблице Orange будет иметь ранг 1, 2 и 3, но другие будут иметь только ранг 1. Затем, присоединяясь к таблицам, основанным на именах, вы также можете присоединиться к рангам таким образом, вы получите оранжевый ранг 1 и 2, но оранжевый с рангом 3 не будет соответствовать.

Это основано на моем понимании проблемы. Дайте мне знать, если это требование отличается от того, что я здесь дал.

  • 1
    К сведению: MySQL V8 (после выпуска) должен иметь эти функции.
  • 0
    @Used_By_Already Полезно знать. Меня всегда беспокоило, почему у него нет таких функций.
Показать ещё 2 комментария
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 здесь

Чистое решение MySQL немного сложнее, потому что оно требует использования @variables, который заменит эти функции окна.

  • 0
    Спасибо за ваш комментарий. Отличная информация. Во-первых, «Произвольные отношения» звучат точно так же, как и мой вопрос. Я буду изучать эту тему. И да, ваш результат - это то, чего я хочу достичь. Поскольку я использую MySQL, я должен применить ваш пример из MariaDB к MySQL. Тем не менее, clinomaniac, предоставил мне отличный ответ чуть ниже, который использует MySQL. Спасибо, что нашли время для меня.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню