SQL: каскадные условия при соединении - PullRequest
0 голосов
/ 07 июня 2018

Я нашел несколько похожих вопросов на этот вопрос в SO, но ничего, что относится к моей ситуации.

У меня большой набор данных с сотнями миллионов строк в таблице 1, и я ищу наиболее эффективный способвыполнить следующий запрос. Я использую Google BigQuery, но я думаю, что это общий вопрос SQL, применимый к любой СУБД?

Мне нужно назначить владельца для каждой строки в таблице 1. Я хочу присоединиться кследующий приоритет:

1: если item_id совпадает с идентификатором в Таблице 2

2: если ни один item_id не совпадает, попробуйте сопоставить по item_name

3: если ни один item_id или item_name не совпадают, попробуйтесовпадение по item_division

4: если нет совпадений по item_division, вернуть null

Таблица 1 - Точки данных:

| id | item_id | item_name | item_division | units | revenue
|----|---------|-----------|---------------|-------|---------
| 1  |   xyz   |  pen      |      UK       |   10  |   100
| 2  |   pqr   |  cat      |      US       |   15  |   120
| 3  |   asd   |  dog      |      US       |   12  |   105
| 4  |   xcv   |  hat      |      UK       |   11  |   140
| 5  |   bnm   |  cow      |      UK       |   14  |   150

Таблица 2 -Идентификаторы:

| id |  type   |  code     | owner | 
|----|---------|-----------|-------|
| 1  |   id    |  xyz      |  bob  |  
| 2  |   name  |  cat      |  dave |    
| 3  | division|  UK       | alice |    
| 4  |   name  |  pen      | erica |      
| 5  |   id    |  xcv      | fred  |  

Желаемый результат:

| id | item_id | item_name | item_division | units | revenue | owner |
|----|---------|-----------|---------------|-------|---------|-------|
| 1  |   xyz   |  pen      |      UK       |   10  |   100   |  bob  | <- id
| 2  |   pqr   |  cat      |      US       |   15  |   120   |  dave | <- code
| 3  |   asd   |  dog      |      US       |   12  |   105   |  null | <- none
| 4  |   xcv   |  hat      |      UK       |   11  |   140   |  fred | <- id
| 5  |   bnm   |  cow      |      UK       |   14  |   150   | alice | <- division

Мои попытки до сих пор включали множественное соединение таблицы на себя, и я боюсь, что она становитсякрайне неэффективно.

Любая помощь очень ценится.

Ответы [ 3 ]

0 голосов
/ 07 июня 2018

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

#standardSQL
SELECT COALESCE(
  null
  , (SELECT MIN(payload) 
     FROM `githubarchive.year.2016` 
     WHERE actor.login=a.user)
  , (SELECT MIN(payload) 
     FROM `githubarchive.year.2016` 
     WHERE actor.id = SAFE_CAST(user AS INT64))
)
FROM (SELECT '15229281' user) a


4.2s elapsed, 683 GB processed
{"action":"started"}    

Например,выполнение следующего запроса заняло много времени, но BigQuery мог бы в будущем значительно оптимизировать его выполнение (в зависимости от того, как часто пользователям нужна была операция, подобная этой):

#standardSQL
SELECT COALESCE(
  "hello"
  , (SELECT MIN(payload) 
     FROM `githubarchive.year.2016` 
     WHERE actor.login=a.user)
  , (SELECT MIN(payload) 
     FROM `githubarchive.year.2016` 
     WHERE actor.id = SAFE_CAST(user AS INT64))
)
FROM (SELECT actor.login user FROM `githubarchive.year.2016` LIMIT 10) a


114.7s elapsed, 683 GB processed
hello
hello
hello
hello
hello
hello
hello
hello
hello
hello
0 голосов
/ 09 июня 2018

Еще одна опция для BigQuery Standard SQL

#standardSQL
SELECT ARRAY_AGG(a)[OFFSET(0)].*, 
  ARRAY_AGG(owner 
    ORDER BY CASE 
      WHEN type = 'id' THEN 1
      WHEN type = 'name' THEN 2
      WHEN type = 'division' THEN 3
    END  
    LIMIT 1
  )[OFFSET(0)] owner
FROM Datapoints a
JOIN Identifiers b
  ON (a.item_id = b.code AND b.type = 'id')
   OR (a.item_name = b.code AND b.type = 'name')
   OR (a.item_division = b.code AND b.type = 'division')
GROUP BY a.id
ORDER BY a.id  

Он пропускает записи, у которых k = нет владельцев - как в приведенном ниже результате (id = 3 отсутствует, поскольку у него нет владельца)

Row id  item_id item_name   item_division   units   revenue owner    
1   1   xyz     pen         UK              10      100     bob  
2   2   pqr     cat         US              15      120     dave     
3   4   xcv     hat         UK              11      140     fred     
4   5   bnm     cow         UK              14      150     alice    
0 голосов
/ 07 июня 2018

Я использую следующий запрос (спасибо @Barmar), но хочу знать, есть ли более эффективный способ в Google BigQuery:

SELECT a.*, COALESCE(b.owner,c.owner,d.owner) owner FROM datapoints a
LEFT JOIN identifiers b on a.item_id = b.code and b.type = 'id'
LEFT JOIN identifiers c on a.item_name = c.code and c.type = 'name'
LEFT JOIN identifiers d on a.item_division = d.code and d.type = 'division'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...