在单个字符串中生成以逗号分隔的数字列表

Generate a comma-separated list of numbers in a single string

有没有办法在提供 "begin" 和 "end" 数字的情况下生成以逗号分隔的一系列数字字符串?

例如,提供数字 1 和 10,输出将是单个值:1,2,3,4,5,6,7,8,9,10

10/10/2019 编辑解释我为什么对此感兴趣:

我的工作场所在 SELECT 语句和聚合函数中编写包含多个列的查询。然后是使用列号的 GROUP BY 子句。我认为使用一个为 copy/paste 创建逗号分隔列表的宏会节省一些时间。

SELECT t.colA
     , t.colB
     , t.colC
     , t.colD
     , t.colE
     , t.colF
     , t.colG
     , t.colH
     , t.colI
     , t.colJ
     , sum(t.colK) as sumK
     , sum(t.colL) as sumL
     , sum(t.colM) as sumM
  FROM t
 GROUP BY 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
;

在SQL Server-

中检查这些方法
IF OBJECT_ID('TEMPDB..#Sample') IS NOT NULL 
    DROP TABLE #Sample

Create table #Sample 
(
NUM int
)

declare @n int
select @n=10
insert into #Sample(NUM) 
SELECT NUM FROM (select row_number() over (order by (select null)) AS NUM from sys.columns) A WHERE NUM<=@N

--Method 1 (For SQL SERVER -NEW VERSION Support)
SELECT STRING_AGG(NUM,',') AS EXPECTED_RESULT FROM #Sample
--Method 1 (For SQL SERVER -OLD VERSION Support)
select DISTINCT STUFF(CAST((
    SELECT   ' ,' +CAST(c.num AS VARCHAR(MAX))
    FROM (  
            SELECT num
            FROM   #Sample
        ) c
    FOR XML PATH(''), TYPE) AS VARCHAR(MAX)), 1, 2, '') AS EXPECTED_RESULT
    from #Sample t

我不确定在 Teradata 中是否有直接生成序列的好方法。不过,您可以通过几种不同的方式伪造它。这是一个逗号分隔的数字列表,从 5 到 15,例如:

SELECT TRIM(TRAILING ',' FROM (XMLAGG(TRIM(rn)|| ',' ) (VARCHAR(10000))))
FROM (SELECT 4 + ROW_NUMBER() OVER (ORDER BY Sys_Calendar."CALENDAR".day_of_calendar) as rn FROM Sys_Calendar."CALENDAR" QUALIFY rn <= 15) t

我在这里只用了 sys_calendar.calendar 因为它很大 table。不过,任何大 table 都可以。

While 循环似乎合适

declare @begin int=1
declare @end int=11

declare @list varchar(500)

if @begin > @end
    begin
        select 'error, beginning number ' + convert(varchar(500),@begin)
        + ' must not be greater than ending number '
        + convert(varchar(500),@end) + '.' err
        return
    end
    else
        set @list = convert(varchar(500),@begin)
;
while @begin < @end
    begin
        set @begin += 1
        set @list = @list + ',' + convert(varchar(500),@begin)
    end

select @list

你可能想使用 varchar(5000) 或其他东西,这取决于你想要它有多大。

disclaimer -- I don't know if this works with teradata

这是在 Teradata 中执行此操作的一种方法:

SELECT ARRAY_AGG(src.RowNum) 
FROM (
  SELECT ROW_NUMBER() OVER() AS RowNum
  FROM sys_calendar.calendar
  QUALIFY RowNum BETWEEN <begin_num> AND <end_num>
) src

这将为您提供 ARRAY 数据类型的输出,您可以将其转换为 VARCHAR。它还假定 begin_num > 0<end_num> 小于 sys_calendar.calendar 视图中的行数。您始终可以 fiddle 使用它来满足您所需的值范围。

还有 DelimitedBuild UDF(如果您能找到的话)可用于将行值转换为分隔字符串。

您可以使用递归 CTE 生成您的数字,并 xml_agg 生成您的字符串:

with  recursive nums (counter) as
( select * from (select  cast(1 as bigint) as counter) t
union all
select
counter + 1
from nums
where counter between 1 and 9
)
 select 
 trim(trailing ',' from cast(xmlagg(cast(counter as varchar(2)) || ',' order by counter) as varchar(100)))
 from nums

实现您的目标最便宜的方法是这个(不需要函数,也不需要连接到表):

WITH RECURSIVE NumberRanges(TheNumber,TheString) AS
(
SELECT 1 AS TheNumber,casT(1 as VARCHAR(500)) as TheString

FROM
( 
  SELECT * FROM (SELECT NULL AS X) X
) DUMMYTABLE
UNION ALL
SELECT
    TheNumber + 1 AS TheNumber,
    TheString ||',' || TRIM(TheNumber+1) 

FROM NumberRanges
WHERE
TheNumber < 10
)
SELECT TheString
FROM NumberRanges
QUALIFY ROW_NUMBER() OVER ( ORDER BY TheNumber DESC) = 1;

结果字符串:1,2,3,4,5,6,7,8,9,10