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)
;

編集:もう1つの解決策。これは、Promo テーブルと PromoPackage テーブルを組み合わせて「Promotion」テーブルを作成します。PromoPackage レコードが関連付けられていない Promo レコードは、実質的に 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 に答える