加入哪些行不存在或哪里标准匹配......?

Gre*_*reg 5 sql sql-server database-design sql-server-2008

我正在尝试编写一个查询,告诉我哪些订单有有效的promocodes.促销代码仅仅是某些日期之间有效的可选某些包.

我甚至无法解释它是如何工作的(参见下面的psudo-ish代码),但基本上如果有与promocode相关联的包,那么订单必须有一个这样的包并且在有效的日期范围内,否则它只需要处于有效的日期范围内.

整个"如果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
Run Code Online (Sandbox Code Playgroud)

订购:

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
Run Code Online (Sandbox Code Playgroud)

促销:

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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

期望的结果:

OrderID | IsPromoCodeValid
1       | 1
2       | 0
3       | 1
4       | 0
Run Code Online (Sandbox Code Playgroud)

Gar*_*thD 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;
Run Code Online (Sandbox Code Playgroud)

非 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;
Run Code Online (Sandbox Code Playgroud)