在SQL Server 2005中,我有一个订单详细信息表,其中包含订单ID和产品ID。我想编写一个sql语句,查找包含特定订单中所有项目的所有订单。所以,如果订单5有第1,2和3项,我会希望所有其他订单也有1,2和3.另外,如果订单5有2次和3次,我想要所有其他订单两个2s和一个3。
我的偏好是它会返回完全匹配的订单,但如果更容易/执行得更好,那么作为超集的订单是可以接受的。
我尝试了如下所示的自我加入,但是发现了任何项目的订单,而不是所有项目。
SELECT * FROM Order O1
JOIN Order O2 ON (O1.ProductId = O2.ProductId)
WHERE O2.OrderId = 5
如果订单5包含两次相同的商品,这也给了我重复。
答案 0 :(得分:3)
如果OrderDetails表包含OrderId和ProductId的唯一约束,那么您可以执行以下操作:
Select ...
From Orders As O
Where Exists (
Select 1
From OrderDetails As OD1
Where OD1.ProductId In(1,2,3)
And OD1.OrderId = O.Id
Group By OD1.OrderId
Having Count(*) = 3
)
如果可以多次在同一个Order上使用相同的ProductId,那么您可以将Having子句更改为Count(Distinct ProductId) = 3
现在,鉴于上述情况,如果您想要每个订单具有相同签名并且具有重复产品条目的情况,那就更棘手了。要做到这一点,您需要对相关产品的相关订单签名,然后查询该签名:
With OrderSignatures As
(
Select O1.Id
, (
Select '|' + Cast(OD1.ProductId As varchar(10))
From OrderDetails As OD1
Where OD1.OrderId = O1.Id
Order By OD1.ProductId
For Xml Path('')
) As Signature
From Orders As O1
)
Select ...
From OrderSignatures As O
Join OrderSignatures As O2
On O2.Signature = O.Signature
And O2.Id <> O.Id
Where O.Id = 5
答案 1 :(得分:1)
这种事情在SQL中很难做到,因为SQL旨在通过在最基本的级别上将每行的一组列值与另一个值进行比较来生成其结果集。您要做的是将多行上的单个列值(或列值集)与另一组多行进行比较。
为了做到这一点,你必须创建某种订单签名。严格地说,单独使用查询语法是不可能的;你必须使用一些T-SQL。
declare @Orders table
(
idx int identity(1, 1),
OrderID int,
Signature varchar(MAX)
)
declare @Items table
(
idx int identity(1, 1),
ItemID int,
Quantity int
)
insert into @Orders (OrderID) select OrderID from [Order]
declare @i int
declare @cnt int
declare @j int
declare @cnt2 int
select @i = 0, @cnt = max(idx) from @Orders
while @i < @cnt
begin
select @i = @i + 1
declare @temp varchar(MAX)
delete @Items
insert into @Items (ItemID, Quantity)
select
ItemID,
Count(ItemID)
from OrderItem oi
join @Orders o on o.idx = @i and o.OrderID = oi.OrderID
group by oi.ItemID
order by oi.ItemID
select @j = min(idx) - 1, @cnt2 = max(idx) from @Items
while @j < @cnt2
begin
select @j = @j + 1
select @temp = isnull(@temp + ', ','') +
'(' +
convert(varchar,i.ItemID) +
',' +
convert(varchar, i.Quantity) +
')'
from @Items i where idx = @j
end
update @Orders set Signature = @temp where idx = @i
select @temp = null
end
select
o_other.OrderID
from @Orders o
join @Orders o_other on
o_other.Signature = o.Signature
and o_other.OrderID <> o.OrderID
where o.OrderID = @OrderID
这假定(根据您的问题的措辞)在订单中排序多个相同项目将导致多行,而不是使用Quantity
列。如果是后一种情况,只需从group by
填充查询中删除@Items
,然后将Count(ItemID)
替换为Quantity
。
答案 2 :(得分:1)
我认为这应该有效。我使用108作为OrderID的示例,因此您必须在下面替换两次或使用变量。
WITH TempProducts(ProductID) AS
(
SELECT DISTINCT ProductID FROM CompMarket
WHERE OrderID = 108
)
SELECT OrderID FROM CompMarket
WHERE ProductID IN (SELECT ProductID FROM TempProducts)
AND OrderID != 108
GROUP BY OrderID
HAVING COUNT(DISTINCT ProductID) >= (SELECT COUNT(ProductID) FROM TempProducts)
这使用CTE获取订单产品的列表,然后选择所有产品都在此列表中的订单ID。为了确保返回的订单包含所有产品,这会将CTE的计数与退回的订单产品的计数进行比较。