2017-03-15 2 views
2

두 개의 테이블이 있습니다. 하나는 Objects이고 다른 하나는 각 개체에 대해 Settings입니다. Objects 테이블의 모든 행에 Settings 테이블에 해당 행이있는 것은 아닙니다. "기타"오브젝트에 사용될 것으로 가정되는 Settings 테이블에 특수 행이 있습니다."기타"행에 가입하는 방법

ObjectsSettings 사이에 조인을 만들면 어떻게 하나 또는 "기타"설정이있는 경우 주어진 설정을 얻을 수 있습니까?

예를 들어 다음 스크립트를 고려 :

CREATE TABLE #Objects (Code nvarchar(20) not null); 
CREATE TABLE #Settings (Code nvarchar(20) not null, Value int not null); 

INSERT INTO #Objects 
VALUES 
    ('A'), 
    ('B'), 
    ('D') 

INSERT INTO #Settings 
VALUES 
    ('A', 1), 
    ('B', 2), 
    ('C', 3), 
    ('Other', 4) 

SELECT 
    #Objects.Code, 
    #Settings.Value 
FROM 
    #Objects 
    JOIN #Settings 
     ON #Objects.Code = #Settings.Code 
     OR #Settings.Code = 'Other' 

DROP TABLE #Settings, #Objects 

나는이 얻을 꿔 다음을 사용

Code | Value 
----- | ----- 
A  | 1 
A  | 4 
B  | 2 
B  | 4 
D  | 4 
+1

아래와 같이 #Settings 테이블과 가입이 CTE를 사용하지 나는 exe를보고 싶다. 지금까지의 네 가지 답변 각각에 대한 합리적인 계획과 합리적인 크기의 색인 된 테이블의 실제 데이터에 대한 계획. 샘플 데이터의 경우 모든 답변에 대해 동일하거나 유사한 계획을 제공하며 차이가 너무 작아 측정 할 수 없습니다. –

+0

이제 다섯 가지 답변 : :) 그러나 나는 계획을 보지 않고 그 중 누구에게나 투표하는 것을 주저합니다. –

+0

@JoelCoehoorn 슬프게도 내 성능 요구 사항이 엄격하지는 않습니다 ('1000 개 정도의 오브젝트에서 30 분 이내에 실행됩니다.),하지만 개발 예산은 ('아직 안 끝났습니까? 왜 안 했습니까? '). 따라서 큰 데이터에 대한 쿼리 계획은 다른 날을 기다려야합니다. 나는 분석을하는 것이 좋을 것이라고 동의한다. –

답변

1

:

Code | Value 
---- | ----- 
A | 1 
B | 2 
D | 4 

내가 실제로 얻고 것은을 left joinnull입니다. o.Code은 일치하지 않습니다. #Settings 을 사용하고 coalesce()을 사용하여이 null 일 때 value#Settings에서 반환하십시오.

coalesce 대신 isnull()을 사용할 수 있습니다. 결과는이 인스턴스에서 동일합니다.

나는이 허용되는 경우 잘 모르겠지만, 그것은 올바른 결과를 반환 :

select 
    o.Code 
    , coalesce(s.Value,x.Value) as Value 
from #Objects o 
    left join #Settings s 
    on o.Code = s.Code 
    cross join (
    select top 1 value 
    from #Settings 
    where Code = 'Other' 
    ) x 

rextester 데모 : http://rextester.com/EBUG86037

반환 : 양식에서

+------+-------+ 
| Code | Value | 
+------+-------+ 
| A |  1 | 
| B |  2 | 
| D |  4 | 
+------+-------+ 

를 @ RBarryYoung의 선호도 :

select 
    o.Code 
    , coalesce(s.Value,x.Value) as Value 
from #Objects o 
    left join #Settings s 
    on o.Code = s.Code 
    inner join #Settings x 
    on x.Code = 'Other' 

이것은 더 간결하며 (많은 keystrokes을 저장합니다) 초기 응답과 동일한 실행 계획을 생성합니다. 그것이하는 일에 대해 어느 정도 분명하든간에 나는 당신에게 달려 있습니다. 나는 둘 다 좋아합니다.

+0

니스, 내가 '내부 조인 (..) 코드'= '기타'에서'크로스 조인 (.. 어디 코드 = '기타') '선호합니다. – RBarryYoung

+0

@RBarryYoung 감사합니다. 대체 답변을 업데이트했습니다. – SqlZim

2

당신은 APPLY하여이 작업을 수행 할 수 있습니다

SELECT o.Code, s.Value 
FROM #Objects o 
CROSS APPLY (
    SELECT TOP 1 * 
    FROM #Settings s 
    WHERE s.Code = o.Code or s.Code = 'Other' 
    ORDER BY case when s.Code = o.Code then 0 else 1 end 
) s 
재미를 들어

:

SELECT o.Code, s2.Value 
FROM #Objects o 
LEFT JOIN #Settings s1 on s1.Code = o.Code 
INNER JOIN #Settings s2 on s2.Code = coalesce(s1.Code, 'Other') 
: 동일한 기본 테마에 모든 유사하다 Gurv, jyaoSqlZim에 의해 답변에서 하이브리드

지금까지이 방법 (LEFT JOIN + INNER JOIN ON COALESCE())을 가장 좋아했습니다.

개체 레코드 당 하나의 설정 레코드 만있을 수있는 경우에만 작동합니다.APPLY 응답 이 여전히 변경되면이 작동하지만 여기에서는 다른 대답이 작동하지 않을 수 있습니다.

select o.Code, 
    coalesce(s.Value, s2.value) as value 
from #Objects o 
left join #Settings s on o.Code = s.Code 
join #Settings s2 on s2.Code = 'Other' 
+0

나는이 문제에 대한 답을 가장 좋아한다. 왜냐하면 내가 가진 문제는 실제로는 좀 더 복잡한 방법의 작은 부분이며 이미 APPLY를 사용하고 있기 때문이다. –

1

[코드]의 "기타"의 값을 갖는다 Alternative_code] [표 #Object]의 추가 열이 [#Settings]에 존재하고

; with c as (
    select alternative_Code = isnull(s.code, 'Other'), o.Code 
    from #Objects o 
    left join #Settings s 
     on o.Code = s.Code) 
select c.Code, s.value 
from c 
inner join #Settings s 
on c.alternative_Code = s.Code 
1

또 다른 방법은 추가 CTE를 사용하는 것입니다 효과적으로 cross joinleft join 다른 하나 - 다음 방금 두 번 join을 할 수있는 하나의 "기타"값이있을 것입니다 경우

+0

cte없이이 작업을 수행 할 수 있습니다. 두 번 설정에 조인하고 두 번째 조인을위한 조건에 합치면됩니다. –