如何仅使用内部联接创建左联接?

时间:2016-09-12 15:25:14

标签: sql left-join inner-join

我最近接受了一次采访,有人问我如何通过仅使用内连接来创建左连接。面试官告诉我他们在公司使用的一些软件不允许使用左连接,所以我们必须使用内部连接来完成它们。我对这个问题很感兴趣,我想知道这里有人知道怎么做吗?

7 个答案:

答案 0 :(得分:3)

这是我对它的抨击。它基本上将内部联接转换为交叉应用,如果它们与实际所需的连接条件不匹配,则将值清零。

CREATE TABLE #testusers (userid INT)

CREATE TABLE #testusers2 (userID INT)

INSERT INTO #testusers (userid)
VALUES (1)
    , (2)
    , (3)

INSERT INTO #testusers2 (userid)
VALUES (2), (5), (1)


--Expecting to see one result due to straight inner join
SELECT t1.*
    , t2.*
FROM #testusers t1
INNER JOIN #testusers2 t2
    ON t1.userid = t2.userid

--Forcing all results by basically doing a cross apply and then NULLing out non matching values based on the join condition
SELECT distinct t1.*
    , MAX(CASE 
        WHEN t1.userid <> t2.userID
            THEN NULL
        ELSE t2.userid
        END) AS userid
FROM #testusers t1
INNER JOIN #testusers2 t2
    ON t1.userid = t2.userid
        OR 1 = 1
GROUP BY t1.userid

也适用于VARCHAR。

CREATE TABLE #testusersnames (username varchar(10))

CREATE TABLE #testusersnames2 (username varchar(10))

INSERT INTO #testusersnames (username)
VALUES ('Tom')
    , ('Jane')
    , ('Dick')

INSERT INTO #testusersnames2 (username)
VALUES ('Tom'), ('Sally'), ('Mary')

SELECT t1.*
    , t2.*
FROM #testusersnames t1
INNER JOIN #testusersnames2 t2
    ON t1.username = t2.username

--Forcing all results by basically doing a cross apply and then NULLing out non matching values based on the join condition
SELECT distinct t1.*
    , MAX(CASE 
        WHEN t1.username <> t2.username
            THEN NULL
        ELSE t2.username
        END) AS username
FROM #testusersnames t1
INNER JOIN #testusersnames2 t2
    ON t1.username = t2.username
        OR 1 = 1
GROUP BY t1.username

答案 1 :(得分:1)

这是我的尝试。已在http://sqliteonline.com/

上验证

限制:我必须“删除”我不想返回的列。

编辑 OP说没有UNION,因此这个答案不适用。

{{1}}

答案 2 :(得分:1)

这个怎么样:

SELECT * 
FROM Table1 t1
INNER JOIN (
  SELECT * FROM Table2
  UNION 
  SELECT {NULL for every column in Table2}
) t2
  ON 1=1
WHERE t1.id = t2.id
OR t2.id IS NULL

答案 3 :(得分:0)

你可以这样做:

-- dummy data
with a as (
    select 
        1 as id, 
        'A' as name
    union
    select 2, 'B'
),

b as  (
    select 
        1 as id, 
        'C' as value 
)

select *, 
    (select b.value
        from 
    b 
        inner join a a1 
            on a1.id=b.id 
            and a1.id = a.id
    ) as bvalue 
from
    a 

你必须为你想要加入的每个值写一个子查询,听起来很有趣!

如果您的子查询返回多个值,您可以编写一个毛茸茸的窗口分区,以确保每行只连接一次。

答案 4 :(得分:0)

我看到解决方案不是尝试在select语句中做一些奇特的事情,而是手动重新创建左连接。因此,您创建一个临时表,从较大的表中为其赋予一个id值,从较小的表中填充它,然后在其上填充内部联接。它不是非常友好,但我想你可以将临时表转换为永久表,它永远保留所有第一个表的ID值,同时只保存第二个表中的值。 / p>

--setup (optional for first time)
DROP TABLE demo;
DROP TABLE demoLeftJoin;
DROP TABLE temp;
--setup
CREATE TABLE demo(id int, lastName varchar(32), hint varchar(120));
CREATE TABLE demoLeftJoin(id int, name varchar(32), hint varchar(120));
--populate demo
INSERT INTO demo VALUES (1, 'Doe', 'nothing');
INSERT INTO demo VALUES (2, 'Doe', 'nothing2');
INSERT INTO demo VALUES (3, 'Deer', 'nothing3');
--populate demoLeftJoin
INSERT INTO demoLeftJoin VALUES (1, 'John', 'nothing');
INSERT INTO demoLeftJoin VALUES (2, 'Jane', 'nothing2');
INSERT INTO demoLeftJoin VALUES (3, 'John', 'nothing3');
INSERT INTO demoLeftJoin VALUES (4, 'Buck', 'nothing4');
INSERT INTO demoLeftJoin VALUES (5, 'Truck', 'nothing5');
--create temp table
CREATE TABLE temp(id int, lastName varchar(32), hint varchar(120));
--make sure it will match an inner join for all values from demoLeftJoin
INSERT INTO temp select id, NULL, NULL from demoLeftJoin;
--populate temp with values you want from demo
UPDATE temp
SET 
    lastName = (SELECT d.lastName FROM demo d WHERE temp.id = d.id), 
    hint = (SELECT d.hint FROM demo d WHERE temp.id = d.id)
WHERE temp.id in (SELECT d.id FROM demo d);
-- perform inner join
SELECT * FROM demoLeftJoin dlj INNER JOIN temp t on dlj.id = t.id;

您的结果应该为您提供内部联接的等效内容。您可能会注意到第4和第5个结果的提示列现在为空。我已离开,以便向您显示重叠名称的潜在问题。最简单的解决方案是确保列名称不会发生冲突,例如,将名称命名为“&#39;提示”。列到&#39; hint2&#39;在临时桌上。

答案 5 :(得分:0)

+1 @ dfundako的答案,如果要求是在单个SQL查询中执行,那就是我的方式。

另一个选择是定义执行外连接的VIEW

CREATE VIEW joinedTable AS
  SELECT ... FROM table1 LEFT OUTER JOIN table2 ON ...;

然后客户端可以在不违反规则的情况下进行简单查询:

SELECT ... FROM joinedTable;

答案 6 :(得分:0)

从表A到表B选择“内部连接” 从表B中选择不在表A中的选项

然后将它们与各种方法结合起来。在Sql中你可以做一个Union,或者你可以选择它们到表或临时表中,然后选择临时表。

或者您可以将它们组合在发出sql命令的客户端工具上。

这可能是一个棘手的问题。提问的人可能不知道他或她在做什么。在我回答正确的情况下,我接受了面试问题。但是提问的人并没有正确地知道答案,并且正在寻找一个与他们有同样错误理解的候选人。这也可能是一个问题,看你如何反应。你爆炸了吗,你是指控,还是你做出了合理的反应?

要考虑的事情。