Sql server 如何仅从tsql中的计数展开行

Sql server 如何仅从tsql中的计数展开行,sql-server,tsql,common-table-expression,Sql Server,Tsql,Common Table Expression,我有一个包含数字和范围值的表。例如,一列的值为40,另一列的值为100,这意味着从40开始的范围有100个以139结尾的值,包括数字40。我想编写一个tsql语句,将数据扩展到单独的行中 我想我需要一个cte,但不知道如何才能做到这一点 注意:当扩展时,我希望有700万行。您可以尝试以下方法: create function [dbo].[fRange](@a int, @b int) returns @ret table (val int) as begin declare

我有一个包含数字和范围值的表。例如,一列的值为40,另一列的值为100,这意味着从40开始的范围有100个以139结尾的值,包括数字40。我想编写一个tsql语句,将数据扩展到单独的行中

我想我需要一个cte,但不知道如何才能做到这一点


注意:当扩展时,我希望有700万行。

您可以尝试以下方法:

create function [dbo].[fRange](@a int, @b int)
    returns @ret table (val int)
as 
begin
    declare @val int
    declare @end int
    set @val = @a
    set @end = @a + @b
    while @val < @end
    begin
        insert into @ret(val)
        select @val
        set @val = @val+1
    end
return
end

go

declare @ranges table(start int, noOfEntries int)

insert into @ranges (start, noOfEntries)
select 40,100
union all select 150, 10

select * from @ranges r
    cross apply dbo.fRange(start,noOfEntries ) fr

不是最快的,但应该可以工作

我不知道如何使用常用的表表达式实现这一点,但这里有一个使用临时表的解决方案:

   SET NOCOUNT ON

   DECLARE @MaxValue INT
   SELECT @MaxValue = max(StartValue + RangeValue) FROM MyTable

   DECLARE @Numbers table ( 
      Number INT IDENTITY(1,1) PRIMARY KEY 
   )

   INSERT @Numbers DEFAULT VALUES 

   WHILE COALESCE(SCOPE_IDENTITY(), 0) <= @MaxValue 
      INSERT @Numbers DEFAULT VALUES 

    SELECT n.Number
    FROM   @Numbers n
    WHERE  EXISTS(
        SELECT *
        FROM   MyTable t
        WHERE  n.Number BETWEEN t.StartValue AND t.StartValue + t.RangeValue - 1
    )

    SET NOCOUNT OFF

如果数字表是常规表,则可以进行优化。因此,您不必在每次通话时都填写临时表格。

我会做一些与splattne稍有不同的事情

SET NOCOUNT ON

DECLARE @MaxValue INT
DECLARE @Numbers table (
    Number INT IDENTITY(1,1) PRIMARY KEY CLUSTERED
 )

SELECT @MaxValue = max(RangeValue) FROM MyTable
INSERT @Numbers DEFAULT VALUES

WHILE COALESCE(SCOPE_IDENTITY(), 0) <= @MaxValue
    INSERT @Numbers DEFAULT VALUES

SELECT
    t.startValue + n.Number
FROM
    MyTable t
INNER JOIN
    @Numbers n
        ON n.Number < t.RangeValue

SET NOCOUNT OFF
这将最大限度地减少需要插入表变量的行数,然后使用联接将一个表与另一个表“相乘”

根据查询的性质,源表不需要索引,但是numbers表应该有索引或主键。聚集索引指的是它们在磁盘上的存储方式,所以我看不出聚集索引在这里是否相关,但我在这里保留了它,因为我刚刚从Splattne复制了它


像这样的大型连接可能会很慢,但仍然比数百万次插入快得多。

如果需要CTE,这里有一个示例:

初始插入:

insert into rangeTable (StartValue, RangeValue)
select 40,100
union all select 150,10
go
查询:

with r_CTE (startVal, rangeVal, generatedVal)
as
(
    select r.startValue, r.rangeValue, r.startValue
    from rangeTable r
    union all
    select r.startValue, r.rangeValue, generatedVal+1
    from rangeTable r
    inner join r_CTE rc 
        on r.startValue = rc.startVal
        and r.rangeValue = rc.rangeVal
        and r.startValue +  r.rangeValue > rc.generatedVal + 1
)
select * from r_CTE
order by startVal, rangeVal, generatedVal
请注意,默认的最大递归数是100。您可以通过调用将其最大值更改为32767

option (maxrecursion 32767)
或者无限

option (maxrecursion 0)

有关详细信息,请参见

以明确说明:您需要所有行,例如100、101、102。。。139这是所有当前行的数字吗?数字是否在某个范围内?假设从0到10000?混合范围,但唯一且不交叉。例如10100;180, 3000 ; 或者说,6000行、140行应该提到的结果是大约700万行。需要相当快的速度,我不认为内联函数会解决这个问题,但感谢您的想法。在这种情况下,您可能需要一个表,在该表上使用join时,预先填充可能范围的值。关于CTE方法,不确定hoe是否会执行。您很可能会使用递归,但仍然需要使用一些数学运算,如+1来获取值。请叫我Anal,但临时表Table存储在磁盘上,表变量@Table存储在内存中。所以,临时表变量有点自相矛盾:[而且,聚集索引对表变量有什么影响吗?]我从一个实际表中重写了这个示例。。。因此,聚集索引来自复制粘贴-+1,我认为使用常规表的解决方案会表现良好。CoolCoder表示生成了大约700万行,所以每次将许多行插入到表变量中是非常困难的consuming@Dems,你说的是一个常见的误解。表变量在场景后面创建临时表;临时表和表变量都将尽可能多地使用内存。有了临时表,你可以得到统计数据和创建索引的能力。很好!但我认为结果会忽略每行的第一个值。在CoolCoder的示例中,值100将被忽略。对于300000左右的记录数和回答问题的最大范围16777216.+1来说,速度太慢。但我猜CoolCoder不会用它。当我试图理解这个问题时,我的大脑受伤了@splattne—我想您建议的方法,但使用预填充的标准表,最适合于大量记录。以及有关中央选举委员会;;我的大脑也很痛,我很久没有使用递归了,所以我想我应该试试:范围值可以大于32767,所以CTE是不可能的,我必须试试看它是否比TSQL循环快。有点担心这么深的递归成本。。。