Как сгруппировать две записи таблицы с добавленными сведениями о столбце

У меня есть таблица MySQL, которая выглядит так:

Таблица 1

User_ID  |  Serial |  Warranty 
1        |  12     | 2024-01-01
4        |  13423  | 2022-11-21
1        |  643r   | 2026-05-13
4        |  r42r4  | 2023-10-07
5        |  743f   | 2026-06-22
6        |  4324   | 2027-04-15

Таблица 2

ID |  Name  |  Side  |  Serial
1  | Bob    |  Left  |  12     
4  | Mark   |  Right |  13423  
1  | Bob    |  Right |  643r   
4  | Mark   |  Left  |  r42r4  
5  | Ella   |  Left  |  743f   
6  | Deb    |  Right |  4324 

Мне нужен запрос, который объединит все детали в один результат, например:

User_ID  |  Name  |  Left Warranty |  Right Warranty  |  Left Serial  | Right Serial
5        | Ella   | 2026-06-22     |  null            |    743f       | null
4        | Mark   | 2023-10-07     |  2022-11-21      |    r42r4      | 13423  
1        | Bob    | 2024-01-01     |  2026-05-13      |    12         | 643r
6        | Deb    | null           |  2027-04-15      |    null       |  4324   

Я знаю, как группировать, но я полностью зациклен на логике объединения этих таблиц в центральный результат запроса со всей объединенной информацией о записях на основе серийных номеров.

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

dougp 18.07.2024 19:44

Ты прав. Извините, я испортил пример table2. Я сейчас отредактирую. Спасибо, что обратили на это мое внимание.

chris.cavage 18.07.2024 20:58

Для объединения таблиц требуется JOIN. Размещение левых и правых в своих столбцах — это поворот. Если вы изучите оба из них, вы получите ответ.

Barmar 18.07.2024 21:50

Вы хоть что-нибудь пробовали???

Eric 18.07.2024 21:55
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
1
4
58
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Непонятно, что table1 принесет на вечеринку, как сказал Дуг.

Но для примера данных в таблице 2 подойдет простое условное агрегирование. Общий термин для этого — «поворот».

CREATE TABLE table_2 (
    ID INT,
    Name VARCHAR(50),
    Side VARCHAR(5),
    Warranty DATE,
    Serial VARCHAR(20)
);

INSERT INTO table_2 (ID, Name, Side, Warranty, Serial) VALUES
    (1, 'Bob', 'Left', '2024-01-01', '12'),
    (4, 'Mark', 'Right', '2022-11-21', '13423'),
    (1, 'Bob', 'Right', '2026-05-13', '643r'),
    (4, 'Mark', 'Left', '2023-10-07', 'r42r4'),
    (5, 'Ella', 'Left', '2026-06-22', '743f'),
    (6, 'Deb', 'Right', '2027-04-15', '4324');

select id,
       name,
       max(case when side = 'Left' then warranty else null end) as left_warranty,
       max(case when side = 'Right' then warranty else null end) as right_warranty,
       max(case when side = 'Left' then serial else null end) as left_serial,
       max(case when side = 'Right' then serial else null end) as right_serial
  from table_2
 group
    by id,
       name

Спасибо за ответ. Я отредактировал свое исходное сообщение, так как в таблице 2 по ошибке появился дополнительный столбец!

chris.cavage 18.07.2024 21:00
Ответ принят как подходящий

Объединение сделает свое дело. Измените соединение в соответствии с вашими потребностями. Скрипка

CREATE TABLE User_Warranty 
(
    User_ID INT NOT NULL
    , Serial VARCHAR(50) NOT NULL
    , Warranty DATE NOT NULL
    , PRIMARY KEY (User_ID, Serial)
);
CREATE TABLE User_Serial 
(
    ID INT NOT NULL
    , Name VARCHAR(50) NOT NULL
    , Side VARCHAR(10) NOT NULL
    , Serial VARCHAR(50) NOT NULL
    , PRIMARY KEY (ID, Serial)
);

INSERT INTO User_Warranty (User_ID, Serial, Warranty) VALUES (1, '12', '2024-01-01');
INSERT INTO User_Warranty (User_ID, Serial, Warranty) VALUES (4, '13423', '2022-11-21');
INSERT INTO User_Warranty (User_ID, Serial, Warranty) VALUES (1, '643r', '2026-05-13');
INSERT INTO User_Warranty (User_ID, Serial, Warranty) VALUES (4, 'r42r4', '2023-10-07');
INSERT INTO User_Warranty (User_ID, Serial, Warranty) VALUES (5, '743f', '2026-06-22');
INSERT INTO User_Warranty (User_ID, Serial, Warranty) VALUES (6, '4324', '2027-04-15');

INSERT INTO User_Serial (ID, Name, Side, Serial) VALUES (1, 'Bob', 'Left', '12');
INSERT INTO User_Serial (ID, Name, Side, Serial) VALUES (4, 'Mark', 'Right', '13423');
INSERT INTO User_Serial (ID, Name, Side, Serial) VALUES (1, 'Bob', 'Right', '643r');
INSERT INTO User_Serial (ID, Name, Side, Serial) VALUES (4, 'Mark', 'Left', 'r42r4');
INSERT INTO User_Serial (ID, Name, Side, Serial) VALUES (5, 'Ella', 'Left', '743f');
INSERT INTO User_Serial (ID, Name, Side, Serial) VALUES (6, 'Deb', 'Right', '4324');

SELECT 
    us.ID AS User_ID
    , us.Name
    , MAX(CASE WHEN us.Side = 'Left' THEN uw.Warranty END) `Left Warranty`
    , MAX(CASE WHEN us.Side = 'Right' THEN uw.Warranty END) `Right Warranty`
    , MAX(CASE WHEN us.Side = 'Left' THEN us.Serial END) `Left Serial`
    , MAX(CASE WHEN us.Side = 'Right' THEN us.Serial END) `Right Serial`
FROM User_Serial us
JOIN User_Warranty uw ON us.ID = uw.User_ID AND us.Serial = uw.Serial
GROUP BY us.ID, us.Name;

Вам понадобится OUTER JOIN и определить объединение двух столбцов (User_ID и Serial), использовать оператор CASE, чтобы вручную свести данные, а затем каким-то образом агрегировать (я использую MAX() ниже), чтобы консолидировать результаты и исключить повторяющиеся строки, содержащие NULL.

WITH
table1 (
    User_ID
  , Serial
  , Warranty 
) as (
        select 1, '12'   , DATE '2024-01-01'
  union select 4, '13423', DATE '2022-11-21'
  union select 1, '643r' , DATE '2026-05-13'
  union select 4, 'r42r4', DATE '2023-10-07'
  union select 5, '743f' , DATE '2026-06-22'
  union select 6, '4324' , DATE '2027-04-15'
), 
table2 (
    ID
  , Name
  , Side
  , Serial
) as (
        select 1, 'Bob' , 'Left' , '12'
  union select 4, 'Mark', 'Right', '13423'
  union select 1, 'Bob' , 'Right', '643r'
  union select 4, 'Mark', 'Left' , 'r42r4'
  union select 5, 'Ella', 'Left' , '743f'
  union select 6, 'Deb' , 'Right', '4324'
)

select
  table2.ID as User_ID
, table2.Name
, max(case when table2.Side = 'Left'  then table1.Warranty end) as "Left Warranty"
, max(case when table2.Side = 'Right' then table1.Warranty end) as "Right Warranty"
, max(case when table2.Side = 'Left'  then table1.Serial   end) as "Left Serial"
, max(case when table2.Side = 'Right' then table1.Serial   end) as "Right Serial"

from table2
  left outer join table1 on table1.User_ID = table2.ID
                        and table1.Serial = table2.Serial

group by 
  table2.ID
, table2.Name

order by 1

Чтобы достичь желаемого результата, вы можете использовать комбинацию операторов LEFT JOIN и CASE для сведения данных на основе столбца Side.

SELECT
t1.User_ID,
  t2.Name,
  MAX(CASE WHEN t2.Side = 'Left'
    THEN t1.Warranty END) AS `Left Warranty`,
  MAX(CASE WHEN t2.Side = 'Right'
    THEN t1.Warranty END) AS `Right Warranty`,
  MAX(CASE WHEN t2.Side = 'Left'
    THEN t2.Serial END) AS `Left Serial`,
  MAX(CASE WHEN t2.Side = 'Right'
    THEN t2.Serial END) AS `Right Serial`
FROM
table1 t1
JOIN
table2 t2 ON t1.Serial = t2.Serial
GROUP BY
t1.User_ID, t2.Name
ORDER BY
t1.User_ID;

Другие вопросы по теме