简体   繁体   中英

Select columns from a table based on two different where clauses / joins - if one column matches use that, if not then use another

I am trying to create a SQL query that will SELECT columns from table 2 based on equality between one of two columns in table 1.

I understand I can't JOIN on multiple columns. Conceptually I want it to JOIN on a common column, call it column 1, if column 1 exists (not NULL) in both tables, else JOIN on a different common column, call it column2.

Since a JOIN like this isn't legal, I came up with an alternative with multiple COALESCE 's but it is far too slow for my purposes (there will be a lot of rows in those tables):

The two WHERE clauses represent checking if the first column exists or not in both tables and then checking the second column.

My query will need to select n columns from table2. How it is currently I have to add n COALESCE statements, which is really inefficient.

Does anyone know a way of doing this query all at once, ie without coalescing multiple times? Or another way of making it performant?

Minimum reproducible example:

/* Definition query */
CREATE TABLE [dbo].[table1](
    [foo] [bigint] NULL,
    [bar] [nvarchar](50) NULL,
    [qux] [bigint] NULL,
    [quux] [nvarchar](50) NULL
); 

CREATE TABLE [dbo].[table2](
    [baz] [nvarchar](50) NULL,
    [qux] [bigint] NULL,
    [quux] [nvarchar](50) NULL,
    [corge] [bigint] NULL
);

/* Sample data */
INSERT [dbo].[table1] ([foo], [bar], [qux], [quux]) VALUES (1, N'asd', 345, NULL);
INSERT [dbo].[table1] ([foo], [bar], [qux], [quux]) VALUES (2, N'fas', NULL, N'abc');
INSERT [dbo].[table1] ([foo], [bar], [qux], [quux]) VALUES (3, N'fasfdjka', 678, NULL);
INSERT [dbo].[table1] ([foo], [bar], [qux], [quux]) VALUES (4, N'jggiy', NULL, N'def');
INSERT [dbo].[table2] ([baz], [qux], [quux], [corge]) VALUES (N'afsfsaf', 345, N'xyz', 764694659);
INSERT [dbo].[table2] ([baz], [qux], [quux], [corge]) VALUES (N'jjuiku', 8910, N'abc', 519285912);
INSERT [dbo].[table2] ([baz], [qux], [quux], [corge]) VALUES (N'gghsd', 678, N'vuw', 152512512);
INSERT [dbo].[table2] ([baz], [qux], [quux], [corge]) VALUES (N'oolas;p', 111213, N'def', 921839129);


/* Select query */
SELECT t1.foo, t1.bar  ,
    COALESCE(  
    (  
    SELECT top 1 t2.baz 
   FROM  table2 as t2  
    WHERE t2.qux = t1.qux   
    ),  
    (  
    SELECT top 1 t2.baz 
    FROM  table2 as t2  
    WHERE  t2.quux = t1.quux
    )  
    ) AS baz, 
    COALESCE(  
    (  
    SELECT top 1 t2.corge 
   FROM  table2 as t2  
    WHERE t2.qux = t1.qux   
    ),  
    (  
    SELECT top 1 t2.corge 
    FROM  table2 as t2  
    WHERE  t2.quux = t1.quux
    ) ) AS corge  
FROM  table1 as t1

Here is the result I am getting, which is the desired result. But when you operate on large tables it is far too slow, which makes it inviable.

Coalesce result

I tried INTERSECT in place of COALESCE but it gives me this result with NULL 's in both columns I trying to select from table 2, which is not desired:

SELECT t1.foo, t1.bar  , 
    (SELECT top 1 t2.baz 
   FROM  table2 as t2  
    WHERE t2.qux = t1.qux
    INTERSECT  
    SELECT top 1 t2.baz 
    FROM  table2 as t2  
    WHERE  t2.quux = t1.quux)
    AS baz,
    (SELECT top 1 t2.corge 
   FROM  table2 as t2  
    WHERE t2.qux = t1.qux   
    INTERSECT
    SELECT top 1 t2.corge 
    FROM  table2 as t2  
    WHERE  t2.quux = t1.quux)
    AS corge
FROM  table1 as t1

Intersect result

I tried using EXCEPT instead of COALESCE and it gave me a different result, but not a desired one:

SELECT t1.foo, t1.bar  , 
    (SELECT top 1 t2.baz 
   FROM  table2 as t2  
    WHERE t2.qux = t1.qux
    EXCEPT  
    SELECT top 1 t2.baz 
    FROM  table2 as t2  
    WHERE  t2.quux = t1.quux)
    AS baz,
    (SELECT top 1 t2.corge 
   FROM  table2 as t2  
    WHERE t2.qux = t1.qux   
    EXCEPT
    SELECT top 1 t2.corge 
    FROM  table2 as t2  
    WHERE  t2.quux = t1.quux)
    AS corge
FROM  table1 as t1

Except result

Thanks

Something like this?

select 
    t1.foo
    ,t1.bar
    ,isnull(t2.baz, t3.baz) as baz 
    ,isnull(t2.corge, t3.corge) as corge
from #table1 t1
left outer join #table2 t2 on t1.qux = t2.qux
left outer join #table2 t3 on t1.quux = t3.quux

Returns:

foo bar baz corge
1 asd afsfsaf 764694659
2 fas jjuiku 519285912
3 fasfdjka gghsd 152512512
4 jggiy oolas;p 921839129

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM