1

Set - based Speed Phreakery : The FIFO Stock Inventory SQL Problem: ( https://www.simple-talk.com/sql /performance/set-based-speed-phreakery-the-fifo-stock-inventory-sql-problem/ )。

SQL Server から Teradata SQL に適応させようとしてきましたが、次のことがわかりました。

(a) Teradata は 1 つの CTE with ステートメントのみを処理できます

(b) クロスアプライは使用できません

(c) ヒント索引を使用できないのですか?

私の質問は次のとおりです。

上記の(a)を回避するためのTeradata(揮発性テーブル以外)の代替手段はありますか?

Terdata の「Cross Join」は、SQL Server の Cross Apply と同じですか?

このスクリプトを Teradata に適応させた人はいますか?

4

2 に答える 2

0

あなたの投稿は数か月前のものですが、他の人にも役立つかもしれません.

数年前に Teradata に移植したことを思い出したとき、Teradata の Developer Exchange に同様の質問がありました。他のソリューションをすばやく検索したところ、この投稿にたどり着きました。

Teradata が ROWS UNBOUNDED PRECEDING をサポートしているため、はるかに単純であることが判明しました (Microsoft は SS2012 で追加しました)。

ご質問について:

a: CTE は派生テーブルに置き換えることができます。これは単なる構文のバリエーションです。

b: CROSS/OUTER APPLY は SQL Server 独自の構文であり、[OUTER] JOIN に置き換えることができます。この場合、累積和を計算する複雑な方法でした。

c: オプティマイザーが適切な計画を実行していない場合は、インデックス ヒントを最後の手段にする必要があります。

SELECT
   ArticleId
  ,SUM(ItemCnt) AS CurrentItems -- same as TotalStock
  ,SUM(ItemCnt * CurrentPrice) AS CurrentValue
FROM
 (
   SELECT
      ArticleId

     -- how many items will be used from this transaction, maybe less than all for the oldest row
     ,CASE WHEN RollingStock + Items > TotalStock THEN TotalStock - RollingStock ELSE Items END AS ItemCnt

     -- find the latest IN-price for RET rows
     ,MAX(Price)
      OVER (PARTITION BY ArticleID, PriceGroup
            ORDER BY TranDate) AS CurrentPrice
   FROM
    (
      SELECT
         ArticleId ,TranDate ,Price ,Items --,TranCode

        -- dummy column to get the current price in the next step, new group starts with every 'IN'
        ,SUM(CASE WHEN TranCode = 'IN' THEN 1 ELSE 0 END)
         OVER (PARTITION BY ArticleID
               ORDER BY TranDate
               ROWS UNBOUNDED PRECEDING) AS PriceGroup

        -- Aggregating all in/out movements -> number of items left in stock after all transactions
        ,SUM(CASE WHEN TranCode IN ('IN', 'RET') THEN Items ELSE -Items END)
         OVER (PARTITION BY ArticleID) AS TotalStock

        -- reverse sum of all inbound IN/RET movements
        ,SUM(CASE WHEN TranCode IN ('IN', 'RET') THEN Items END)
         OVER (PARTITION BY ArticleID)
        -SUM(CASE WHEN TranCode IN ('IN', 'RET') THEN Items END)
         OVER (PARTITION BY ArticleID
               ORDER BY TranDate
               ROWS UNBOUNDED PRECEDING) AS RollingStock
/*
        -- same as above, simpler syntax, but different ORDER BY results in extra STATS step in explain
        ,COALESCE(SUM(CASE WHEN TranCode IN ('IN', 'RET') THEN Items END)
         OVER (PARTITION BY ArticleID
               ORDER BY TranDate DESC
               ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING),0) AS RollingStock
*/
/*      -- cumulative sum, not needed to get the result
        ,SUM(CASE WHEN TranCode IN ('IN', 'RET') THEN Items ELSE -Items END)
         OVER (PARTITION BY ArticleID
               ORDER BY TranDate
               ROWS UNBOUNDED PRECEDING) AS CurrentItems
*/
      FROM Stock
      -- only keep the row needed to calculate the value
      -- plus all IN rows to find the current price for RET rows in the next step
      -- to exclude items out of stock: add "AND (TotalStock > 0)"
      QUALIFY ((TranCode = 'IN') OR (RollingStock <= TotalStock AND TranCode = 'RET'))AND (TotalStock > 0)
    ) AS dt
   -- remove older IN rows
   QUALIFY ItemCnt >= 0
 ) AS dt
GROUP BY 1
ORDER BY 1

ここで説明されている優勝ソリューションと同じロジックに基づいています: https://www.simple-talk.com/sql/performance/set-based-speed-phreakery-the-fifo-stock-inventory-sql-problem/

これは非常に高速に実行され、SQL Server に必要なインデックスを作成する必要はありません :-)

他の DBMS への移植に関する注意事項:

これは単純な標準 SQL であり、QUALIFY のみが Teradata 固有です。QUALIFY は GROUP BY の HAVING と同じで、OLAP 関数の結果をフィルタリングします。条件を外部レベルの WHERE に移動することで簡単に置き換えることができます。

于 2013-09-15T11:19:24.160 に答える