我有一张看起来像这样的表
IDNUM | Name | LowRange | HighRange | Notes
123 | TESTS | 100 | 201 | Hello
124 | TEST2 | 200 | 210 |
125 | TESTS | 100 | 201 | Hello
我想知道是否有一个会返回以下结果的查询
IDNUM | Name | Number | Notes
123 | TESTS | 100 | Hello
123 | TESTS | 101 | Hello
123 | TESTS | 102 | Hello
123 | TESTS | 103 | Hello
......til 201
124 | TEST2 | 200 |
124 | TEST2 | 201 |
124 | TEST2 | 202 |
......til 210
我正在寻找在SQL Server 2016和Oracle 11g中执行此操作的方法,但任何一方的帮助都将受到赞赏
答案 0 :(得分:2)
最简单的方法是数字表。以下内容适用于Oracle和SQL Server - 假设“数字”的基表足够大:
with numbers as (
select row_number() over (order by idnum) - 1 as n
from t
)
select idnum, name, lowrange + n.n as number, notes
from t join
numbers n
on lowrange + n.n <= highrange;
如果上述内容无法生成足够的数字,您可以在CTE中使用cross join
来获取更多数据。
每个数据库都有其他生成数字的方法,但这适用于两个数据库。
答案 1 :(得分:2)
Oracle分层查询:
SELECT t.IDNUM,
t.Name,
n.COLUMN_VALUE AS "Number",
t.Notes
FROM your_table t
CROSS JOIN
TABLE(
CAST(
MULTISET(
SELECT t.LowRange + LEVEL - 1
FROM DUAL
CONNECT BY t.LowRange + LEVEL - 1 < t.HighRange
) AS SYS.ODCINUMBERLIST
)
) n;
递归子查询保理条款:
WITH numbers ( IDNUM, Name, LowRange, HighRange, Notes ) AS (
SELECT IDNUM, Name, LowRange, HighRange, Notes
FROM your_table
UNION ALL
SELECT IDNUM, Name, LowRange + 1, HighRange, Notes
FROM numbers
WHERE LowRange < HighRange
)
SELECT IDNUM,
Name,
LowRange AS "Number",
Notes
FROM numbers;
答案 2 :(得分:0)
一种方法是使用this accepted answer中的代码并使用以下内容:
DECLARE @startnum INT
DECLARE @endnum INT
SELECT @startnum = MIN(LowRange) ,
@endnum = MAX(HighRange)
FROM IDsAndRanges
;
WITH gen AS (
SELECT @startnum AS num
UNION ALL
SELECT num+1 FROM gen WHERE num+1<=@endnum
)
SELECT *
FROM [IDsAndRanges] I
LEFT
JOIN gen G
ON G.num BETWEEN I.LowRange AND I.HighRange
option (maxrecursion 10000)
这是使用以下测试工具编写的:
CREATE TABLE [IDsAndRanges]
(
IDNUM [INT],
Name NVARCHAR(100),
LowRange INT,
HighRange INT,
Notes NVARCHAR(100)
)
INSERT
INTO [IDsAndRanges]
(
IDNUM, Name, LowRange, HighRange, Notes
)
VALUES (123, 'TESTS', 100, 201, 'Hello'),
(124, 'TEST2', 200, 210, ''),
(125, 'TESTS', 100, 201, 'Hello')
答案 3 :(得分:0)
您可以将此作为递归的with子句(也称为递归CTE),如下所示:
WITH main_data (idnum, NAME, NUM, highrange, notes) AS (SELECT idnum,
NAME,
lowrange NUM,
highrange,
notes
FROM sample_data
UNION ALL
SELECT idnum,
NAME,
NUM + 1 NUM,
highrange,
notes
FROM main_data
WHERE NUM < highrange)
SELECT idnum,
NAME,
NUM,
notes
FROM main_data
ORDER BY idnum, NUM;
IDNUM NAME NUM NOTES
---------- ----- ---------- -----
123 TESTS 100 Hello
123 TESTS 101 Hello
123 TESTS 102 Hello
123 TESTS 103 Hello
124 TEST2 200
124 TEST2 201
124 TEST2 202
124 TEST2 203
124 TEST2 204
125 TESTS 150 Hello
125 TESTS 151 Hello
125 TESTS 152 Hello
125 TESTS 153 Hello
125 TESTS 154 Hello
125 TESTS 155 Hello
125 TESTS 156 Hello
125 TESTS 157 Hello
125 TESTS 158 Hello
125 TESTS 159 Hello
125 TESTS 160 Hello
以上查询在Oracle中工作(我相信它也应该在SQL Server中工作)基于以下示例数据:
SELECT 123 idnum, 'TESTS' NAME, 100 lowrange, 103 highrange, 'Hello' notes FROM dual UNION ALL
SELECT 124 idnum, 'TEST2' NAME, 200 lowrange, 204 highrange, NULL notes FROM dual UNION ALL
SELECT 125 idnum, 'TESTS' NAME, 150 lowrange, 160 highrange, 'Hello' notes FROM dual
答案 4 :(得分:0)
也许不是一个好方法,但它对我有用;
CREATE TYPE shin.tab_rows AS OBJECT (
idnum NUMBER,
description VARCHAR2(50),
num_ber NUMBER,
notes VARCHAR2(50)
);
/
CREATE TYPE shin.test_tab IS TABLE OF shin.tab_rows;
/
CREATE OR REPLACE FUNCTION shin.get_numbers
RETURN shin.test_tab PIPELINED AS
BEGIN
for records in (select IDNUM,lowrange,highrange,name,notes from shin.test_stack) LOOP
FOR num_ber IN records.lowrange..records.highrange LOOP
PIPE ROW(shin.tab_rows(records.IDNUM, records.name,num_ber,records.notes));
END LOOP;
END LOOP;
RETURN;
END;
/
select * from table(shin.get_numbers)