2011-02-04 67 views
1

在SQL Server中,我有一個來自加入many:many關係的結果集。SQL - 爲一個表中的值標識行,其中所有連接的行只有一個特定的值

考慮通過一個鏈接錶鏈接到訂單的產品,

Table - Products 
ID 
ProductName 

Table - Orders 
ID 
OrderCountry 

LinkTable OrderLines (columns not shown) 

我希望能夠過濾這些結果表明只有在結果,其中從一個表中的實體,所有的值其他表只在特定列中具有給定值。在我的例子來說,對於每一個產品,我想只返回加入行時,他們起來的全部訂單都是國家英國

所以,如果我的鏈接結果集是

productid, product, orderid, ordercountry 
1, Chocolate, 1, uk 
2, Banana, 2, uk 
2, Banana, 3, usa 
3, Strawberry, 4, usa 

我想過濾,以便只顯示那些只在英國訂購的產品(即巧克力)。我確信這應該是直接的,但它的星期五下午和我的大腦的SQL部分已經放棄了一天...

回答

3

你可以做這樣的事情,在這裏首先你得到所有的產品只在一個國家出售,那麼你繼續得到所有訂單爲這些產品

with distinctProducts as 
(
    select LinkTable.ProductID 
    from Orders 
    inner join LinkTable on LinkTable.OrderID = Orders.ID 
    group by LinkTable.ProductID 
    having count(distinct Orders.OrderCountry) = 1 
) 
select pr.ID as ProductID 
     ,pr.ProductName 
     ,o.ID as OrderID 
     ,o.OrderCountry 
from Products pr 
inner join LinkTable lt on lt.ProductID = pr.ID 
inner join Orders o on o.ID = lt.OrderID 
inner join distinctProducts dp on dp.ProductID = pr.ID 
where o.OrderCountry = 'UK' 
0
SELECT pr.Id, pr.ProductName, od.Id, od.OrderCountry 
from Products pr 
    inner join LinkTable lt 
    on lt.ProductId = pr.ID 
    inner join Orders od 
    on od.ID = lt.OrderId 
where od.OrderCountry = 'UK' 
+1

將返回`香蕉',這是不會被退回 – AakashM 2011-02-04 15:04:44

+0

對不起 - 這返回有美國訂單的產品行 - 我需要過濾掉這一行(和其他人喜歡它在我的真實數據集中...) – 2011-02-04 15:12:26

1

嗯。基於飛利浦以前的辦法,嘗試添加像這樣以排除行,其中有許多人在其他國家訂購的相同產品:

SELECT pr.Id, pr.ProductName, od.Id, od.OrderCountry 
    from Products pr 
     inner join LinkTable lt 
     on lt.ProductId = pr.ID 
     inner join Orders od 
     on od.ID = lt.OrderId 
    where 
     od.OrderCountry = 'UK' 
     AND NOT EXISTS 
     (
     SELECT 
      * 
     FROM 
      Products MatchingProducts 
      inner join LinkTable lt 
       on lt.ProductId = MatchingProducts.ID 
      inner join Orders OrdersFromOtherCountries 
       on OrdersFromOtherCountries.ID = lt.OrderId 
     WHERE 
      MatchingProducts.ID = Pr.ID AND 
      OrdersFromOtherCountries.OrderCountry != od.OrderCountry 
    ) 
+0

目前與我的例子中使用表,我得到「消息4104,級別16,狀態1,行1 多部分標識符「Products.ID」無法綁定。「爲最後的where子句。 – 2011-02-04 15:32:28

+1

@Kris呃,是的,我只是想給你提供這個想法。但是,如果這是完全錯誤的,請將Products.ID更改爲pr.ID,因爲這是主查詢中的別名。我會改變答案。 – 2011-02-04 15:58:44

1

在此希望一些這可能是一般可重複使用:

;with startingRS (productid, product, orderid, ordercountry) as (
    select 1, 'Chocolate', 1, 'uk' union all 
    select 2, 'Banana', 2, 'uk' union all 
    select 2, 'Banana', 3, 'usa' union all 
    select 3, 'Strawberry', 4, 'usa' 
), countryRankings as (
select productid,product,orderid,ordercountry, 
    RANK() over (PARTITION by productid ORDER by ordercountry) as FirstCountry, 
    RANK() over (PARTITION by productid ORDER by ordercountry desc) as LastCountry 
from 
    startingRS 
), singleCountry as (
    select productid,product,orderid,ordercountry 
    from countryRankings 
    where FirstCountry = 1 and LastCountry = 1 
) 
select * from singleCountry where ordercountry='uk' 

在startingRS中,您將當前必須提供的任何查詢生成所顯示的中間結果。 countryRankings CTE增加了兩個新列,這些列對每個產品中的國家進行排名。

singleCountry CTE將結果集減少到那些國家作爲產品中第一個也是最後一個國家(即該產品只有一個國家)的結果。最後,我們查詢那些來自英國的結果。

如果你想要的,例如,與原產地的一個國家所有的productid行,你就跳過這最後的where子句(和你會在你的結果也讓3,草莓,4,USA)


所以你有一個當前查詢,看起來像:

select p.productid,p.product,o.orderid,o.ordercountry 
from product p inner join order o on p.productid = o.productid --(or however these joins work for your tables) 

那麼你已經重寫了第一CTE爲:

;with startingRS (productid, product, orderid, ordercountry) as (
    select p.productid,p.product,o.orderid,o.ordercountry 
    from product p inner join order o on p.productid = o.productid 
), /* rest of query */ 
0

這可能不是最有效的方法,但是...

SELECT p.ProductName 
FROM Product p 
WHERE p.ProductId IN 
(
    SELECT DISTINCT ol.ProductId 
    FROM OrderLines ol 
    INNER JOIN [Order] o 
    ON ol.OrderId = o.OrderId 
    WHERE o.OrderCountry = 'uk' 
) 
AND p.ProductId NOT IN 
(
    SELECT DISTINCT ol.ProductId 
    FROM OrderLines ol 
    INNER JOIN [Order] o 
    ON ol.OrderId = o.OrderId 
    WHERE o.OrderCountry != 'uk' 
) 

TESTDATA

create table product 
(
ProductId int, 
ProductName nvarchar(50) 
) 
go 

create table [order] 
(
OrderId int, 
OrderCountry nvarchar(50) 
) 
go 

create table OrderLines 
(
OrderId int, 
ProductId int 
) 
go 


insert into Product VALUES (1, 'Chocolate') 
insert into Product VALUES (2, 'Banana') 
insert into Product VALUES (3, 'Strawberry') 

insert into [order] values (1, 'uk') 
insert into [order] values (2, 'uk') 
insert into [order] values (3, 'usa') 
insert into [order] values (4, 'usa') 

insert into [orderlines] values (1, 1) 
insert into [orderlines] values (2, 2) 

insert into [orderlines] values (3, 2) 
insert into [orderlines] values (4, 3) 

insert into [orderlines] values (3, 2) 
insert into [orderlines] values (3, 3) 
1
;WITH mytable (productid,ordercountry) 
AS 
(SELECT productid, ordercountry 
FROM Orders od INNER JOIN LinkTable lt ON od.orderid = lt.OrderId) 

SELECT * FROM mytable 
INNER JOIN dbo.Products pr ON pr.productid = mytable.productid 
WHERE pr.productid NOT IN (SELECT productid FROM mytable 
          GROUP BY productid 
          HAVING COUNT(ordercountry) > 1) 
AND ordercountry = 'uk' 
相關問題