1

有一个旧堆栈帖子(先进先出 (FIFO) 库存成本计算),其中包含基于集合的 Speed Phreakery:FIFO Stock Inventory SQL 问题:(https://www.simple-talk.com/sql /performance/set-based-speed-phreakery-the-fifo-stock-inventory-sql-problem/)。

我一直在尝试将其从 SQL Server 调整为 Teradata SQL,但发现:

(a) Teradata 只能处理一个 CTE with statement

(b) 您不能使用交叉应用

(c) 不能使用提示索引?

我的问题是:

Teradata 中是否有替代方案(易失性表除外)来绕过上述(a)?

Terdata“交叉连接”是否与 SQL Server 中的交叉应用相同?

有没有人将此脚本改编为 Teradata?

4

2 回答 2

0

您可以使用派生表而不是 CTE

于 2013-06-18T14:06:12.243 回答
0

您的帖子已有几个月的历史,但是这对其他人也可能有用。

Teradata 的 Developer Exchange 上有一个类似的问题,当时我记得几年前我将它移植到了 Teradata。快速搜索其他解决方案将我引导到这篇文章。

由于 Teradata 支持 ROWS UNBOUNDED PRECEDING(微软在 SS2012 中添加了这一点),结果变得更加简单:

关于你的问题:

a: CTE 可以用 Derived Tables 代替,它只是一种语法变化。

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 回答