Соединение SQL для столбца с подстановочными знаками / объединение для столбцов col1 и col2, если объединение col1 в таблице еще выполняется для столбцов col2 - PullRequest
2 голосов
/ 19 марта 2019

Представьте, что я компания, которая продает гороскопы, основываясь на именах клиентов. У меня есть таблица с фамилией, фамилией и текстом гороскопа. Поскольку я не могу охватить каждую отдельную комбинацию имен, я часто сохраняю фамилию как NULL в качестве универсального значения.

Horoscope DB

sur | fam | horoscope
----------------------
John| Doe  | text1
Jane| Doe  | text2
NULL| Doe  | text3
Ike | Smith| text4
NULL| Smith| text5

И список клиентов

customer DB

sur | fam
---------
John| Doe
Jack| Doe
Lisa| Smith
Carl| Smith

Теперь нам нужно сопоставить гороскоп каждому клиенту. Если у нас есть полное совпадение по фамилии и фамилии, мы сопоставляем по обоим, но если у нас нет полного совпадения, мы сопоставляем просто по фамилии, поэтому результат будет:

Customer horoscope DB

sur | fam | horoscope
----------------------
John| Doe  | text1
Jack| Doe  | text3
Lisa| Smith| text5
Carl| Smith| text5

Если я сделаю обычный LEFT JOIN USING(sur, fam), я получу совпадение только с Джоном Если я использую LEFT JOIN USING(fam), я получу много дубликатов. Мне нужно настроить некоторые условия, но я не уверен, как.

Я готов изменить свое универсальное значение, если необходимо, или закодировать его в отдельный столбец.

В частности, я работаю с Google Big Query. Я установил DB-скрипку, которую вы можете использовать

Ответы [ 5 ]

1 голос
/ 19 марта 2019

Ниже для BigQuery Standard SQL

#standardSQL
SELECT c.sur, c.fam,
  ARRAY_AGG(horoscope ORDER BY h.sur DESC LIMIT 1)[OFFSET(0)] horoscope
FROM `project.dataset.customer` c
JOIN `project.dataset.horoscope` h
ON c.fam = h.fam
AND c.sur = IFNULL(h.sur, c.sur)
GROUP BY c.sur, c.fam

Вы можете проверить, поиграть с выше, используя пример данных из вашего примера, как в примере ниже

#standardSQL
WITH `project.dataset.horoscope` AS (
  SELECT 'John' sur,'Doe' fam, 'text1' horoscope UNION ALL
  SELECT 'Jane', 'Doe', 'text2' UNION ALL
  SELECT NULL, 'Doe', 'text3' UNION ALL
  SELECT 'Ike', 'Smith', 'text4' UNION ALL
  SELECT NULL, 'Smith', 'text5' 
), `project.dataset.customer` AS (
  SELECT 'John' sur, 'Doe' fam UNION ALL
  SELECT 'Jack', 'Doe' UNION ALL
  SELECT 'Lisa', 'Smith' UNION ALL
  SELECT 'Carl', 'Smith' 
)
SELECT c.sur, c.fam,
  ARRAY_AGG(horoscope ORDER BY h.sur DESC LIMIT 1)[OFFSET(0)] horoscope
FROM `project.dataset.customer` c
JOIN `project.dataset.horoscope` h
ON c.fam = h.fam
AND c.sur = IFNULL(h.sur, c.sur)
GROUP BY c.sur, c.fam  

с результатом

Row sur     fam     horoscope    
1   John    Doe     text1    
2   Jack    Doe     text3    
3   Lisa    Smith   text5    
4   Carl    Smith   text5    
1 голос
/ 19 марта 2019

Вы можете присоединиться к нескольким условиям для каждого случая:

select c.sur, c.fam, h.horoscope from customer c 
inner join horoscope h
on (c.fam = h.fam and c.sur = h.sur) or 
  (c.fam = h.fam and h.sur is null and not exists(
    select 1 from horoscope 
    where fam = c.fam and sur = c.sur
  )
)

См. Демоверсию

1 голос
/ 19 марта 2019

Другим решением было бы использование условной агрегации. Вы можете присоединиться к фамилии, а затем проверить, существует ли гороскоп для данной фамилии; если нет, то откат на фамилию NULL.

SELECT
    c.sur,
    c.fam,
    COALESCE(
        MAX(CASE WHEN c.sur = h.sur THEN h.text END),
        MAX(CASE WHEN h.sur IS NULL THEN h.text END) 
    ) horoscope_text
FROM
    customer c
    INNER JOIN horoscope h ON c.fam = h.fam
GROUP BY 
    c.sur,
    c.fam
1 голос
/ 19 марта 2019

Исходя из того, что я понял, вот один из способов сделать это

select c.id customer_id, c.sur, c.fam, h.id horoscope_id, h.sur h_sur, 
h.fam h_fam, h.horoscope
FROM customer c join horoscope h
on (c.sur = h.sur and c.fam = h.fam)
or (h.sur is null and c.fam = h.fam and not exists 
      (select 1 from horoscope h1 where h1.sur = c.sur and h1.fam = c.fam)
   )


и результат

enter image description here

1 голос
/ 19 марта 2019

Вот один из методов:

select . . .
from (select c.*,
             h.* except (sur, fam), -- whatever columns you want
             row_number() over (partition by c.fam
                                order by (case when c.sur = h.sur then 1 else 2 end)
                               ) as seqnum
      from horoscope h join
           customer c
           on c.fam = h.fam
     ) ch
where seqnum = 1;

По сути, это объединяет семью и выбирает «лучшее совпадение», которое является точным совпадением по фамилии.

Вам следуетбудьте осторожны, потому что разные семьи могут иметь одну и ту же фамилию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...