2016-09-12 4 views
4

최근에 인터뷰를했고 내부 조인 만 사용하여 왼쪽 조인을 만드는 방법을 묻습니다. 인터뷰 담당자는 회사에서 사용하는 일부 소프트웨어는 왼쪽 조인을 허용하지 않으므로 내부 조인을 사용하여이를 수행해야한다고 말했습니다. 나는 그 질문으로 스터브되었다. 그리고 나는 그것을하는 방법을 누구라도 여기에서 알지 않는가에 관해 궁금하게 생각하고 있었다?내부 조인 만 사용하여 왼쪽 조인을 만드는 방법은 무엇입니까?

+0

'INNER JOIN'을 (를) * 사용 하시겠습니까?라는 말은'EXISTS','UNION' 등을 의미합니까? – Lamak

+0

@Lamak 그래, 그는 내가 내적 조인만을 사용할 수 있다는 것을 나에게 알렸다. 난 단지 SQL의 기초를 알고 그래서 어쩌면 노동 조합을 사용하고 그것을 할 수있는 유일한 방법입니다. – Antonio

+0

나는 이것이 흥미로운 질문 일 수 있겠는가? 우리가 'INNER'를 사용하는 순간, 일치하지 않는 행이 쫓겨납니다. – dubes

답변

3

여기 내 균열이 있습니다. 기본적으로 내부 조인을 교차 적용으로 변환 한 다음 실제 원하는 조인 조건과 일치하지 않으면 값을 NULL 처리합니다.

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 
+0

테이블 2에 1 개의 행만 있기 때문에 작동합니다. 하나를 더 추가하면 더 이상 LEFT JOIN으로 작동하지 않습니다. – Lamak

+0

더 많은 행을 수용하도록 업데이트되었습니다. – dfundako

1

여기 내 시도입니다. 확인 된 날짜 : http://sqliteonline.com/

제한 사항 : 반환하지 않으려는 열을 "null"로 설정해야합니다.

편집 OP에는 UNION이 없으므로이 답변이 적용되지 않습니다.

이 방법에 대해
CREATE TABLE demo (id int, name varchar(32)); 

CREATE TABLE demo_details (demo_id int, description varchar(64)); 

INSERT INTO demo_details 
VALUES (1, 
     'Woohooooooooo'); 

SELECT * 
FROM demo d 
INNER JOIN demo_details dd ON d.id = dd.demo_id 
UNION 
SELECT d.*, 
     NULL, 
     NULL 
FROM demo d 
INNER JOIN demo_details dd ON d.id <> dd.demo_id; 
+0

op는 'UNION' – Lamak

+0

좋은 지적이며, 그림 게시판으로 돌아갑니다. – dubes

+0

정말입니까? Antonio는 말했다 : "어쩌면 노동 조합을 사용하고 존재하는 것만이 그것을 할 수있는 유일한 방법입니다." 그가이 옵션들을 완전히 나에게서 제외시키는 것처럼 들리지는 않습니다. – cars10m

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 
+0

하나의 제한은 'UNION'이 아닙니다 – Lamak

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 

당신은 가입 왼쪽으로 원하는 모든 값에 대한 하위 쿼리를 작성해야 할 것, 재미 소리!

하위 쿼리가 여러 값을 반환하면 각 행이 한 번만 조인되도록 털이 창 파티션을 작성할 수 있습니다.

0

나는 해결책이 select 문에서 멋진 것을 시도하지 않고 수동으로 왼쪽 조인을 다시 생성하는 것입니다. 그래서 당신은 임시 테이블을 만들고, 더 큰 테이블에서 id 값을주고, 더 작은 테이블에서 그것을 채우고, 내부 조인을합니다. 성능에 친숙하지는 않지만 임시 테이블을 항상 첫 번째 테이블의 ID 값을 유지하면서 두 번째 테이블의 값만 저장하는 영구 테이블로 전환 할 수 있다고 상상합니다.

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

결과는 내부 조인과 동일해야합니다. 힌트 열이 이제 네 번째 및 다섯 번째 결과에 대해 null임을 알 수 있습니다. 이름이 겹칠 수있는 잠재적 인 문제점을 보여주기 위해 그 것을 남겼습니다. 가장 쉬운 해결책은 열 이름이 충돌하지 않도록하는 것입니다. 예를 들어 임시 테이블에서 '힌트'열의 이름을 'hint2'로 지정하십시오.

0

+1 @ dfundako의 대답은 단일 SQL 쿼리에서 요구 사항을 수행하는 것이기 때문에 그렇게하는 것입니다.표 A로부터

SELECT ... FROM joinedTable; 
0

가하는 선택을 :

또 다른 옵션은 외부 그런 다음 클라이언트가 규칙을 위반하지 않고 간단한 쿼리를 할 수

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

가입 않는 뷰를 정의하는 것입니다 표 B "내부 조인" 표 B에서 선택하십시오. 표 A에없는 곳

그런 다음 다양한 방법으로 결합하십시오. SQL에서는 Union을 수행하거나 테이블 또는 임시 테이블로 선택하고 임시 테이블을 선택할 수 있습니다.

또는 SQL 명령을 작성중인 클라이언트 도구에서이를 결합 할 수 있습니다.

트릭 질문 일 수 있습니다. 질문을하는 사람은 자신이하는 일을 알지 못할 수도 있습니다. 나는 내가 옳은 대답을했던 인터뷰 질문을 받았다. 그러나 묻는 사람은 그 해답을 정확하게 알지 못했고 같은 잘못 이해 한 후보자를 찾고있었습니다. 당신이 어떻게 반응하는지 보는 것도 문제가 될 수 있습니다. 폭발하거나, 비난을가합니까, 아니면 합리적으로 대응합니까?

생각할 사항.

+0

저는 단 2 개의 테이블로 SQL에서 다 대다 관계를 수행하는 방법을 묻습니다. 트릭이나 무능한 질문인지 확실하지 않습니다. –

+0

그래, 그는 그가 대답을 모르겠다는 것을 내가 아는 질문에 어떻게 반응 할 것인지를보기 위해 그것을하고 있었다. 면접관은 자신이 무슨 말을하는지 확실히 알고 있었고, 내가 들어가기 전에 이것이 인터뷰 스타일이라고 들었습니다. – Antonio

관련 문제