MySQL - Попытка получить несколько строк, совпадающих с дублирующимися внешними ключами, в качестве дополнительных столбцов - PullRequest
0 голосов
/ 13 ноября 2018

У меня есть база данных со следующими двумя таблицами:

+------------+-------+---------+
| customer_id| name  | surname |  
+------------+-------+---------+  
| 123        | Bob   | Johnson |  
| 124        | Alice | Smith   |  
| 125        | Fred  | Rogers  |  
+------------+-------+---------+

+------------+-------------+--------------+------------+  
| address_id | customer_id | address_1    | address_2  |  
+------------+-------------+--------------+------------+  
| 1          |     123     | 123 A Street | Oneville   |  
| 2          |     124     | 321 B Street | Twoville   |  
| 3          |     124     | 42  C Street | Threeville |  
| 4          |     125     | 23  D Street | Fourville  |  
+------------+-------------+--------------+------------+  

Я пытаюсь использовать запрос, чтобы получить дополнительные строки с тем же идентификатором клиента из таблицы адресов в формате, подобном этому, с дополнительными адресами, добавленными в строку:

+-------------+---------------+--------------+------------+--------------+------------+  
| customer_id | customer_name | address_1    | address_2  |  address_3   | address_4  |
+-------------+---------------+--------------+------------+--------------+------------+  
| 123         |     Bob       | 123 A Street | Oneville   |              |            |
| 124         |     Alice     | 321 B Street | Twoville   | 42  C Street | Threeville |
| 125         |     Fred      | 23  D Street | Fourville  |              |            |
+-------------+---------------+--------------+------------+--------------+------------+ 

В настоящее время мой (упрощенный) запрос выглядит так:

SELECT
    c.customer_id,
    c.name AS 'customer_name',
    a.address_1,
    a.address_2,
FROM
    customer c
LEFT JOIN 
    address a ON c.customer_id = a.customer_id
GROUP BY a.customer_id

Исходя из того, что я уже нашел здесь, я попытался добавить подзапрос, чтобы сделать это, но я не думаю, что понимаю их достаточно хорошо, чтобы заставить его работать как задумано.

Кроме того, я хотел бы поблагодарить участников этого сайта за то, что они нашли меня, несмотря на чрезвычайно запутанную базу данных продуктов, которую я экспортировал до этого. Разве миграция веб-сайтов не интересна?

1 Ответ

0 голосов
/ 14 ноября 2018

В идеале такие требования, связанные с отображением данных, обычно должны решаться с использованием кода приложения (например, PHP, C ++, Java и т. Д.). Однако, основываясь на ваших комментариях , вам нужно делать это только с SQL. Более того, вы подтверждаете, что вас интересует не более двух адресов клиента.

В версии MySQL <8.0.2 мы можем <a href="http://www.mysqltutorial.org/mysql-row_number/" rel="nofollow noreferrer"> эмулировать Row_Number(), используя определяемые пользователем переменные . В производной таблице мы получим все адреса клиента. В этом подзапросе важно получить данные в определенном порядке, чтобы внешний подзапрос мог использовать их для правильного вычисления значений номеров строк в разделе customer_id.

Во внешнем подзапросе мы назначим номер строки условно, используя выражения CASE..WHEN. Во внешнем подзапросе мы будем выполнять условное агрегирование по группе customer_id. address_1 и address_2 будут определены, когда номер строки равен 1; и address_3 и address_4 будут определены, когда номер строки 2

SELECT 
  dt2.customer_id, 
  dt2.customer_name, 
  MAX(CASE WHEN dt2.row_no = 1 THEN dt2.address_1 END) AS address_1,
  MAX(CASE WHEN dt2.row_no = 1 THEN dt2.address_2 END) AS address_2,
  MAX(CASE WHEN dt2.row_no = 2 THEN dt2.address_1 END) AS address_3,
  MAX(CASE WHEN dt2.row_no = 2 THEN dt2.address_2 END) AS address_4
FROM 
(
  SELECT 
    @rn := CASE WHEN @cid = dt.customer_id THEN @rn + 1
                ELSE 1
           END AS row_no, 
    @cid := dt.customer_id AS customer_id, 
    dt.customer_name, 
    dt.address_1, 
    dt.address_2
  FROM 
  (
    SELECT
      c.customer_id,
      c.name AS 'customer_name',
      a.address_1,
      a.address_2 
    FROM
      customer c
    LEFT JOIN 
      address a ON c.customer_id = a.customer_id
    ORDER BY c.customer_id, a.address_id  -- this ordering is important
  ) AS dt
  CROSS JOIN (SELECT @cid := 0, @rn := 0) AS user_init_vars -- initialize variables
) AS dt2
GROUP BY dt2.customer_id, dt2.customer_name 
ORDER BY dt2.customer_id 
...