2010-06-02 30 views
3

我的情況是這樣的。我的產品有PK「家長」具有「組件」中的數據看起來是這樣T-SQL - 在單個表中找到PK的差異(自加入?)

Parent(PK) Component 
Car1   Wheel 
Car1   Tyre 
Car1   Roof 
Car2   Alloy 
Car2   Tyre 
Car2   Roof 
Car3   Alloy 
Car3   Tyre 
Car3   Roof 
Car3   Leather Seats 

現在我想做一個表是一些查詢,我可以養活兩個代碼,看到的差異... IE如果我喂「Car1」,「Car2」它會返回類似於;

Parent  Component 
Car1   Wheel 
Car2   Alloy 

由於這是兩者之間的差異。如果我說「Car1」,我會指望「Car3」;

Parent  Component 
Car1   Wheel 
Car3   Alloy 
Car3   Leather Seats 

您對此事的幫助將不勝感激。

回答

1

另一種

DECLARE @thisCar varchar(20) 
DECLARE @thatCar varchar(20) 

SET @thisCar = 'Car1' 
SET @thatCar = 'Car2' 


SELECT * FROM 
(
    SELECT @thisCar AS Parent, Component FROM products WHERE parent = @thisCar 
    EXCEPT 
    SELECT @thisCar AS Parent, Component FROM products WHERE parent = @thatCar 
) c1 
UNION ALL 
SELECT * FROM 
(
    SELECT @thatCar AS Parent, Component FROM products WHERE parent = @thatCar 
    EXCEPT 
    SELECT @thatCar AS Parent, Component FROM products WHERE parent = @thisCar 
    ) c2 
+0

但這很簡單它是不那麼有效,然後gbn和我的回答 – 2010-06-02 11:48:26

2

我嘗試這樣做,它返回預期的結果:

Select Min(parent) As parent, component 
From 
(
    Select parent, component 
    From products 
    Where parent In ('Car1', 'Car3') 
) 
Group By component 
Having Count(*) = 1 

子查詢獲取的Car1Car2所有組件,並與Group ByHaving -clause我們去掉那些組件,這兩個車有。

+0

我有點不喜歡做數...感覺有點不對 – 2010-06-02 09:18:59

+0

@Sam:也想過這個,但在這種情況下,我覺得它更容易閱讀,我希望它執行得很好(有一個'父'的索引,或者甚至更好的'父,組件'的複合索引)。將不得不被描述。 – 2010-06-02 09:27:36

+0

臨時工您可以在SEDE上進行配置文件 http://cloudexchange.cloudapp.net/stackoverflow/q/1978/text – 2010-06-02 09:33:08

3
DECLARE @ThisCar .., @ThatCar; 

SELECT @ThisCar = '...', @ThatCar = '...'; 

SELECT 
    Parent, Component 
FROM 
    MyTable M1 
WHERE 
    M1.Parent = @ThisCar 
    AND 
    NOT EXISTS (SELECT * 
     FROM 
      MyTable M2 
     WHERE 
      M2.Parent = @ThatCar AND M1.Component = M2.Component) 
UNION 
SELECT 
    Parent, Component 
FROM 
    MyTable M2 
WHERE 
    M2.Parent = @ThatCar 
    AND 
    NOT EXISTS (SELECT * 
     FROM 
      MyTable M1 
     WHERE 
      M1.Parent = @ThisCar AND M1.Component = M2.Component): 
+0

謝謝。這裏有一些好的答案。 – CaRDiaK 2010-06-02 09:38:29

+1

@Sam Saffron:垃圾:通常效率最高:-) – gbn 2010-06-02 10:12:54

+1

我聲明雙垃圾......看到我的回答,更快,想要證明,簡介:) – 2010-06-02 11:35:01

4

沒有GROUP BY或UNION:

create table Products (
    Parent varchar(20) not null, 
    Component varchar(20) not null 
) 
insert into Products (Parent,Component) 
select 'Car1','Wheel' union all 
select 'Car1','Tyre' union all 
select 'Car1','Roof' union all 
select 'Car2','Alloy' union all 
select 'Car2','Tyre' union all 
select 'Car2','Roof' union all 
select 'Car3','Alloy' union all 
select 'Car3','Tyre' union all 
select 'Car3','Roof' union all 
select 'Car3','Leather Seats' 
go 
select 
    ISNULL (a.Parent,b.Parent) as Parent, 
    ISNULL (a.Component,b.Component) as Component 
from 
    Products a 
     full outer join 
    Products b 
     on 
      a.Component = b.Component and 
      a.Parent = 'Car1' and 
      b.Parent = 'Car3' 
where 
    (a.Parent = 'Car1' and b.Parent is null) or 
    (b.Parent = 'Car3' and a.Parent is null) 
+0

可運行版本:http://cloudexchange.cloudapp。net/stackoverflow/q/2082/text – 2010-06-02 09:25:52

+0

請注意,如果您在具有10k行的表格上嘗試此操作,查詢窒息並需要一個真正的完整連接的長時間原因,請參閱我的答案以獲取有效途徑 – 2010-06-02 11:41:18

0

我異形是迄今爲止速度最快的解決方案是:

select 
    ISNULL (a.Parent,b.Parent) as Parent, 
    ISNULL (a.Component,b.Component) as Component 
from 
    (select * from Products where Parent = 'Car1') as a 
     full outer join 
    (select * from Products where Parent = 'Car2') as b 
     on 
      a.Component = b.Component 
where 
    (a.Parent = 'Car1' and b.Parent is null) or 
    (b.Parent = 'Car2' and a.Parent is null) 

它運行比@gbns solu快大約30%重刑和很多很多很多倍@Damiens解決方案

對於勇敢快,這裏有一些執行計劃:

 
select 
    ISNULL (a.Parent,b.Parent) as Parent, 
    ISNULL (a.Component,b.Component) as Component 
from 
    (select * from Products where Parent = 'Car1') as a 
     full outer join 
    (select * from Products where Parent = 'Car2') as b 


StmtText 
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
    |--Compute Scalar(DEFINE:([Expr1012]=isnull([Expr1004],[Expr1010]), [Expr1013]=isnull([Expr1005],[Expr1011]))) 
     |--Filter(WHERE:([Expr1004]='Car1' AND [Expr1010] IS NULL OR [Expr1010]='Car2' AND [Expr1004] IS NULL)) 
      |--Hash Match(Full Outer Join, HASH:([CloudDb].[dbo].[Products].[Component])=([CloudDb].[dbo].[Products].[Component]), RESIDUAL:([CloudDb].[dbo].[Products].[Component]=[CloudDb].[dbo].[Products].[Component])) 
       |--Compute Scalar(DEFINE:([Expr1004]=[CloudDb].[dbo].[Products].[Parent], [Expr1005]=[CloudDb].[dbo].[Products].[Component])) 
       | |--Nested Loops(Inner Join, OUTER REFERENCES:([Bmk1000])) 
       |   |--Index Seek(OBJECT:([CloudDb].[dbo].[Products].[idxProducts]), SEEK:([CloudDb].[dbo].[Products].[Parent]='Car1') ORDERED FORWARD) 
       |   |--RID Lookup(OBJECT:([CloudDb].[dbo].[Products]), SEEK:([Bmk1000]=[Bmk1000]) LOOKUP ORDERED FORWARD) 
       |--Compute Scalar(DEFINE:([Expr1010]=[CloudDb].[dbo].[Products].[Parent], [Expr1011]=[CloudDb].[dbo].[Products].[Component])) 
         |--Nested Loops(Inner Join, OUTER REFERENCES:([Bmk1006])) 
          |--Index Seek(OBJECT:([CloudDb].[dbo].[Products].[idxProducts]), SEEK:([CloudDb].[dbo].[Products].[Parent]='Car2') ORDERED FORWARD) 
          |--RID Lookup(OBJECT:([CloudDb].[dbo].[Products]), SEEK:([Bmk1006]=[Bmk1006]) LOOKUP ORDERED FORWARD) 

StmtText 
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 

SELECT 
    Parent, Component 
FROM 
    Products M1 
WHERE 
    M1.Parent = 'Car1' 
    AND 
    NOT EXISTS (SELECT * 
     FROM 
      Products M2 
     WHERE 
      M2.Parent = 'Car2' AND M1.Component = M2.Component) 
UNION ALL 
SELEC 

StmtText 
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
    |--Concatenation 
     |--Nested Loops(Left Anti Semi Join, OUTER REFERENCES:([M1].[Component])) 
     | |--Nested Loops(Inner Join, OUTER REFERENCES:([Bmk1000])) 
     | | |--Index Seek(OBJECT:([CloudDb].[dbo].[Products].[idxProducts] AS [M1]), SEEK:([M1].[Parent]='Car1') ORDERED FORWARD) 
     | | |--RID Lookup(OBJECT:([CloudDb].[dbo].[Products] AS [M1]), SEEK:([Bmk1000]=[Bmk1000]) LOOKUP ORDERED FORWARD) 
     | |--Top(TOP EXPRESSION:((1))) 
     |   |--Nested Loops(Inner Join, OUTER REFERENCES:([Bmk1003])) 
     |    |--Index Seek(OBJECT:([CloudDb].[dbo].[Products].[idxProducts] AS [M2]), SEEK:([M2].[Parent]='Car2') ORDERED FORWARD) 
     |    |--RID Lookup(OBJECT:([CloudDb].[dbo].[Products] AS [M2]), SEEK:([Bmk1003]=[Bmk1003]), WHERE:([CloudDb].[dbo].[Products].[Component] as [M1].[Component]=[CloudDb].[dbo].[Products].[Component] as [M2].[Component]) LOOKUP ORDERED FORWA 
     |--Nested Loops(Left Anti Semi Join, OUTER REFERENCES:([M2].[Component])) 
      |--Nested Loops(Inner Join, OUTER REFERENCES:([Bmk1007])) 
      | |--Index Seek(OBJECT:([CloudDb].[dbo].[Products].[idxProducts] AS [M2]), SEEK:([M2].[Parent]='Car2') ORDERED FORWARD) 
      | |--RID Lookup(OBJECT:([CloudDb].[dbo].[Products] AS [M2]), SEEK:([Bmk1007]=[Bmk1007]) LOOKUP ORDERED FORWARD) 
      |--Top(TOP EXPRESSION:((1))) 
       |--Nested Loops(Inner Join, OUTER REFERENCES:([Bmk1010])) 
         |--Index Seek(OBJECT:([CloudDb].[dbo].[Products].[idxProducts] AS [M1]), SEEK:([M1].[Parent]='Car1') ORDERED FORWARD) 
         |--RID Lookup(OBJECT:([CloudDb].[dbo].[Products] AS [M1]), SEEK:([Bmk1010]=[Bmk1010]), WHERE:([CloudDb].[dbo].[Products].[Component] as [M1].[Component]=[CloudDb].[dbo].[Products].[Component] as [M2].[Component]) LOOKUP ORDERED FORWA 

StmtText 
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 

SELECT * FROM 
(
    SELECT 'Car1' AS Parent, Component FROM products WHERE parent = 'Car1' 
    EXCEPT 
    SELECT 'Car1'AS Parent, Component FROM products WHERE parent = 'Car2' 
) c1 
UNION ALL 
SELECT * FROM 
(
    SELECT 'Car2' AS Parent, Component 

StmtText 
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
    |--Concatenation 
     |--Nested Loops(Left Anti Semi Join, OUTER REFERENCES:([CloudDb].[dbo].[Products].[Component])) 
     | |--Sort(DISTINCT ORDER BY:([CloudDb].[dbo].[Products].[Component] ASC)) 
     | | |--Compute Scalar(DEFINE:([Expr1004]='Car1')) 
     | |   |--Nested Loops(Inner Join, OUTER REFERENCES:([Bmk1000])) 
     | |    |--Index Seek(OBJECT:([CloudDb].[dbo].[Products].[idxProducts]), SEEK:([CloudDb].[dbo].[Products].[Parent]='Car1') ORDERED FORWARD) 
     | |    |--RID Lookup(OBJECT:([CloudDb].[dbo].[Products]), SEEK:([Bmk1000]=[Bmk1000]) LOOKUP ORDERED FORWARD) 
     | |--Top(TOP EXPRESSION:((1))) 
     |   |--Nested Loops(Inner Join, OUTER REFERENCES:([Bmk1005])) 
     |    |--Index Seek(OBJECT:([CloudDb].[dbo].[Products].[idxProducts]), SEEK:([CloudDb].[dbo].[Products].[Parent]='Car2') ORDERED FORWARD) 
     |    |--RID Lookup(OBJECT:([CloudDb].[dbo].[Products]), SEEK:([Bmk1005]=[Bmk1005]), WHERE:([CloudDb].[dbo].[Products].[Component]=[CloudDb].[dbo].[Products].[Component]) LOOKUP ORDERED FORWARD) 
     |--Nested Loops(Left Anti Semi Join, OUTER REFERENCES:([CloudDb].[dbo].[Products].[Component])) 
      |--Sort(DISTINCT ORDER BY:([CloudDb].[dbo].[Products].[Component] ASC)) 
      | |--Compute Scalar(DEFINE:([Expr1014]='Car2')) 
      |   |--Nested Loops(Inner Join, OUTER REFERENCES:([Bmk1010])) 
      |    |--Index Seek(OBJECT:([CloudDb].[dbo].[Products].[idxProducts]), SEEK:([CloudDb].[dbo].[Products].[Parent]='Car1') ORDERED FORWARD) 
      |    |--RID Lookup(OBJECT:([CloudDb].[dbo].[Products]), SEEK:([Bmk1010]=[Bmk1010]) LOOKUP ORDERED FORWARD) 
      |--Top(TOP EXPRESSION:((1))) 
       |--Nested Loops(Inner Join, OUTER REFERENCES:([Bmk1015])) 
         |--Index Seek(OBJECT:([CloudDb].[dbo].[Products].[idxProducts]), SEEK:([CloudDb].[dbo].[Products].[Parent]='Car2') ORDERED FORWARD) 
         |--RID Lookup(OBJECT:([CloudDb].[dbo].[Products]), SEEK:([Bmk1015]=[Bmk1015]), WHERE:([CloudDb].[dbo].[Products].[Component]=[CloudDb].[dbo].[Products].[Component]) LOOKUP ORDERED FORWARD) 

一個稍微詳細查詢可以,有時,導致一個簡單的執行計劃。

+0

注意這仍然需要測試一個產品的非常大的集合組件,它可能的哈希匹配會奮鬥,我不知道沒有測試過 – 2010-06-02 11:56:08