3

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

我想我需要一个 cte,但不知道如何实现这一点。

注意:扩展时我期待 7m 行。

4

4 回答 4

3

如果你想要 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)

详见BOL _

于 2009-01-21T12:05:14.537 回答
1

我不知道如何使用公用表表达式来完成,但这里有一个使用临时表的解决方案:

   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

如果 Numbers 表是常规表,则可以优化。因此,您不必在每次调用时填写临时表。

于 2009-01-21T10:53:32.873 回答
0

你可以试试这种方法:

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

不是最快的,但应该可以

于 2009-01-21T10:41:22.193 回答
0

我会做一些与 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

这将最大限度地减少您需要插入表变量的行数,然后使用连接将一个表“乘以”另一个表......

根据查询的性质,源表不需要索引,但“数字”表应该有索引(或主键)。聚集索引指的是它们在磁盘上的存储方式,所以我看不到 CLUSTERED 在这里是相关的,但我把它留在了我刚从 Splattne 复制的地方。

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

于 2009-01-21T11:05:42.927 回答