TSQL GROUP BY在递归CTE中

时间:2012-12-19 16:05:03

标签: sql-server tsql common-table-expression

是否有解决方法在循环CTE中使用GROUP BY或有解决方法?

我需要对CTE表的结果集进行分组,并在具有相同CTE的另一个循环中使用它,但是我得到以下错误:

  

不允许使用GROUP BY,HAVING或聚合函数   递归公用表表达式'cte'的递归部分。

以下是查询:

WITH cte
    AS
    (
        SELECT
          id,
          dailyconsumption,
          stock/dailyconsumption as cutoff
        FROM items
        WHERE father IS NULL


        UNION ALL

        SELECT
          i.id,
          SUM(father.dailyconsumption*i.num),
          MAX(stock)/SUM(father.dailyconsumption*i.num)
        FROM cte father
        JOIN items i ON father.id=i.father
        group by i.id
    )

SELECT id, MIN(cutoff)
FROM cte
GROUP BY id

SQL-Fiddle(带样本数据)


编辑......这是逻辑问题

我有一组最终用户项(father = NULL)和其他一些子项(由字段父和字段num填充)。 我得到了最终用户项目的日常消费(我用“WHERE父IS NULL”开始我的cte),子项的dailyconsumption由SUM(father.dailyconsumption * item.num)计算。

WITH cte AS(
    SELECT
      id,
      dailyconsumption,
      stock/dailyconsumption as cutoff
    FROM items
    WHERE father IS NULL


    UNION ALL

    SELECT
      i.id,
      father.dailyconsumption*i.num
      0
    FROM cte father
    JOIN items i ON father.id=i.father
)

SELECT id, SUM(dailyconsumption)
FROM cte
GROUP BY id

http://sqlfiddle.com/#!3/f4f2a/95

使用此有效查询,我将为所有项目(最终用户和子项目)填充所有dailyconsumption。请注意,父子关系可以超过1级。

现在我需要计算截止值(我的库存需要多少天)。 对于最终用途,它非常容易并且已经在第一次CTE中计算出来: stock / dailyconsumption 。 对于子项,它有点复杂: subitem.stock / subitem.dailyconsumption + MIN(father.cutoff) 其中MIN(father.cutoff)是本子项目所有父亲的最小截止点。 这是因为我需要另一个小组。

我是否需要另一个CTE来循环同一个父子关系?

感谢您的关注,对不起我的英语。

2 个答案:

答案 0 :(得分:5)

;WITH cte AS
 (
  SELECT id, father, 
         dailyconsumption,
         (stock / dailyconsumption) AS cutoff,
         0 AS [Level] 
  FROM items
  WHERE father IS NULL
  UNION ALL
  SELECT i.id, i.father, 
         c.dailyconsumption * i.num,
         i.stock / (c.dailyconsumption * i.num),
         [Level] + 1
  FROM cte c JOIN items i ON c.id = i.father
  )
  SELECT c.id, c.dailyconsumption, c.cutoff AS subItemsCutoff, 
         MIN(ct.cutoff) OVER(PARTITION BY ct.[Level]) AS fatherCutoff,
         (c.cutoff  + ISNULL(MIN(ct.cutoff) OVER(PARTITION BY ct.[Level]), 0)) AS Cutoff
  FROM cte c LEFT JOIN cte ct ON c.father = ct.id

SQLFiddle上的演示

答案 1 :(得分:0)

我建议使用变量表。声明表,然后将这些记录插入其中。您需要找到一种方法在第二次插入命令时循环它。我得到了这个让你入门:

DECLARE @staging TABLE
(
    id                  INT
    ,dailyconsumption   FLOAT
    ,cutoff             FLOAT
)

INSERT INTO @staging
    SELECT
      id,
      dailyconsumption,
      stock/dailyconsumption as cutoff
    FROM 
      items
    WHERE 
      father IS NULL

INSERT INTO @staging
  SELECT
      i.id,
      SUM(father.dailyconsumption*i.num),
      MAX(stock)/SUM(father.dailyconsumption*i.num)
    FROM 
      @staging father

        JOIN items i 
        ON father.id=i.father
    group by 
      i.id

SELECT 
  id
 ,MIN(cutoff)
FROM 
  @staging
GROUP BY 
  id