5

我正在尝试编写一个查询来告诉我哪些订单具有有效的促销代码。促销代码仅在特定日期和可选的特定套餐之间有效。

我什至无法解释这是如何工作的(请参阅下面的伪代码),但基本上如果有与促销代码相关联的包,那么订单必须具有这些包之一并且在有效的日期范围内,否则它只需要在有效的日期范围内。

整个“如果 PrmoPackage 行存在”的事情真的让我失望,我觉得我应该能够在没有一大堆Unions 的情况下做到这一点。(我什至不确定这是否会让它更容易......)

有人对查询有任何想法吗?

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

促销包:

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
4

5 回答 5

3

啊....我认为有几种方法可以做到:

这是一个有点混乱的方法,它使用了几个左外连接、一个 group 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 表来创建一个“Promotion”表。没有关联 PromoPackage 记录的促销记录实际上具有 null 的 PackageID。

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
于 2012-04-04T20:26:44.980 回答
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;
于 2012-04-04T20:27:12.843 回答
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     
于 2012-04-04T20:24:16.793 回答
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
于 2012-04-04T20:26:13.063 回答
-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
于 2012-04-04T20:22:25.687 回答