在CTE中使用max递归生成CTE,而不是仅在最终的SELECT语句中使用

时间:2019-04-13 22:06:54

标签: sql sql-server tsql

我想在预定的开始日期和结束日期之间产生一列日期,并将结果存储在CTE中以在查询中使用。下面的递归方法确实有效,但是似乎无法在CTE中使用maxrecursion。还有其他解决方法吗?

(1)可以正常工作:

function f(S, T, K){
  // mapS maps a char to indexes of its occurrences in S
  // rsS maps the index in S to that char's rank (index) in mapS
  const [mapS, rsS] = mapString(S)
  const [mapT, rsT] = mapString(T)
  // h is used to memoize g
  const h = {}

  function g(c, rs, rt){
    if (rs < 0 || rt < 0)
      return 0
    
    if (h.hasOwnProperty([c, rs, rt]))
      return h[[c, rs, rt]]
      
    // (We are guaranteed to be on
    // a match in this state.)
    let best = [1, c]
    
    let idxS = mapS[c][rs]
    let idxT = mapT[c][rt]

    if (idxS == 0 || idxT == 0)
      return best

    for (let i=idxS-1; i>=Math.max(0, idxS - 1 - K); i--){
      for (let j=idxT-1; j>=Math.max(0, idxT - 1 - K); j--){
        if (S[i] == T[j]){
          const [len, str] = g(S[i], rsS[i], rsT[j])

          if (len + 1 >= best[0])
            best = [len + 1, str + c]
        }
      }
    }
  
    return h[[c, rs, rt]] = best
  }

  let best = [0, '']
  
  for (let c of Object.keys(mapS)){
    for (let i=0; i<(mapS[c]||[]).length; i++){
      for (let j=0; j<(mapT[c]||[]).length; j++){
        let [len, str] = g(c, i, j)
        
        if (len > best[0])
          best = [len, str]
      }
    }
  }
  
  return best
}

function mapString(s){
  let map = {}
  let rs = []
  
  for (let i=0; i<s.length; i++){
    if (!map[s[i]]){
      map[s[i]] = [i]
      rs.push(0)
    
    } else {
      map[s[i]].push(i)
      rs.push(map[s[i]].length - 1)
    }
  }
  
  return [map, rs]
}

console.log(f('attgcgtagcaatg', 'tctcaggtcgatagtgac', 1))

console.log(f('aaaattttcccc', 'cccgggggaatatca', 1))

console.log(f('abcade', 'axe', 1))

(2)无效:

DECLARE @startnum INT=1
DECLARE @endnum INT=10000
;
WITH gen AS (       
    SELECT @startnum AS num
    UNION ALL
    SELECT num+1 FROM gen WHERE num+1<=@endnum
)

SELECT * FROM gen
option (maxrecursion 10000)

2 个答案:

答案 0 :(得分:3)

使用Tally,而不是使用RBAR rCTE。您也可以使用CTE执行此操作。这样就不会遇到最大递归问题,而且速度更快:

WITH N AS (
    SELECT N
    FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL)) N(N)),
Tally AS(
    SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS I
    FROM N N1 --10
         CROSS JOIN N N2 --100
         CROSS JOIN N N3 --1000
         CROSS JOIN N N4 --10000
    )
SELECT *
FROM Tally;

在上述示例中,您可以在CTE计数中继续向CROSS JOIN进行N的操作,并将行数增加10的倍数。

答案 1 :(得分:2)

您在最终选择的末尾添加了maxrecursion选项。该选项适用于所有CTE。

将整个事情视为一个单独的陈述。

我知道这似乎违反直觉。我第一次遇到这个问题时感到困惑。