Как расставить приоритеты в порядке OR и учесть значения NULL в операторе JOIN ON для нескольких таблиц в Teradata SQL? - PullRequest
0 голосов
/ 10 октября 2019

Я пытаюсь объединить TABLEONE (a) и TABLETWO (b) в трех ключевых столбцах, чтобы затем вернуть описание DESC для примерно 1 миллиарда строк данных.

Хотя один из этих столбцов является простымобъединение (a.TS = b.UCDE), два других имеют различные правила, которые должны выполняться в определенном порядке, чтобы они могли соответствовать должным образом.

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

Правила:

  1. a.TS = b.UCDE (всегда)
  2. Если a.ICI IS NOT NULL, то проверьте, соответствует ли оно b.STMдано 1.

a. Если найдено совпадение, перейдите к 3.

b. Если он не находит соответствия (то есть b.STM IS NULL), тогда верните DESC для этой строки.

c. Если a.ICI IS NULL, тогда присоединитесь к строке, где b.STM IS NULL дано 1.

a.S_ID может быть либо 0000000000, NULL, либо значением, например 0000000300, тогда как b.SRL будет либо NULL, либо значением, например 000300 (Примечание: a.S_ID имеет 10 символови b.SRL имеет только 6 символов, поэтому объединение справа состоит из 6 символов a.S_ID)

a. Приоритет должен быть на RIGHT(a.S_ID,6) = b.SRL, если есть совпадение

b. Если a.S_ID = 0000000000 или IS NULL, это может присоединиться к b.SRL IS NULL, хотя объединение фактически избыточно, так как в этом случае должно быть достаточно 1. и 2.

SELECT a.TDATE, a.AMT, a.ISI, a.TS, b.UCDE, a.ICI, b.STM, a.S_ID,
CASE WHEN b.SRL1 IS NULL THEN '0000000000' ELSE b.SRL1 END AS SRL, a.RES,
-- Manually override certain conditions
CASE WHEN (a.ISI = 'AP' AND a.TS = '1234') THEN 'APP'
     WHEN (a.ISI = 'JK' AND a.TS = '1234') THEN 'JAX'
     ELSE b.DESC END AS DESC
FROM TABLEONE as a
FULL JOIN TABLETWO AS b
    ON  ( a.TS = b.UCDE
        AND (a.ICI = b.STM OR (a.ICI IS NULL and b.STM IS NULL) OR b.STM IS NULL)
        AND (RIGHT(a.S_ID,6) = RIGHT(SRL,6) OR a.S_ID IS NULL)
        )
ORDER BY (CASE WHEN STM IS NULL THEN 2 ELSE 1 END)

Мой текущий код работает непоследовательнои в некоторых случаях я получаю дубликаты из OR b.STM IS NULL или OR a.S_ID IS NULL. В других случаях кажется, что он работает нормально.

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


ИЗМЕНИТЬ, чтобы добавить пример (EXPECTED DESC - мой ожидаемый результат):

TABLE A:
+----+------------+-----+-----+------+--------+------------+-----+---------------+
| #  |   TDATE    | AMT | ISI |  TS  |  ICI   |    S_ID    | RES | EXPECTED DESC |
+----+------------+-----+-----+------+--------+------------+-----+---------------+
|  1 | 2019-09-01 |  94 | DC  | 1001 | 1A     | 0000000300 | PX  | A             |
|  2 | 2019-09-01 |  35 | DC  | 1001 | 2B     | 0000000300 | DL  | B             |
|  3 | 2019-09-01 |  40 | DC  | 1001 | 2B     | 0000000600 | JI  | C             |
|  4 | 2019-09-01 |  65 | DC  | 1001 | 2B     | <NULL>     | WO  | D             |
|  5 | 2019-09-02 |  95 | AC  | 1001 | 2B     | 0000000000 | FK  | D             |
|  6 | 2019-09-03 |  10 | AC  | 1001 | 3C     | <NULL>     | SL  | E             |
|  7 | 2019-09-04 |   8 | AC  | 1001 | 3C     | 0000000000 | FH  | E             |
|  8 | 2019-09-05 |  40 | DC  | 1001 | 3C     | 0000000600 | WO  | E             |
|  9 | 2019-09-06 |  65 | DC  | 1001 | 4D     | <NULL>     | FK  | F             |
| 10 | 2019-09-07 |  95 | AC  | 1001 | 4D     | 0000000000 | SL  | F             |
| 11 | 2019-09-08 |  10 | AC  | 1001 | 4D     | 0000000600 | FH  | F             |
| 12 | 2019-09-09 |   8 | AC  | 1001 | <NULL> | 0000000300 | WO  | G             |
| 13 | 2019-09-10 |  40 | DC  | 1001 | <NULL> | 0000000500 | FK  | H             |
| 14 | 2019-09-11 |  65 | DC  | 1001 | <NULL> | <NULL>     | SL  | I             |
| 15 | 2019-09-12 |  95 | AC  | 1001 | <NULL> | 0000000000 | FH  | I             |
+----+------------+-----+-----+------+--------+------------+-----+---------------+
TABLE B:
+------+--------+--------+------+
| UCDE |  STM   |  SRL   | DESC |
+------+--------+--------+------+
| 1001 | 1A     | 000300 | A    |
| 1001 | 2B     | 000300 | B    |
| 1001 | 2B     | 000600 | C    |
| 1001 | 2B     | <NULL> | D    |
| 1001 | 3C     | <NULL> | E    |
| 1001 | 4D     | <NULL> | F    |
| 1001 | <NULL> | 000300 | G    |
| 1001 | <NULL> | 000500 | H    |
| 1001 | <NULL> | <NULL> | I    |
+------+--------+--------+------+

Ответы [ 2 ]

0 голосов
/ 11 октября 2019

Я сомневаюсь, что вы можете получить ожидаемый результат, используя одно объединение без сопоставления нескольких строк, которое должно быть удалено с помощью функции OLAP, например ROW_NUMBER (может быть довольно дорого в большой таблице).

Попробуйте 2-ое объединение с tabletwo (конечно, тогда вам нужно COALESCE для каждого столбца из этой таблицы):

SELECT a.TDATE, a.AMT, a.ISI, a.TS,
   Coalesce(b1.UCDE, b2.UCDE), a.ICI,
   Coalesce(b1.STM,  b2.STM), a.S_ID,
   Coalesce(b1.SRL,  b2.SRL, '0000000000') AS SRL,
   a.RES,
   -- Manually override certain conditions
   CASE
      WHEN (a.ISI = 'AP' AND a.TS = '1234') THEN 'APP'
      WHEN (a.ISI = 'JK' AND a.TS = '1234') THEN 'JAX'
      ELSE Coalesce(b1.DESC, b2.DESC)
   END AS DESC_
FROM tableone AS a
LEFT JOIN tabletwo AS b1
  ON a.TS = b1.UCDE
 AND (a.ICI = b1.STM OR (a.ICI IS NULL AND b1.STM IS NULL))
 AND (Coalesce(Right(a.S_ID,6), '000000') = Coalesce(b1.SRL, '000000'))
LEFT JOIN tabletwo AS b2
  ON a.TS = b2.UCDE
 AND (a.ICI = b2.STM OR (a.ICI IS NULL AND b2.STM IS NULL))
 AND b1.UCDE IS NULL -- join only if no match based on SRL, yet

Производительность будет в основном зависеть от PI tableoneа количество рядов в планшете два.

0 голосов
/ 10 октября 2019

Насколько я понимаю, вы пытаетесь присоединиться к TABLEONE и TABLETWO на следующих условиях:

  1. a.TS = b.UCDE

  2. a.ICI IS NOT NULL AND a.ICI = b.STM и логика № 3;в противном случае присоединитесь к b.STM IS NULL

  3. RIGHT(a.S_ID,6) = b.SRL;в противном случае, если a.S_ID = 0000000000 or IS NULL, присоединитесь к b.SRL IS NULL

Я принял указанную вами логику и заново обработал ваше JOIN условие:

SELECT a.TDATE, a.AMT, a.ISI, a.TS, b.UCDE, a.ICI, b.STM, a.S_ID,
CASE WHEN b.SRL1 IS NULL THEN '0000000000' ELSE b.SRL1 END AS SRL, a.RES,
-- Manually override certain conditions
CASE WHEN (a.ISI = 'AP' AND a.TS = '1234') THEN 'APP'
     WHEN (a.ISI = 'JK' AND a.TS = '1234') THEN 'JAX'
     ELSE b.DESC END AS DESC
FROM TABLEONE AS a
FULL OUTER JOIN TABLETWO AS b ON a.TS = b.UCDE
  AND (
    (
      a.ICI = b.STM AND -- a.ICI IS NOT NULL --> check for match on b.STM (NULL <> NULL)
      (
        (RIGHT(a.S_ID, 6) = b.SRL) OR -- Priority should be on RIGHT(a.S_ID,6) = b.SRL
        (COALESCE(a.S_ID, 0000000000) = 0000000000 AND b.SRL IS NULL)
      )
    ) OR
    (a.ICI IS NULL AND b.STM IS NULL) -- a.ICI IS NULL then join on b.STM IS NULL
  )
ORDER BY (CASE WHEN STM IS NULL THEN 2 ELSE 1 END)

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

Кроме того, я не совсем следую этой строке If it does not find a match (i.e. b.STM IS NULL), then return DESC for that row. Я предполагаю, что у вас есть логикав вашем CASE выражении в вашем SELECT, поэтому я не коснулся этой части.

Обновление
Вот таблица истинности, основанная на запросе в моем ответе:

Case    a.ICI   b.STM   "Match" Join rows?
------------------------------------------
1       NULL    NULL    NO      YES
2       5E      NULL    NO      NO
3       NULL    6B      NO      NO
4       5E      6B      NO      NO
5       5E      5E      YES     Logic #3 (a.S_ID = b.SRL?)

Это логика, которую вы ищете? Если вы получаете ожидаемые строки, то вы можете просто добавить оператор COALESCE или CASE в свой SELECT, чтобы отобразить правильное значение DESC.

Если логика в таблицевыше не то, что вы хотите, и вы не получите ожидаемые строки, а затем, исходя из вашего комментария о том, что b.STM IS NULL является универсальным, я думаю, вы можете просто изменить эту строку (a.ICI IS NULL AND b.STM IS NULL), чтобы она была просто (b.STM IS NULL). Это приведет к тому, что объединение будет работать для дела № 2.

...