SQL Server: Как ограничить рекурсию CTE строками просто recursivly добавленный?

Это тот же вопрос, что и Как округлить десятичные знаки после числа 2? . Вам просто нужно внести коррективы в дополнительные десятичные знаки.

Math.floor(1.12346 * 10000) / 10000

console.log(Math.floor(1.12346 * 10000) / 10000);

Если вы хотите использовать эту функцию в качестве многоразовой, вы можете сделать:

[ 1113]
function MathRound (number, digits) {
  var adjust = Math.pow(10, digits); // or 10 ** digits if you don't need to target IE
  return Math.floor(number * adjust) / adjust;
}

console.log(MathRound(1.12346, 4));

12
задан Ian Boyd 18 March 2009 в 05:12
поделиться

6 ответов

Попробуйте это:

WITH Nodes AS
(
   --initialization
   SELECT ParentNodeID, NodeID, 1 AS GenerationsRemoved
   FROM ##Nodes

   UNION ALL

   ----recursive execution
   SELECT P.ParentNodeID, N.NodeID, P.GenerationsRemoved + 1
   FROM Nodes AS P
      INNER JOIN ##Nodes AS N
      ON P.NodeID = N.ParentNodeID
   WHERE P.GenerationsRemoved <= 10

)
SELECT ParentNodeID, NodeID, GenerationsRemoved
FROM Nodes
ORDER BY ParentNodeID, NodeID, GenerationsRemoved

В основном удаление "только показывает мне абсолютных родителей" от запроса инициализации; Тем путем это генерирует результаты, запускающиеся от каждого из них и убывающие оттуда. Я также включил, "ГДЕ P.GenerationsRemoved <= 10" как выгода бесконечной рекурсии (заменяют 10 любым числом до 100 для установки потребностям). Затем добавьте вид, таким образом, он похож на результаты, которые Вы хотели.

19
ответ дан 26 October 2019 в 10:46
поделиться

В стороне: у Вас есть SQL Server 2008? Это могло бы подходить hierarchyid тип данных.

0
ответ дан 26 October 2019 в 10:46
поделиться

Если я понимаю Ваши намерения, можно получить Вас результат путем выполнения чего-то вроде этого:

DECLARE @StartID INT;
SET @StartID = 1;
WITH CTE (ChildNodeID, ParentNodeID, [Level]) AS
(
  SELECT  t1.ChildNodeID, 
          t1.ParentNodeID, 
          0
  FROM tblNodes AS t1
  WHERE ChildNodeID = @StartID
  UNION ALL
  SELECT  t1.ChildNodeID, 
          t1.ParentNodeID, 
          t2.[Level]+1
  FROM tblNodes AS t1
    INNER JOIN CTE AS t2 ON t1.ParentNodeID = t2.ChildNodeID    
)
SELECT t1.ChildNodeID, t2.ChildNodeID, t1.[Level]- t2.[Level] AS GenerationsDiff
FROM CTE AS t1
  CROSS APPLY CTE t2

Это возвратит различие в поколении между всеми узлами, можно изменить его для Вас, требуют потребности.

0
ответ дан 26 October 2019 в 10:46
поделиться

Ну, Ваш ответ не совсем настолько очевиден :-)

WITH (NodeChildren) AS
{
   --initialization
   SELECT ParentNodeID, ChildNodeID, 1 AS GenerationsRemoved
   FROM Nodes

Эту часть называют частью "привязки" рекурсивного CTE - но это должно действительно только выбрать один или выбор немного строк от Вашей таблицы - это выбирает все!

Я предполагаю то, что Вы пропускаете, вот просто подходящий оператор Where:

WITH (NodeChildren) AS
{
   --initialization
   SELECT ParentNodeID, ChildNodeID, 1 AS GenerationsRemoved
   FROM Nodes
   **WHERE ParentNodeID IS NULL**

Однако я боюсь, что Ваше требование, чтобы не иметь просто "прямой" иерархии, но также и дочерних прародителем строк, не могло бы быть настолько легко удовлетворить.... обычно, рекурсивный CTE будет только когда-либо показывать один уровень и его прямых подчиненных (и что вниз иерархия, конечно) - это обычно не пропускает один, два или еще больше уровней.

Надежда это помогает немного.

Marc

0
ответ дан 26 October 2019 в 10:46
поделиться

Проблема с пределом рекурсии значения по умолчанию SQL-сервера (100). Если Вы пробуете свой пример наверху удаленным ограничением привязки (также добавленный Порядок):

WITH NodeChildren AS
(
   --initialization
   SELECT ParentNodeID, NodeID, 1 AS GenerationsRemoved
   FROM Nodes

   UNION ALL

   --recursive execution
   SELECT P.ParentNodeID, N.NodeID, P.GenerationsRemoved + 1
   FROM NodeChildren AS P
      inner JOIN Nodes AS N
      ON P.NodeID = N.ParentNodeID
)
SELECT ParentNodeID, NodeID, GenerationsRemoved
FROM NodeChildren
ORDER BY ParentNodeID ASC

Это приводит к желаемым результатам. Проблема Вы, которые направление Ааре с большим числом строк, Вы будете recirse более чем 100 раз, который является пределом по умолчанию. Это может быть изменено путем добавления option (max recursion x) после Вашего запроса, где x является числом между 1 и 32767. x может также быть установлен на 0, который не устанавливает предела, однако мог очень быстро оказать очень вредное влияние на Вашу производительность сервера. Очевидно как количество строк в увеличениях Узлов, число желания рекурсий может увеличиться очень быстро, и я избежал бы этого подхода, если не был известный верхний предел строк в таблице. Для полноты заключительный запрос должен быть похожим:

 WITH NodeChildren AS
    (
       --initialization
       SELECT ParentNodeID, NodeID, 1 AS GenerationsRemoved
       FROM Nodes

       UNION ALL

       --recursive execution
       SELECT P.ParentNodeID, N.NodeID, P.GenerationsRemoved + 1
       FROM NodeChildren AS P
          inner JOIN Nodes AS N
          ON P.NodeID = N.ParentNodeID
    )
    SELECT * 
    FROM NodeChildren
    ORDER BY ParentNodeID
    OPTION (MAXRECURSION 32767)

Где 32767 мог быть уменьшен для установки сценарию

0
ответ дан 26 October 2019 в 10:46
поделиться

Вы попытались создать путь в CTE и использовать его для идентификации предков?

Можно затем вычесть порожденную глубину узла из глубины узла предка для вычисления столбца GenerationsRemoved, как так...

DECLARE @Nodes TABLE
(
    NodeId varchar(50) PRIMARY KEY NOT NULL,
    ParentNodeId varchar(50) NULL
)

INSERT INTO @Nodes (NodeId, ParentNodeId) VALUES ('A', NULL)
INSERT INTO @Nodes (NodeId, ParentNodeId) VALUES ('B', 'A')
INSERT INTO @Nodes (NodeId, ParentNodeId) VALUES ('C', 'B')

DECLARE @Hierarchy TABLE
(
    NodeId varchar(50) PRIMARY KEY NOT NULL,
    ParentNodeId varchar(50) NULL,
    Depth int NOT NULL,
    [Path] varchar(2000) NOT NULL
)

WITH Hierarchy AS
(
    --initialization
    SELECT NodeId, ParentNodeId, 0 AS Depth, CONVERT(varchar(2000), NodeId) AS [Path]
    FROM @Nodes
    WHERE ParentNodeId IS NULL

    UNION ALL

    --recursive execution
    SELECT n.NodeId, n.ParentNodeId, p.Depth + 1, CONVERT(varchar(2000), p.[Path] + '/' + n.NodeId)
    FROM Hierarchy AS p
    INNER JOIN @Nodes AS n
    ON p.NodeId = n.ParentNodeId
)
INSERT INTO @Hierarchy
SELECT *
FROM Hierarchy

SELECT parent.NodeId AS AncestorNodeId, child.NodeId AS DescendantNodeId, child.Depth - parent.Depth AS GenerationsRemoved
FROM @Hierarchy AS parent
INNER JOIN @Hierarchy AS child
ON child.[Path] LIKE parent.[Path] + '/%'
0
ответ дан 26 October 2019 в 10:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: