joa*_*olo 11 postgresql sql-server t-sql functions
给定两个数字n
and m
,我想生成一系列的形式
1, 2, ..., (n-1), n, n, (n-1), ... 2, 1
Run Code Online (Sandbox Code Playgroud)
并重复它m
几次。
例如,对于n = 3
and m = 4
,我想要以下 24 个数字的序列:
1, 2, 3, 3, 2, 1, 1, 2, 3, 3, 2, 1, 1, 2, 3, 3, 2, 1, 1, 2, 3, 3, 2, 1
---------------- ---------------- ---------------- ----------------
Run Code Online (Sandbox Code Playgroud)
我知道如何通过以下两种方法之一在 PostgreSQL 中实现此结果:
使用以下查询,该查询使用该generate_series
函数,以及一些确保订单正确的技巧:
WITH parameters (n, m) AS
(
VALUES (3, 5)
)
SELECT
xi
FROM
(
SELECT
i, i AS xi
FROM
parameters, generate_series(1, parameters.n) AS x(i)
UNION ALL
SELECT
i + parameters.n, parameters.n + 1 - i AS xi
FROM
parameters, generate_series(1, parameters.n) AS x(i)
) AS s0
CROSS JOIN
generate_series (1, (SELECT m FROM parameters)) AS x(j)
ORDER BY
j, i ;
Run Code Online (Sandbox Code Playgroud)
... 或使用具有伴随和嵌套循环的相同目的的函数:
CREATE FUNCTION generate_up_down_series(
_elements /* n */ integer,
_repetitions /* m */ integer)
RETURNS SETOF integer AS
$BODY$
declare
j INTEGER ;
i INTEGER ;
begin
for j in 1 .. _repetitions loop
for i in 1 .. _elements loop
return next i ;
end loop ;
for i in reverse _elements .. 1 loop
return next i ;
end loop ;
end loop ;
end ;
$BODY$
LANGUAGE plpgsql IMMUTABLE STRICT ;
Run Code Online (Sandbox Code Playgroud)
我怎么可能在标准 SQL 或 Transact-SQL/SQL Server 中执行等效操作?
Vér*_*ace 11
这是一个很长的方法,所以我首先将最好的(即最快的)方法放在这里。它使用了INTARRAY扩展 - 对于 340 和 570 的参数,需要 21ms *。第二好的(22 ms - 相同的参数)仅使用标准 PostgreSQL 构造。如果其他人想出更快的方法,我会将它们放在这里并“退休”我的!
\n* 8 GB RAM、Intel i5 第 11 代 CPU、四核 - 8 线程、NVMe 256 GB 驱动器
\n这个问题引起了我的兴趣(+1)并且我思考了
\na) 如何回答以及
\nb) 答案如何概括?
\n下面的所有代码都可以在每个方法/贡献者的各种小提琴中找到。
\n有趣的是,到目前为止,没有人回答过(10 个答案 - 以及一些非常高质量的 SQL/编程启动!)使用过ARRAY
s (教程),我相信这在这种情况下非常有帮助。
一般来说,我的方法是将第一个系列生成为 ARRAY ( {1, 2,.. n, n,..2, 1}
),然后生成m
这些序列以完成完整的任务。
我采取了三五种方法:
第一个是 PostgreSQL 特定的,使用GENERATE_SERIES()
(教程)和ARRAY
s。还有一个可以用 a 替换的函数调用RECURSIVE CTE
("RCTE"
- 请参阅教程)。
第二个(也是 PostgreSQL 特有的)将 an与对和s 的RCTE
调用结合起来。可以替换为- 请参阅解决方案 3。GENERATE_SERIES()
ARRAY
GENERATE_SERIES()
RCTE
第三种解决方案是"Pure SQL"
并且应该适用于任何支持s的RDBMS (例如RCTE
SQL Server ) - 也可以使用表(即序列)根据dba聊天室的讨论,我已经删除了使用s来构造序列的要求。numbers
RCTE
然后有两种“快速”解决方案,它们依赖于UNNEST()
保持秩序的事实。
我根据问题使用了一个名为的表param
来存储值(3
& ) - 这些值显然可以更改。5
另外,对于基准测试步骤(见下文),我将这个参数表用于所有测试的查询,以便有一个公平的竞争环境。如上所述,numbers
序列表也是允许的。
--\n-- Setup of parameters...\n--\n\nCREATE TABLE param(n INT, m INT);\nINSERT INTO param (VALUES(3, 5));\nSELECT * FROM param;\n\n\n--\n-- Setup of numbers\n--\n\nCREATE TABLE numbers (n INT);\nINSERT INTO numbers\nSELECT GENERATE_SERIES(1, ((SELECT m FROM param))); \nSELECT * FROM numbers LIMIT 5;\n
Run Code Online (Sandbox Code Playgroud)\n第一种方法如下:
\n--\n-- Step 1\n--\nSELECT\n GENERATE_SERIES(1, (SELECT n FROM param)) AS the_first_series\nUNION ALL\nSELECT \n GENERATE_SERIES((SELECT n FROM param), 1, -1);\n
Run Code Online (Sandbox Code Playgroud)\n结果:
\nthe_first_series\n 1\n 2\n 3\n 3\n 2\n 1\n
Run Code Online (Sandbox Code Playgroud)\n--\n-- Two possible Step 2s using a PL/pgSQL function or an RCTE\n--\nCREATE OR REPLACE FUNCTION fill_array_with_seq(the_array anyarray, seq_num INT)\nRETURNS ANYARRAY LANGUAGE PLpgSQL AS $$\nDECLARE\nBEGIN\n FOR i IN 1..seq_num LOOP\n the_array[i] := i;\n i = i + 1;\n END LOOP;\n RETURN the_array;\nend $$;\n\nSELECT fill_array_with_seq(ARRAY[]::INT[], (SELECT n * 2 FROM param));\n\nWITH RECURSIVE cte_fill_arr (n, f_arr) AS\n(\n SELECT 1 AS n, ARRAY[1]::INT[] AS f_arr\n UNION ALL\n SELECT n + 1, array_append(f_arr, n + 1)\n FROM cte_fill_arr\n WHERE n < (SELECT n * 2 FROM param)\n)\nSELECT f_arr FROM cte_fill_arr\nWHERE CARDINALITY(f_arr) = (SELECT n * 2 FROM param);\n
Run Code Online (Sandbox Code Playgroud)\n结果(相同):
\nfill_array_with_seq\n {1,2,3,4,5,6}\n f_arr\n {1,2,3,4,5,6}\n
Run Code Online (Sandbox Code Playgroud)\n--\n-- Step 3\n--\n\nWITH RECURSIVE cte_fill_arr (n, f_arr) AS\n(\n SELECT 1 AS n, ARRAY[1]::INT[] AS f_arr\n UNION ALL\n SELECT n + 1, array_append(f_arr, n + 1)\n FROM cte_fill_arr\n WHERE n < (SELECT n * 2 FROM param)\n)\nSELECT \n ROW_NUMBER() OVER () AS rn,\n (\n SELECT f_arr FROM cte_fill_arr\n WHERE CARDINALITY(f_arr) = (SELECT n * 2 FROM param)\n ),\n \n -- could use\n --\n -- fill_array_with_seq(ARRAY[]::INT[], (SELECT n * 2 FROM param))\n --\n \n ARRAY\n (\n SELECT \n GENERATE_SERIES(1, (SELECT n FROM param))\n UNION ALL\n SELECT \n GENERATE_SERIES((SELECT n FROM param), 1, -1)\n ) AS arr\n FROM\n GENERATE_SERIES(1, (SELECT m FROM param)) AS x;\n
Run Code Online (Sandbox Code Playgroud)\n结果:
\nrn f_arr arr\n 1 {1,2,3,4,5,6} {1,2,3,3,2,1}\n 2 {1,2,3,4,5,6} {1,2,3,3,2,1}\n 3 {1,2,3,4,5,6} {1,2,3,3,2,1}\n 4 {1,2,3,4,5,6} {1,2,3,3,2,1}\n 5 {1,2,3,4,5,6} {1,2,3,3,2,1}\n
Run Code Online (Sandbox Code Playgroud)\n最后:
\n--\n-- Steps 4 & 5 - separate subquery not shown\n--\n\nWITH RECURSIVE cte_fill_arr (n, f_arr) AS\n(\n SELECT 1 AS n, ARRAY[1]::INT[] AS f_arr\n UNION ALL\n SELECT n + 1, array_append(f_arr, n + 1)\n FROM cte_fill_arr\n WHERE n < (SELECT n * 2 FROM param)\n)\nSELECT the_series FROM\n(\n SELECT \n ROW_NUMBER() OVER () AS rn,\n UNNEST\n (\n (\n SELECT f_arr FROM cte_fill_arr\n WHERE CARDINALITY(f_arr) = (SELECT n * 2 FROM param)\n )\n ) AS seq, \n UNNEST\n (\n ARRAY\n (\n SELECT \n GENERATE_SERIES(1, (SELECT n FROM param))\n UNION ALL\n SELECT \n GENERATE_SERIES((SELECT n FROM param), 1, -1)\n )\n ) AS arr\n FROM\n GENERATE_SERIES(1, (SELECT m FROM param)) AS x\n ORDER BY rn, seq\n) AS fin_arr\nORDER BY rn, seq;\n
Run Code Online (Sandbox Code Playgroud)\n结果:
\nthe_series\n 1\n 2\n 3\n 3\n 2\n 1\n 1\n 2\n...\n... snipped for brevity\n...\n
Run Code Online (Sandbox Code Playgroud)\n在这里,我通过在同一个 RCTE 中构建所需的序列及其编号方案,成功地“一石二鸟”,如下所示:
\n--\n-- Step 1\n--\nWITH RECURSIVE cte_fill_array AS -- (cnt, val_arr, cnt_arr) AS\n(\n SELECT 1 AS i, 1 AS cnt, ARRAY[1] AS val_arr, ARRAY[1] AS cnt_arr\n UNION ALL\n SELECT i + 1, cnt + 1, \n ARRAY_APPEND\n (\n val_arr,\n (\n SELECT \n CASE\n WHEN cnt < (SELECT n FROM param) THEN (i + 1)\n WHEN cnt = (SELECT n FROM param) THEN cnt\n WHEN cnt > (SELECT n FROM param) THEN 6 - i\n END\n )\n ),\n ARRAY_APPEND(cnt_arr, cnt + 1)\n FROM cte_fill_array\n WHERE cnt < 2 * (SELECT n FROM param)\n)\nSELECT i, cnt, val_arr, cnt_arr FROM cte_fill_array;\n
Run Code Online (Sandbox Code Playgroud)\n结果:
\ni cnt val_arr cnt_arr\n1 1 {1} {1}\n2 2 {1,2} {1,2}\n3 3 {1,2,3} {1,2,3}\n4 4 {1,2,3,3} {1,2,3,4}\n5 5 {1,2,3,3,2} {1,2,3,4,5}\n6 6 {1,2,3,3,2,1} {1,2,3,4,5,6}\n
Run Code Online (Sandbox Code Playgroud)\n我们只想要最后一条记录,因此我们通过使用CARDINALITY()
函数来选择它 - 其中等于 ( n * 2
) 的是最后一条记录(步骤未单独显示)。
最后一步 -有关更多详细信息,请参阅fiddle
\n--\n-- Steps 2 - end\n--\nWITH RECURSIVE cte_fill_arr (n, f_arr) AS\n(\n SELECT 1 AS n, ARRAY[1]::INT[] AS f_arr\n UNION ALL\n SELECT n + 1, array_append(f_arr, n + 1)\n FROM cte_fill_arr\n WHERE n < (SELECT n * 2 FROM param)\n)\nSELECT arr AS the_series FROM\n(\n SELECT \n ROW_NUMBER() OVER () AS rn,\n UNNEST\n (\n (\n SELECT f_arr FROM cte_fill_arr\n WHERE CARDINALITY(f_arr) = (SELECT n * 2 FROM param)\n )\n ) AS seq, \n UNNEST\n (\n ARRAY\n (\n SELECT \n GENERATE_SERIES(1, (SELECT n FROM param))\n UNION ALL\n SELECT \n GENERATE_SERIES((SELECT n FROM param), 1, -1)\n )\n ) AS arr\n FROM\n GENERATE_SERIES(1, (SELECT m FROM param)) AS x\n ORDER BY rn, seq\n) AS fin_arr\nORDER BY rn, seq;\n
Run Code Online (Sandbox Code Playgroud)\n结果(与其他相同):
\nthe_series\n 1\n 2\n 3\n 3\n...\n... snipped for brevity\n...\n
Run Code Online (Sandbox Code Playgroud)\n存在一个更简单、(恕我直言)更优雅的解决方案 - 使用GENERATE_SUBSCRIPTS()
函数(解释)如下:
WITH RECURSIVE cte (i) AS\n(\n SELECT 1 AS i, 1 AS cnt\n UNION ALL\n SELECT \n CASE\n WHEN cnt < (SELECT n FROM param) THEN (i + 1)\n WHEN cnt = (SELECT n FROM param) THEN cnt\n ELSE i - 1\n END AS i,\n cnt + 1\n FROM cte\n WHERE cnt < 2 * (SELECT n FROM param)\n)\nSELECT the_arr\nFROM\n(\n SELECT \n x, \n UNNEST(ARRAY(SELECT i FROM cte)) AS the_arr, \n GENERATE_SUBSCRIPTS(ARRAY(SELECT i FROM cte), 1) AS ss\n\n FROM GENERATE_SERIES(1, (SELECT m FROM param)) AS t(x)\n) AS s\nORDER BY x, ss;\n
Run Code Online (Sandbox Code Playgroud)\n结果(相同):
\nthe_series\n1\n2\n3\n3\n...\n... snipped for brevity\n...\n
Run Code Online (Sandbox Code Playgroud)\n由于下面的所有代码都以一种或另一种形式在上面看到,因此我只包括最后一步。没有使用 PostgreSQL 特定功能,它也可以在 SQL Server 2019 (Linux fiddle ) 下运行 - 也可以追溯到 2016 年 - 所有版本。
\nWITH RECURSIVE cte (i, cnt) AS\n(\n SELECT 1 AS i, 1 AS cnt\n UNION ALL\n SELECT \n CASE\n WHEN cnt < (SELECT n FROM param) THEN (i + 1)\n WHEN cnt = (SELECT n FROM param) THEN cnt\n ELSE i - 1\n END AS i,\n cnt + 1\n FROM cte\n WHERE cnt < 2 * (SELECT n FROM param)\n)\nSELECT \n n.n, c.i, c.cnt\nFROM \n cte c\nCROSS JOIN numbers n\nORDER BY n.n, c.cnt;\n
Run Code Online (Sandbox Code Playgroud)\n结果(相同):
\ni\n1\n2\n3\n3\n
Run Code Online (Sandbox Code Playgroud)\nclubhouse leader!
)(小提琴):SELECT UNNEST(arr)\nFROM\n(\n SELECT arr, GENERATE_SERIES(1, (SELECT m FROM param)) AS gs\n FROM\n (\n SELECT \n ARRAY\n (\n SELECT x \n FROM GENERATE_SERIES(1, (SELECT n FROM param)) x\n UNION ALL\n SELECT x\n FROM GENERATE_SERIES((SELECT n FROM param), 1, -1) x\n ) AS arr\n ) AS t\n) AS s;\n
Run Code Online (Sandbox Code Playgroud)\n与所有其他结果相同。
\nSELECT\n UNNEST\n (\n ARRAY_CAT\n (\n ARRAY\n (\n SELECT GENERATE_SERIES(1, (SELECT n FROM param))::INT\n ), \n ARRAY\n (\n SELECT GENERATE_SERIES((SELECT n FROM param), 1, -1)::INT\n )\n )\n ) FROM GENERATE_SERIES(1, (SELECT m FROM param));\n
Run Code Online (Sandbox Code Playgroud)\n与所有其他结果相同。
\nWITH cte AS\n(\n SELECT\n ARRAY(SELECT GENERATE_SERIES(1, (SELECT n FROM param))) AS arr\n)\nSELECT UNNEST \n(\n (\n SELECT ARRAY_CAT(c.arr, SORT(c.arr, \'DESC\'))\n FROM cte c\n )\n) FROM GENERATE_SERIES(1, (SELECT m FROM param));\n
Run Code Online (Sandbox Code Playgroud)\n结果一样!
\n我对所有 PostgreSQL 解决方案进行了基准测试。
\n我已尽最大努力在这些基准测试中做到公平 - 我在 SQL 中使用了参数表(3, 5)
(also(34, 57)
和(340, 570)
at )。对于那些需要表(即序列)的(home)
查询,经过讨论,我已将其包含在需要它的查询中。number
我对此并不完全确定,因为顾问经常被禁止创建单独的表,无论多么微不足道,但这似乎是共识!
如果您对任何测试不满意,请告诉我,我很乐意重新运行它们!
\n我用于db<>fiddle
测试,并且适用通常的警告 - 我不知道在任何给定时刻该服务器上还运行着什么 - 我对每个解决方案平均运行了几次(大部分结果都在~ 彼此的 10% - 丢弃明显的异常值(更长,而不是更短的时间)。
有人向我指出(无论如何我都知道)3 和 5 并不是很大的数字 - 我确实尝试为每个参数使用低 100,但在 db<>fiddle.uk 上运行一直失败,但我只能说所有的运行都非常一致,仅相差 ~ +- 10%。
\n第二个读数的值为 34 和 57 - 请随意尝试。
\n通过(home)
测试,我在 8GB 机器(i5 - 第 10 代,NVMe 256GB)上使用了参数(340, 570)
- 没有其他运行 - 方差低 ~ 1/2%!
V\xc3\xa9race\'s (Another scorcher using INTARRAY!)
第 6 个解决方案(小提琴)(0.110 毫秒)/ 0.630 毫秒/21.5 毫秒(主页)- new leader
!
V\xc3\xa9race\'s (前俱乐部队长) 第四解 (小提琴) 0.120 ms/ 0.625 ms /22.5 ms (主场)
\nV\xc3\xa9race\'s(荣誉奖)第五个解决方案(小提琴)(0.95ms/ 0.615(下降!) /26 ms(主页)
\nV\xc3\xa9race GENERATE_SERIES SQL 方法(小提琴):0.195 ms/ 3.1 ms /140ms(主页)
\nV\xc3\xa9race RECURSIVE CTE SQL 方法(小提琴):0.200 ms/ 2.9 ms /145m(主页)
\nV\xc3\xa9race GENERATE_SUBSCRIPTS() SQL 方法 ( fiddle ): 0.110 ms/ 2.75 ms /130ms (home)
\nErwin Brandtstetter 的 SQL 方法(小提琴):2.15 ms / 3.65 ms /160ms(home)(没有 ORDER BY - home 时 160 下降到 ~ 100)
\nAbelito\ 的 SQL 方法(小提琴)0.145/如果参数更改会失败?
\nEvan Carroll 的 SQL 方法 ( fiddle ) 0.125 ms/ 1.1ms /45ms (home)
\n再次,我重申(冒着重复自己的风险(多次!:-))),如果您对您的基准不满意,请告诉我,我将在此处包含任何修改 - 我只是强调我真正感兴趣公平地说,并从这个过程中实际学习 - 独角兽点都很好,但我的首要任务是增加我(我们的)知识库!
\nPostgreSQL 的源代码有点高于我的工资等级,但我相信 使用GENERATE_SERIES
和ARRAY
s 进行的操作会保留顺序 -WITH ORDINALITY
这意味着(再次,我认为) - 即使不注意顺序也会出现正确的答案(尽管这不是保证)!@ErwinBrandstetter说:
\n\n\n
\n- 我添加了 ORDER BY 以保证所请求的订单。对于当前版本或 Postgres,它也可以在没有 ORDER BY 的情况下用于简单查询 - 但不一定在更复杂的查询中!这是一个实现细节(并且不会改变),但 SQL 标准并未强制要求。
\n
我的理解是ARRAY
s 在 PostgreSQL 中速度很快,因为大部分后端代码都是通过它们实现的 - 但正如我所说,我并不是真正的C
。
当前排名(截至 2021 年 10 月 27 日 13:50 UTC)为:
\n我发现Erwin Brandstetter ( 1 ) 和a_horse_with_no_name (2)的 ARRAY 上的这些帖子非常有帮助!我发现有帮助的其他内容如下(1 , 2。
\nErw*_*ter 10
您可以使用单一的 generate_series()
基本数学运算(请参阅数学函数)。
包装成一个简单的SQL函数:
CREATE OR REPLACE FUNCTION generate_up_down_series(n int, m int)
RETURNS SETOF int AS
$func$
SELECT CASE WHEN n2 < n THEN n2 + 1 ELSE n*2 - n2 END
FROM (
SELECT n2m, n2m % (n*2) AS n2
FROM generate_series(0, n*2*m - 1) n2m
) sub
ORDER BY n2m
$func$ LANGUAGE sql IMMUTABLE;
Run Code Online (Sandbox Code Playgroud)
称呼:
SELECT * FROM generate_up_down_series(3, 4);
Run Code Online (Sandbox Code Playgroud)
生成所需的结果。n和m可以是任何整数,其中n*2*m不会溢出int4
。
在子查询中:
使用简单的升序生成所需的总行数 ( n*2*m )。我的名字n2m
。0到N-1(不是1到N)以简化以下模运算。
拿它% n*2(%
是模运算符)得到一系列n升序数,m次。我的名字n2
。
在外部查询中:
将 1 添加到下半部分 ( n2 < n )。
对于具有n*2 - n2的下半部分的上半部分 ( n2 >= n ) 镜像。
我添加ORDER BY
以保证请求的订单。对于当前版本或 Postgres,它也适用ORDER BY
于简单查询——但不一定适用于更复杂的查询!这是一个实现细节(它不会改变)但不是 SQL 标准保证的。
不幸的generate_series()
是,正如所评论的那样,是 Postgres 特定的而不是标准的 SQL。但是我们可以重用相同的逻辑:
您可以使用递归 CTE 代替 生成序列号generate_series()
,或者更有效地重复使用,创建一个包含序列整数的表一次。谁都可以读,谁也不能写!
CREATE TABLE int_seq (i integer);
WITH RECURSIVE cte(i) AS (
SELECT 0
UNION ALL
SELECT i+1 FROM cte
WHERE i < 20000 -- or as many you might need!
)
INSERT INTO int_seq
SELECT i FROM cte;
Run Code Online (Sandbox Code Playgroud)
那么,上面的SELECT
就变得更简单了:
SELECT CASE WHEN n2 < n THEN n2 + 1 ELSE n*2 - n2 END AS x
FROM (
SELECT i, i % (n*2) AS n2
FROM int_seq
WHERE i < n*2*m -- remember: 0 to N-1
) sub
ORDER BY i;
Run Code Online (Sandbox Code Playgroud)
在 Postgres 中,使用这个generate_series()
函数很容易:
WITH
parameters (n, m) AS
( VALUES (3, 5) )
SELECT
CASE WHEN g2.i = 1 THEN gn.i ELSE p.n + 1 - gn.i END AS xi
FROM
parameters AS p,
generate_series(1, p.n) AS gn (i),
generate_series(1, 2) AS g2 (i),
generate_series(1, p.m) AS gm (i)
ORDER BY
gm.i, g2.i, gn.i ;
Run Code Online (Sandbox Code Playgroud)
在标准 SQL 中 - 并假设参数 n、m 的大小有一个合理的限制,即小于一百万 - 您可以使用一个Numbers
表:
CREATE TABLE numbers
( n int not null primary key ) ;
Run Code Online (Sandbox Code Playgroud)
用您的 DBMS 的首选方法填充它:
INSERT INTO numbers (n)
VALUES (1), (2), .., (1000000) ; -- some mildly complex SQL here
-- no need to type a million numbers
Run Code Online (Sandbox Code Playgroud)
然后使用它,而不是generate_series()
:
WITH
parameters (n, m) AS
( VALUES (3, 5) )
SELECT
CASE WHEN g2.i = 1 THEN gn.i ELSE p.n + 1 - gn.i END AS xi
FROM
parameters AS p
JOIN numbers AS gn (i) ON gn.i <= p.n
JOIN numbers AS g2 (i) ON g2.i <= 2
JOIN numbers AS gm (i) ON gm.i <= p.m
ORDER BY
gm.i, g2.i, gn.i ;
Run Code Online (Sandbox Code Playgroud)
如果您需要纯 SQL。理论上它应该适用于大多数 DBMS(在 PostgreSQL 和 SQLite 上测试):
with recursive
s(i,n,z) as (
select * from (values(1,1,1),(3*2,1,2)) as v -- Here 3 is n
union all
select
case z when 1 then i+1 when 2 then i-1 end,
n+1,
z
from s
where n < 3), -- And here 3 is n
m(m) as (select 1 union all select m+1 from m where m < 2) -- Here 2 is m
select n from s, m order by m, i;
Run Code Online (Sandbox Code Playgroud)
生成系列 1..n
假如说 n=3
with recursive s(n) as (
select 1
union all
select n+1 from s where n<3
)
select * from s;
Run Code Online (Sandbox Code Playgroud)
它非常简单,几乎可以在任何关于递归 CTE 的文档中找到。但是我们需要每个值的两个实例所以
生成系列 1,1,..,n,n
with recursive s(n) as (
select * from (values(1),(1)) as v
union all
select n+1 from s where n<3
)
select * from s;
Run Code Online (Sandbox Code Playgroud)
这里我们只是将初始值加倍,它有两行,但是我们需要以相反的顺序第二组,所以我们将稍微介绍一下顺序。
在我们介绍顺序之前,请注意这也是一回事。我们可以在起始条件中有两行,每行三列,我们n<3
仍然是单列条件。而且,我们仍然只是增加 的价值n
。
with recursive s(i,n,z) as (
select * from (values(1,1,1),(1,1,1)) as v
union all
select
i,
n+1,
z
from s where n<3
)
select * from s;
Run Code Online (Sandbox Code Playgroud)同样,我们可以将它们混合起来,在这里观察我们的起始条件变化:这里我们有一个(6,2)
,(1,1)
with recursive s(i,n,z) as (
select * from (values(1,1,1),(6,1,2)) as v
union all
select
i,
n+1,
z
from s where n<3
)
select * from s;
Run Code Online (Sandbox Code Playgroud)生成系列 1..n,n..1
这里的技巧是生成系列 (1..n) 两次,然后简单地更改第二组的顺序。
with recursive s(i,n,z) as (
select * from (values(1,1,1),(3*2,1,2)) as v
union all
select
case z when 1 then i+1 when 2 then i-1 end,
n+1,
z
from s where n<3
)
select * from s order by i;
Run Code Online (Sandbox Code Playgroud)
这i
是顺序,z
是序列号(如果需要,也可以是序列的一半)。因此,对于序列 1,我们将顺序从 1 增加到 3,对于序列 2,我们将顺序从 6 减少到 4。最后
将系列相乘 m
(请参阅答案中的第一个查询)
归档时间: |
|
查看次数: |
7402 次 |
最近记录: |