Различные значения JOIN в зависимости от значения другого столбца - PullRequest
1 голос
/ 24 апреля 2019

У меня есть 2 таблицы j и c.

Обе таблицы имеют столбцы port и sec.

Для j.port = ABC я хочу объединить первые 6 символов c.sec с первыми 6 символами j.sec.

Для других j.ports я хочу присоединиться к c.sec = j.sec

Как я могу это сделать?

select c.port,j.port,c.sec,j.sec from j, c
where  c.SEC = 
   CASE WHEN j.port = 'ABC' then SUBSTRING(c.sec,1,6) = SUBSTRING(j.sec,1,6)  
   --> something like this
   else j.sec                 

Ответы [ 2 ]

1 голос
/ 24 апреля 2019

Быстродействие, разбив его на две части, может быть полезным.В противном случае сложное условие соединения заставит вложенные циклы.

SELECT c.port,
       j.port,
       c.sec,
       j.sec
FROM   j
       JOIN c
         ON LEFT(c.sec, 6) = LEFT(j.sec, 6)
WHERE  j.port = 'ABC'
UNION ALL
SELECT c.port,
       j.port,
       c.sec,
       j.sec
FROM   j
       JOIN c
         ON c.sec = j.sec
WHERE  j.port IS NULL
        OR j.port <> 'ABC' 

Или в этом конкретном случае вы также можете выполнить

  SELECT c.port,
       j.port,
       c.sec,
       j.sec
FROM   j
       JOIN c
         ON LEFT(c.sec, 6) = LEFT(j.sec, 6)
         and (j.port = 'ABC' OR c.sec = j.sec)

Это позволяет основному объединению быть простым равным соединением, которое можетиспользуйте любой из алгоритмов соединения с остаточным предикатом результата.

Для следующего примера данные на моем компьютере заняли около 700 мс, в то время как я отбил три конкурирующих ответа через 30 секунд, так как ни один из них не был выполненв то время.

create table c(port varchar(10), sec varchar(10)  index ix clustered )  
create table j(port varchar(10), sec varchar(10))  

INSERT INTO c 
SELECT TOP 1000000 LEFT(NEWID(),10) , LEFT(NEWID(),10)
FROM sys.all_objects o1, sys.all_objects o2

INSERT INTO j 
SELECT TOP 1000000 LEFT(NEWID(),10) , LEFT(NEWID(),10)
FROM sys.all_objects o1, sys.all_objects o2
0 голосов
/ 24 апреля 2019

Вы можете использовать:

select c.port,j.port,c.sec,j.sec 
from j 
join c
  on  (CASE WHEN j.port = 'ABC' and SUBSTRING(c.sec,1,6) = SUBSTRING(j.sec,1,6) then 1
           WHEN c.sec = j.sec THEN 1
      END) = 1

Так же, как:

select c.port,j.port,c.sec,j.sec 
from j 
join c
  on (j.port = 'ABC' and SUBSTRING(c.sec,1,6) = SUBSTRING(j.sec,1,6))
  or (c.SEC = j.sec AND (j.port <> 'ABC' or j.port IS NULL))
...