SQL查询从双重返回N行
Posted
技术标签:
【中文标题】SQL查询从双重返回N行【英文标题】:SQL Query to return N rows from dual 【发布时间】:2009-12-29 09:14:19 【问题描述】:我想编写一个接受绑定变量(比如:NUM)的 SQL 查询,它的输出由一列和:NUM 行组成,每行都有其行号。即,如果我们将 :NUM 作为 7 传递,则输出应为:
VAL
====
1
2
3
4
5
6
7
查询中不应有任何实际的数据库表,也不应使用 PL/SQL 代码。即在查询中只应使用对偶
有什么办法可以做到吗?
【问题讨论】:
重新标记为 oracle,希望是正确的 @Rob:Postgres 也支持 PLSQL,但不支持FROM DUAL
所以Oracle 是正确的。
谢谢 Rob,这个问题只在 Oracle DB 上是正确的
【参考方案1】:
你可以使用:
WHERE ROWNUM <= :NUM
...但是表必须包含等于或大于绑定变量限制的行。 This link demonstrates various row number generation techniques in Oracle.
使用CONNECT BY
,Oracle 10g+:
SELECT LEVEL
FROM DUAL
CONNECT BY LEVEL <= :NUM
monojohnny
确认可以使用绑定变量。尝试在 Oracle 9i 上运行,尽管支持 CONNECT BY
语法会导致 ORA-01436 错误。
我唯一没有 100% 了解的是 CONNECT BY 是否会接受来自绑定变量的限制。
参考:
Integer Series Generators - CONNECT BY LEVEL Method【讨论】:
+1 这里也推荐这个方法:adp-gmbh.ch/ora/sql/examples/generate_rows.html 这会给我一个高于 1 的值的错误。SELECT LEVEL FROM DUAL CONNECT BY LEVEL <= 20
: ORA-01436
好点,它可以在较新的服务器(10g)上运行,但不能在 9.0.1.5.0 上运行。不过,您链接中的其他选项效果很好。
关于这个使用绑定变量:我试过了,它确实有效(使用 10.2.0.1.0):我会发布这个效果的答案以供参考。【参考方案2】:
尝试类似:
SELECT 1 AS Val FROM dual
UNION ALL SELECT 2 FROM dual
UNION ALL SELECT 3 FROM dual
UNION ALL SELECT 4 FROM dual
UNION ALL SELECT 5 FROM dual
UNION ALL SELECT 6 FROM dual
UNION ALL SELECT 7 FROM dual;
虽然很麻烦,但可以解决问题。
已编辑:啊 - 你需要传入一个变量来让你知道要走多高...
那么怎么样:
SELECT t1.Val + t2.Val * 2 + t3.Val * 4 + t4.Val * 8 AS Val
FROM
(
SELECT 0 AS Val FROM dual
UNION ALL SELECT 1 FROM dual
) AS t1,
(
SELECT 0 AS Val FROM dual
UNION ALL SELECT 1 FROM dual
) AS t2,
(
SELECT 0 AS Val FROM dual
UNION ALL SELECT 1 FROM dual
) AS t3,
(
SELECT 0 AS Val FROM dual
UNION ALL SELECT 1 FROM dual
) AS t4
WHERE t1.Val + t2.Val * 2 + t3.Val * 4 + t4.Val * 8 <= 7;
好的...再次编辑,现在使用 WITH:
WiTH
A0 AS (SELECT 0 as N FROM DUAL UNION ALL SELECT 0 FROM DUAL),
A1 AS (SELECT 0 as N FROM A0, A0 AS B),
A2 AS (SELECT 0 as N FROM A1, A1 AS B),
A3 AS (SELECT 0 as N FROM A2, A2 AS B),
A4 AS (SELECT 0 as N FROM A3, A3 AS B),
A5 AS (SELECT 0 as N FROM A4, A4 AS B),
A6 AS (SELECT 0 as N FROM A5, A5 AS B),
Nums AS (SELECT ROW_NUMBER() OVER (ORDER BY N) AS Val FROM A6)
SELECT *
FROM Nums
WHERE Val <= :NUM
;
【讨论】:
...然后根据需要继续该模式。您可以使用递归 CTE,但我不确定 Oracle 语法是什么。您也可以使用 row_number 样式的方法。 @Rob:Oracle 对递归 WITH 子句的支持从 11g iirc 开始。 是的,但我不确定它是否与 MS-SQL 中的相同。【参考方案3】:我没有想出这个答案 [所以请确保任何投票都以正确的方式进行!],这只是我基于“OMG Ponies”的测试笔记[不确定该方法是否适用于绑定变量]以上供参考:
Connected to:
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options
SQL> var num_rows number
SQL> begin select 20 into :num_rows from dual;
2 end;
3 /
PL/SQL procedure successfully completed.
SQL> select level from dual
2 connect by level <=:num_rows;
LEVEL
----------
1
2
3
4
...
【讨论】:
【参考方案4】:不通过连接查询
WITH num(n) as(select 1 from dual union all
select n+1 from num where n <= :num_limit)
select * from num
【讨论】:
【参考方案5】:我正在标记这个社区 wiki,因为它实际上并没有满足您对没有表的要求,但是我们在安装数据库时做的第一件事就是为此目的创建一组表。
包含大量整数(例如,-99999 到 99999)的表。 包含从过去 10 年到未来 10 年的每个日期的表格(每个月不断添加并偶尔修剪)。 包含一天中每个小时的表格。通过这样做,我们以(最小且便宜的)磁盘空间为代价,大大降低了大量查询的复杂性并提高了速度。
你应该认真考虑一下。除了维护日期表之外,不需要太多维护。
【讨论】:
DUAL 是执行这种事情的最佳方式——在 10g+ 中,Oracle 提供了涉及零块读取的 FAST DUAL。 DUAL 几乎总能胜过自制桌子。 毫无疑问,但我们不仅仅使用 Oracle。我们拥有的解决方案与供应商无关,并且执行速度足够快。【参考方案6】:另一种解决方案需要一些 PL/SQL 来创建一个函数来返回包含行的集合...不像 select level from dual connect by level <= :b1
方法那么简单,但它在一些情况下很有用:
1) 创建一个数字表对象类型(本例中为 number_tbl):
create or replace type number_tbl as table of number;
2) 创建一个函数,该函数将接收要生成的行数,然后返回带有结果的 number_tbl 对象:
create or replace function get_rows( i_num_rows number ) return number_tbl as
t number_tbl := number_tbl();
begin
if i_num_rows < 1 then
return null;
end if;
t.extend( i_num_rows );
for i in 1..i_num_rows loop
t(i) := i;
end loop;
return t;
end get_rows;
3) 使用 table( ... )
函数从您的函数中选择,将您的 number_tbl 对象转换为可选择的对象:
select * from table( cast ( get_rows( :b1 ) as number_tbl ) );
【讨论】:
【参考方案7】:connect by 真是太棒了。它可以帮助您使用双表中可用的一组数据生成多行。这可以帮助您为虚拟数据生成大量行。例如
insert into test select a.* from test1 a,(select * from dual connect by level <=100000) b;
或者你可以这样做
示例 2:您要打印 1 到 10 的正方形和立方体。
SQL> select level "No", power(level,2) "Square", power(level,3) "Cube" from dual connect by level <= 10;
No Square Cube
---------- ---------- ----------
1 1 1
2 4 8
3 9 27
4 16 64
5 25 125
6 36 216
7 49 343
8 64 512
9 81 729
10 100 1000
因此,您可以以任何您想要的形式对其进行操作。这就是您可以从双表返回多行的方式。 参考资料:http://www.oraclebin.com/2012/12/multipe-rows-from-dual-table.html
【讨论】:
【参考方案8】:另一种方法是使用 XQuery 范围表达式,例如:
select column_value from xmltable(:a||' to '||:b);
1
2
3
4
5
6
7
8
9
10
这个解决方案非常灵活,例如:
select column_value from xmltable('5 to 10, 15 to 20');
5
6
7
8
9
10
15
16
17
18
19
20
【讨论】:
【参考方案9】:WITH cte_numbers(n)
AS (
SELECT 0
UNION ALL
SELECT n + 1
FROM cte_numbers
WHERE n < 10
)
SELECT n
FROM cte_numbers;
返回的行 0 1 2 3 4 5 6 7 8 9 10
【讨论】:
【参考方案10】:取决于数据库,可以使用各种方法。
PostgreSQL 有一个不错的功能——series。
为了得到你想要的东西:
SELECT * FROM generate_series(1, NUM);
【讨论】:
我认为从“PL/SQL”和“双”表的提及中,他希望为 Oracle 提供解决方案。以上是关于SQL查询从双重返回N行的主要内容,如果未能解决你的问题,请参考以下文章
ORACLE SQL 查询从其他表中的行字符串匹配的行返回值