不同的JOIN值取决于另一列的值

时间:2019-04-24 19:36:38

标签: sql sql-server join inner-join

我有2个表j和c。

两个表都有port和sec列。

对于j.port = ABC,我想将c.sec的前6个字符与j.sec的前6个字符连接起来。

对于其他j.port,我想加入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 个答案:

答案 0 :(得分:1)

将性能明智地分成两部分可能是有益的。复杂的连接条件将强制嵌套循环。

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

答案 1 :(得分:0)

您可以使用:

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))