我有一个我似乎无法解决的SQL语句......我不确定如何在我的连接上执行“OR”。事实上,我不确定我是否应该加入一个联盟...这是我到目前为止所拥有的:
SELECT o.* FROM dbo.Orders o
INNER JOIN dbo.Transactions t1 ON t1.OrderId = o.OrderId
AND t1.Code = 'TX33'
INNER JOIN dbo.Transactions t2 ON t2.OrderId = o.OrderId
AND t2.Code = 'TX34'
WHERE o.PurchaseDate NOT NULL
我还没有运行这个,但我认为这将使我获得所有购买日期也同时包含TX33和TX34交易的订单。没有这两个交易的任何订单都不会显示(由于INNER JOINs)。我坚持的部分是:
我还需要确保订单还包含:
只有其中一个附加条件是必要的。我知道我不能简单地INNER JOIN,因为这意味着它必须在那里。如果我做一个常规JOIN,我可能会使它工作,如果其中一个'OR'条件本身不是'AND'条件(我不知道如何TX35 AND TX36
作为一个JOIN条件,也不{ {1}}。
答案 0 :(得分:3)
选择逻辑需要在WHERE
子句中。也许是这样的:
SELECT o.* FROM dbo.Orders AS o, dbo.Transactions AS t1, dbo.Transactions AS t2
WHERE t1.OrderId = o.OrderId AND t2.OrderId = o.OrderId
AND o.PurchaseDate NOT NULL
AND (
(t1.Code = 'TX33' AND t2.Code = 'TX34') OR
(t1.Code = 'TX35' AND t2.Code = 'TX36') OR
(t1.Code = 'TX37') OR
(t1.Code = 'TX38' AND t2.Code = 'TX39')
)
如果您需要四个独立的选择标准,则需要JOIN
表四次,例如:
SELECT o.* FROM dbo.Orders AS o, dbo.Transactions AS t1, dbo.Transactions AS t2
WHERE t1.OrderId = o.OrderId AND t2.OrderId = o.OrderId
AND t3.OrderId = o.OrderId AND t4.OrderId = o.OrderId
AND o.PurchaseDate NOT NULL
AND (t1.Code = 'TX33' AND t2.Code = 'TX34')
AND (
(t3.Code = 'TX35' AND t4.Code = 'TX36') OR
(t3.Code = 'TX37') OR
(t3.Code = 'TX38' AND t4.Code = 'TX39')
)
答案 1 :(得分:2)
您可以在ON
子句中使用复杂条件。使用LEFT OUTER JOIN
可以处理WHERE
子句中的奇数情况(TX37)。
请注意,R
子句中对WHERE
的引用必须处理NULL,以避免将外连接转换为内连接。
select L.*
from dbo.Orders as L left outer join
dbo.Orders as R on R.OrderId = L.OrderId and (
( L.Code = 'TX33' and R.Code = 'TX34' ) or
( L.Code = 'TX35' and R.Code = 'TX36' ) or
( L.Code = 'TX38' and R.Code = 'TX39' ) )
where L.PurchaseDate is not NULL and ( L.Code = 'TX37' or R.Code is not NULL )
如果您真的只想要包含TX33,TX34 和的一个或多个其他模式的订单,那么它会稍微复杂一些。将group by L.OrderId
与count( L.OrderId )
一起使用可以查找在模式中有两个或更多匹配的订单。它开始接近这样的事情:
declare @Orders as Table ( Id Int Identity, OrderId Int, Code VarChar(4), PurchaseDate Date )
insert into @Orders ( OrderId, Code, PurchaseDate ) values
( 1, 'TX37', GetDate() ),
( 2, 'TX37', GetDate() ), ( 2, 'FOO', GetDate() ),
( 3, 'TX33', GetDate() ), ( 3, 'TX34', GetDate() ),
( 4, 'TX33', GetDate() ), ( 4, 'TX34', GetDate() ), ( 4, 'TX37', GetDate() ),
( 5, 'TX33', GetDate() ), ( 5, 'TX34', GetDate() ), ( 5, 'TX35', GetDate() ),
( 5, 'TX36', GetDate() ),
( 6, 'TX33', GetDate() ), ( 6, 'TX34', GetDate() ), ( 6, 'TX35', GetDate() ),
( 6, 'TX36', GetDate() ), ( 6, 'TX37', GetDate() ),
( 7, 'TX38', GetDate() ), ( 7, 'TX39', GetDate() ), ( 7, 'TX35', GetDate() ),
( 7, 'TX36', GetDate() ), ( 7, 'TX37', GetDate() )
select * from (
select L.OrderId,
Max( case when L.Code = 'TX33' and R.Code = 'TX34' then 1 else 0 end ) as Mandatory,
Count( L.OrderId ) as Matches
from @Orders as L left outer join
@Orders as R on R.OrderId = L.OrderId and (
( L.Code = 'TX33' and R.Code = 'TX34' ) or
( L.Code = 'TX35' and R.Code = 'TX36' ) or
( L.Code = 'TX38' and R.Code = 'TX39' ) )
where L.PurchaseDate is not NULL and ( L.Code = 'TX37' or R.Code is not NULL )
group by L.OrderId ) as Arnold
where Mandatory = 1 and Matches > 1
答案 2 :(得分:2)
SELECT o.*
FROM dbo.Orders o
WHERE EXISTS ( SELECT * FROM dbo.Transactions t1
WHERE t1.OrderId = o.OrderId AND t1.Code = 'TX33'
)
AND EXISTS ( SELECT * FROM dbo.Transactions t2
WHERE t2.OrderId = o.OrderId AND t2.Code = 'TX34'
)
AND
( EXISTS ( SELECT * FROM dbo.Transactions t1
WHERE t1.OrderId = o.OrderId AND t1.Code = 'TX35'
)
AND EXISTS ( SELECT * FROM dbo.Transactions t2
WHERE t2.OrderId = o.OrderId AND t2.Code = 'TX36'
OR EXISTS ( SELECT * FROM dbo.Transactions t
WHERE t.OrderId = o.OrderId AND t.Code = 'TX37'
)
OR EXISTS ( SELECT * FROM dbo.Transactions t1
WHERE t1.OrderId = o.OrderId AND t1.Code = 'TX38'
)
AND EXISTS ( SELECT * FROM dbo.Transactions t2
WHERE t2.OrderId = o.OrderId AND t2.Code = 'TX39'
)
) ;
您也可以这样写:
SELECT o.*
FROM dbo.Orders o
JOIN
( SELECT OrderId
FROM dbo.Transactions
WHERE Code IN ('TX33', 'TX34', 'TX35', 'TX36', 'TX37', 'TX38', 'TX39')
GROUP BY OrderId
HAVING COUNT(DISTINCT CASE WHEN Code = 'TX33' THEN Code END) = 1
AND COUNT(DISTINCT CASE WHEN Code = 'TX34' THEN Code END) = 1
AND ( COUNT(DISTINCT
CASE WHEN Code IN ('TX35', 'TX36') THEN Code END) = 2
OR COUNT(DISTINCT CASE WHEN Code = 'TX37' THEN Code END) = 1
OR COUNT(DISTINCT
CASE WHEN Code IN ('TX38', 'TX39') THEN Code END) = 2
)
) t
ON t.OrderId = o.OrderId ;
答案 3 :(得分:-1)
在摆弄了一段时间之后,我想我已经通过以下查询实现了您的目标:
SELECT * FROM (
SELECT o.*, t3.Code as t3 FROM dbo.Orders o
INNER JOIN dbo.Transactions t1 ON t1.OrderId = o.OrderId
AND t1.Code = 'TX33'
INNER JOIN dbo.Transactions t2 ON t2.OrderId = o.OrderId
AND t2.Code = 'TX34'
INNER JOIN dbo.Transactions t3 ON t3.OrderId = o.OrderId
AND (
t3.Code = 'TX35' OR
t3.Code = 'TX37' OR
t3.Code = 'TX38'
)
) WHERE t3 = 'TX37'
OR (t3 = 'TX36' AND EXISTS (SELECT t.Code FROM dbo.Transactions t WHERE t.OrderId = o.OrderId AND t.Code = 'TX36'))
OR (t3 = 'TX38' AND EXISTS (SELECT t.Code FROM dbo.Transactions t WHERE t.OrderId = o.OrderId AND t.Code = 'TX39'))
内部SELECT
应仅返回链接到具有代码TX34,TX35以及TX35,TX37或TX38的交易的订单。我们在结果中保留了最后一个代码的副本。
然后我们必须进一步缩小列表范围,保留其第三个代码为TX37(无需其他条件)的订单或具有与之相关的剩余代码的订单。
我认为这种方法应该比在事务表中加入四次而不首先过滤它更好:它应该需要O*(T+T+T)*(T+T) = 6*O*T^2
次迭代,而四次未过滤连接方法需要O*T*T*T*T = O*T^4
次迭代。