CTE算术移位运算符导致算术溢出错误

时间:2019-02-05 09:05:30

标签: sql sql-server

在执行CTE表达式以通过移位查询有序的子级父关系时,它会失败

  

将表达式转换为数据类型bigint的算术溢出错误

问题是平移值非常容易变大。我知道我可以增加数据类型以支持38个数字值,但是在与深层父子关系时,我仍然会达到这个数字。我想知道是否还有其他方法可以对结果进行排序,所以我不会达到此限制。

这是一个示例脚本,显示了shift参数的增加。

CREATE TABLE [dbo].[ParentChild] (
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [ParentId] [int] NULL,
    [Name] [nvarchar](150) NOT NULL
 CONSTRAINT [PK_Dialog] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
))
GO

ALTER TABLE [dbo].[ParentChild]  WITH CHECK ADD  CONSTRAINT [FK_ParentChild_ParentId] FOREIGN KEY([ParentId])
REFERENCES [dbo].[ParentChild] ([Id])
GO

ALTER TABLE [dbo].[ParentChild] CHECK CONSTRAINT [FK_ParentChild_ParentId]
GO

set identity_insert [dbo].[ParentChild] on
insert into [dbo].[ParentChild] ([Id], [ParentId],[Name])
values 
(1, NULL, '1'),
(2, NULL, '2'),
(3, 1, '1.1'),
(4, 1, '1.2'),
(5, 2, '2.1'),
(6, 5, '2.1.1')
set identity_insert [dbo].[ParentChild] off

-- without shift
with Parent as (
        select d1.[Id], d1.[ParentId], d1.[Name], 0 AS [Level]
        FROM [dbo].[ParentChild] as d1
        WHERE d1.[ParentId] IS NULL
    UNION ALL
        SELECT d2.Id, d2.ParentId, d2.[Name], [Level] + 1
        FROM [dbo].[ParentChild] as d2
        INNER JOIN Parent d1 ON d1.[Id] = d2.ParentId
    )

    select p.Id, p.ParentId, p.[Name], [Level]
    from Parent p
    group by p.Id, p.ParentId, p.[Name], [Level];

-- desired  
with Parent as (
    select d1.[Id], d1.[ParentId], d1.[Name], 0 AS [Level],
    CAST(row_number() over(order by id) as DECIMAL(38,0)) as [shift]
    FROM [dbo].[ParentChild] as d1
    WHERE d1.[ParentId] IS NULL
UNION ALL
    SELECT d2.Id, d2.ParentId, d2.[Name], [Level] + 1, 
    CAST([shift] * 100 + row_number() over(order by d2.id) as DECIMAL(38,0))
    FROM [dbo].[ParentChild] as d2
    INNER JOIN Parent d1 ON d1.[Id] = d2.ParentId
)

select p.Id, p.ParentId, p.[Name], [Level], [shift]
from Parent p
group by p.Id, p.ParentId, p.[Name], [Level], [shift]
order by cast([shift] as varchar(50))

不带shift参数的输出

Id  ParentId    Name    Level
1   NULL        1       0
2   NULL        2       0
3   1           1.1     1
4   1           1.2     1
5   2           2.1     1
6   5           2.1.1   2

带有shift参数的输出(所需)

Id  ParentId    Name    Level   shift
1   NULL        1       0       1
3   1           1.1     1       101
4   1           1.2     1       102
2   NULL        2       0       2
5   2           2.1     1       201
6   5           2.1.1   2       20101

1 个答案:

答案 0 :(得分:1)

假设我们可以将shift设置为字符串而不是支持数学的数据类型,我们可以这样做:

with Parent as (
    select d1.[Id], d1.[ParentId], d1.[Name], 0 AS [Level],
    CONVERT(varchar(max),row_number() over(order by id)) as [shift]
    FROM [dbo].[ParentChild] as d1
    WHERE d1.[ParentId] IS NULL
UNION ALL
    SELECT d2.Id, d2.ParentId, d2.[Name], [Level] + 1,
    shift + RIGHT('0' + CONVERT(varchar(2),row_number() over(order by d2.id)),2)
    FROM [dbo].[ParentChild] as d2
    INNER JOIN Parent d1 ON d1.[Id] = d2.ParentId
)
select p.Id, p.ParentId, p.[Name], [Level], [shift]
from Parent p
group by p.Id, p.ParentId, p.[Name], [Level], [shift]
order by shift

如果行数超过100,则会产生不同的结果,但这似乎仍然会导致这种表示形式的问题(模糊编码)。