1

我需要编写一个查询来打印所有小于或等于 1000 的素数。我需要将结果打印到一行中并使用 & 字符作为分隔符(而不是空格)。像这样:

2&3&5&7&11&13

这是我的代码(Number 的数据类型是 int,所以我需要将其更改为 varchar,以便与号字符可以与 Number 一起显示在一个单元格中):

with temp as
(select 2 as Number
union all 
select Number + 1 from temp where Number<1000)
, temptwo as
(select * from temp t1
where NOT EXISTS
(select 1 from temp t2
where t1.Number > t2.Number
and t1.Number % t2.Number = 0))
, tempthree as
(select Cast(Number AS Varchar) as Number from temptwo)
select 
STUFF((SELECT  '&' + Number
            FROM tempthree tt
            WHERE  tt.Number = t.Number
            FOR XML PATH('')), 1, 1, '') 
FROM tempthree t
OPTION (MAXRECURSION 0)

但它并没有真正起作用。我不知道是什么问题?到目前为止,它运行良好:

with temp as
(select 2 as Number
union all 
select Number + 1 from temp where Number<1000)
, temptwo as
(select * from temp t1
where NOT EXISTS
(select 1 from temp t2
where t1.Number > t2.Number
and t1.Number % t2.Number = 0))
select Cast(Number AS Varchar) as Number from temptwo
OPTION (MAXRECURSION 0)

但它只打印出如下内容:

2
3
5
7
11
13
...

但这不是我想要的。任何人都可以帮忙吗?

4

3 回答 3

1

如果您遇到不支持的 SQL Server 版本,则STRING_AGG需要使用STUFF,但您的语法不太正确;它应该看起来像:

with temp as
(select 2 as Number
union all 
select Number + 1 from temp where Number<1000)
select STUFF((
          SELECT '&' + Cast(Number AS Varchar)
          FROM temp t1
          where NOT EXISTS (select 1 from temp t2
                            where sqrt(t1.Number) >= t2.Number
                              and t1.Number % t2.Number = 0)
          FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
OPTION (MAXRECURSION 0)

请注意,我进行了一些优化,将您的第二个和第三个 cte 的部分带入,并通过仅查看原始数字的平方根的数字来STUFF提高查询的性能。NOT EXISTS

输出:

2&3&5&7&11&13&17&19&23&29&31&37&41&43&47&53&59&61&67&71&73&79&83&89&97&101&103&107&109&113&127&131&137&139&149&151&157&163&167&173&179&181&191&193&197&199&211&223&227&229&233&239&241&251&257&263&269&271&277&281&283&293&307&311&313&317&331&337&347&349&353&359&367&373&379&383&389&397&401&409&419&421&431&433&439&443&449&457&461&463&467&479&487&491&499&503&509&521&523&541&547&557&563&569&571&577&587&593&599&601&607&613&617&619&631&641&643&647&653&659&661&673&677&683&691&701&709&719&727&733&739&743&751&757&761&769&773&787&797&809&811&821&823&827&829&839&853&857&859&863&877&881&883&887&907&911&919&929&937&941&947&953&967&971&977&983&991&997

dbfiddle 上的演示

于 2020-05-10T01:53:06.970 回答
1

您不需要第三个 CTE 仅用于铸造。数字在 中使用时被隐式转换concat()

但是您需要实际查询的子查询从第二个 CTE 查询所有内容并将其连接起来。实际的外部查询需要减少,FROM因为您只需要一行,而不是多行,如果您从第二个 CTE 中选择,您会得到。

& 号是 XML 中的一个特殊字符,因此被编码。解决此问题的一种简单方法是最初使用逗号而不是&符号,然后使用replace()将逗号变成&符号。

WITH tempone
AS
(
SELECT 2 number
UNION ALL
SELECT number + 1
       FROM tempone
       WHERE number < 1000
),
temptwo
AS
(
SELECT *
       FROM tempone t1
       WHERE NOT EXISTS
                 (SELECT *
                         FROM tempone t2
                         WHERE t1.number > t2.number
                               AND t1.number % t2.number = 0)
)
SELECT replace(stuff((SELECT concat(',', tt.number)
                             FROM temptwo tt
                             FOR XML PATH('')), 1, 1, ''), ',', '&')
       OPTION (MAXRECURSION 0);

db<>小提琴

于 2020-05-10T01:54:18.197 回答
1

您的方法可以识别素数。您只是缺少字符串聚合。

这是一个使用 的选项string_agg(),自 SQL Server 2017 起可用:

with temp as (
    select 1 num
    union all 
    select num + 1 from temp where num < 1000
)
select string_agg(num, '&') within group(order by num) res
from temp t
where not exists (select 1 from temp t1 where t.num < t1.num and t.num % t1.num = 0)
option (maxrecursion 0)

请注意,我消除了第二个 cte,这并不是真正需要的(您可以将not exists条件直接放在外部查询中)。

于 2020-05-10T01:43:06.557 回答