我正在尝试编写一个查询,告诉我哪些订单有有效的promocodes。 Promocodes仅在特定日期和可选某些软件包之间有效。
我甚至无法解释它是如何工作的(请参阅下面的psudo-ish代码),但基本上如果有与promocode相关联的包,那么订单必须包含其中一个包并且在有效的日期范围内,否则它只需要处于有效的日期范围内。
整个“如果PrmoPackage行存在”的事情真的让我失望了,我觉得我应该能够在没有一大堆Union
的情况下做到这一点。 (我甚至不确定在这一点上是否会让它更容易......)
有人对查询有任何想法吗?
if `OrderPromoCode` = `PromoCode`
then if `OrderTimestamp` is between `PromoStartTimestamp` and `PromoEndTimestamp`
then if `PromoCode` has packages associated with it
//yes
then if `PackageID` is one of the specified packages
//yes
code is valid
//no
invalid
//no
code is valid
订单:
OrderID* | OrderTimestamp | PackageID | OrderPromoCode
1 | 1/2/11 | 1 | ABC
2 | 1/3/11 | 2 | ABC
3 | 3/2/11 | 2 | DEF
4 | 4/2/11 | 3 | GHI
促销:
PromoCode* | PromoStartTimestamp* | PromoEndTimestamp*
ABC | 1/1/11 | 2/1/11
ABC | 3/1/11 | 4/1/11
DEF | 1/1/11 | 1/11/13
GHI | 1/1/11 | 1/11/13
PromoPackage:
PromoCode* | PromoStartTimestamp* | PromoEndTimestamp* | PackageID*
ABC | 1/1/11 | 2/1/11 | 1
ABC | 1/1/11 | 2/1/11 | 3
GHI | 1/1/11 | 1/11/13 | 1
期望的结果:
OrderID | IsPromoCodeValid
1 | 1
2 | 0
3 | 1
4 | 0
答案 0 :(得分:3)
Agh ....我认为有几种方法可以做到:
使用一些左外连接,一组by和一个case语句,这是一个有点混乱的方法
SELECT [Order].OrderID, CASE count(isnull(Promo.PromoCode, PromoPackage.PromoCode)) WHEN 0 THEN 0 ELSE 1 END
FROM [Order]
LEFT OUTER JOIN Promo ON
Promo.PromoCode = [Order].OrderPromoCode
AND [Order].OrderTimestamp BETWEEN Promo.PromoStartTimestamp and Promo.PromoEndTimestamp
AND NOT EXISTS (SELECT 1 FROM PromoPackage WHERE PromoPackage.PromoCode = Promo.PromoCode)
LEFT OUTER JOIN PromoPackage ON
PromoPackage.PromoCode = [Order].OrderPromoCode
AND PromoPackage.PackageID = [Order].PackageID
AND [Order].OrderTimestamp BETWEEN PromoPackage.PromoStartTimestamp and PromoPackage.PromoEndTimestamp
GROUP BY
[Order].OrderID
您可以使用CTE以更干净的方式执行此操作。
编辑:使用CTE更新了查询
WITH OrderPromo (OrderID, PromoCode, PackageID)
AS
(
SELECT [Order].OrderID, Promo.PromoCode, null
FROM [Order]
INNER JOIN Promo ON
[Order].OrderPromoCode = Promo.PromoCode
AND [Order].OrderTimestamp BETWEEN Promo.PromoStartTimestamp AND Promo.PromoEndTimestamp
AND NOT EXISTS (SELECT 1 FROM PromoPackage WHERE PromoPackage.PromoCode = Promo.PromoCode)
UNION ALL
SELECT [Order].OrderID, PromoPackage.PromoCode, PromoPackage.PackageID
FROM [Order]
INNER JOIN PromoPackage ON
[Order].OrderPromoCode = PromoPackage.PromoCode
AND [Order].PackageID = PromoPackage.PackageID
AND [Order].OrderTimestamp BETWEEN PromoPackage.PromoStartTimestamp AND PromoPackage.PromoEndTimestamp
)
SELECT [Order].OrderID, 1
FROM [Order]
WHERE
EXISTS (SELECT 1 FROM OrderPromo WHERE OrderPromo.OrderID = [Order].OrderID)
UNION ALL
SELECT [Order].OrderID, 0
FROM [Order]
WHERE
NOT EXISTS (SELECT 1 FROM OrderPromo WHERE OrderPromo.OrderID = [Order].OrderID)
;
编辑:还有一个解决方案。这个通过组合Promo和PromoPackage表创建一个“促销”表。没有相关PromoPackage记录的促销记录有效地将PackageID设为null。
SELECT
[Order].OrderID,
CASE count(Promotion.PromoCode) WHEN 0 THEN 0 ELSE 1 END
FROM [Order]
LEFT OUTER JOIN (
SELECT
Promo.PromoCode,
PromoPackage.PackageID,
isnull(PromoPackage.PromoStartTimestamp, Promo.PromoStartTimestamp) as PromoStartTimestamp,
isnull(PromoPackage.PromoEndTimestamp, Promo.PromoEndTimestamp) as PromoEndTimestamp
FROM Promo
LEFT OUTER JOIN PromoPackage ON
Promo.PromoCode = PromoPackage.PromoCode
) Promotion ON
Promotion.PromoCode = [Order].OrderPromoCode
AND (Promotion.PackageID is null OR Promotion.PackageID = [Order].PackageID)
AND [Order].OrderTimestamp BETWEEN Promotion.PromoStartTimestamp AND Promotion.PromoEndTimestamp
GROUP BY
[Order].OrderID
答案 1 :(得分:3)
;WITH PromoCTE AS
( SELECT promo.*, CASE WHEN p.PromoCode IS NULL THEN 0 ELSE 1 END [HasPackage]
FROM Promo
LEFT JOIN
( SELECT DISTINCT PromoCode
FROM PromoPackage
) p
ON promo.PromoCode = p.PromoCode
)
SELECT [Order].OrderID,
CASE WHEN COUNT(CASE WHEN HasPackage = 1 THEN PromoPackage.PromoCode ELSE Promo.PromoCode END) >= 1 THEN 1 ELSE 0 END [IsPromoCodeValid]
FROM [Order]
LEFT JOIN PromoCTE promo
ON Promo.PromoCode = [Order].OrderPromoCode
AND [Order].OrderTimeStamp BETWEEN Promo.PromoStartTimestamp AND Promo.PromoEndTimestamp
LEFT JOIN PromoPackage
ON PromoPackage.PromoCode = OrderPromoCode
AND PromoPackage.PackageID = [Order].PackageID
AND [Order].OrderTimeStamp BETWEEN PromoPackage.PromoStartTimestamp AND PromoPackage.PromoEndTimestamp
GROUP BY [Order].OrderID;
非CTE版本
SELECT [Order].OrderID,
CASE WHEN COUNT(CASE WHEN HasPackage = 1 THEN PromoPackage.PromoCode ELSE Promo.PromoCode END) >= 1 THEN 1 ELSE 0 END [IsPromoCodeValid]
FROM [Order]
LEFT JOIN
( SELECT promo.*, CASE WHEN p.PromoCode IS NULL THEN 0 ELSE 1 END [HasPackage]
FROM Promo
LEFT JOIN
( SELECT DISTINCT PromoCode
FROM PromoPackage
) p
ON promo.PromoCode = p.PromoCode
) promo
ON Promo.PromoCode = [Order].OrderPromoCode
AND [Order].OrderTimeStamp BETWEEN Promo.PromoStartTimestamp AND Promo.PromoEndTimestamp
LEFT JOIN PromoPackage
ON PromoPackage.PromoCode = OrderPromoCode
AND PromoPackage.PackageID = [Order].PackageID
AND [Order].OrderTimeStamp BETWEEN PromoPackage.PromoStartTimestamp AND PromoPackage.PromoEndTimestamp
GROUP BY [Order].OrderID;
答案 2 :(得分:0)
您可以通过相关子查询来完成此操作。我没有测试过,但是:
SELECT
a.OrderID,
CASE WHEN 0 <= (
SELECT COUNT(*)
FROM PromoCode x
JOIN PromoPackage y
ON y.PromoCode = x.PromoCOde
AND a.OrderTimeStamp BETWEEN y.PromoSTartTimestamp AND y.PromoEndTimestamp
WHERE
x.PromoCode = a.OrderPromoCode
) THEN 0
ELSE 1
END AS 'IsPromoCodeValid'
FROM
Order a
答案 3 :(得分:0)
我没有尝试重新创建表格,但此查询应该接近
SELECT o.OrderID, case ISNULL(pck.PackageID, 0) when 0 then 0 else 1 end as IsPromoCodeValid
FROM [Order] as o
LEFT OUTER JOIN [Promo] as p ON
o.OrderPromoCode = p.PromoCode AND o.OrderTimestamp >= p.PromoStartTimestamp AND o.OrderTimestamp <= p.PromoStartTimestamp
LEFT OUTER JOIN [PromoPackage] pck ON o.PackageID = pck.PackageID AND p.PromoCode = pck.PromoCode
答案 4 :(得分:-1)
这样的事可能有用(未经测试):
select o.OrderID,
isPromoCodeValid =
isnull((select 1 from Promo p where o.OrderTimestamp >= p.PromoStartTimestamp and o.OrderTimestamp <= p.PromoEndTimestamp), 0)
or isnull((select 1 from PromoPackage pp where o.OrderTimestamp >= pp.PromoStartTimestamp and o.OrderTimestamp <= pp.PromoEndTimestamp and o.PackageID = pp.PackageID), 0)
from orders o