2017-07-14 52 views
0

我有一個表,看起來像這樣SQL生成由

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中都做到這一點的方法,但任何一方的幫助將不勝感激

+2

這是超級簡單的使用理貨表。 http://www.sqlservercentral.com/articles/T-SQL/62867/這適用於Oracle以及sql服務器(儘管您必須構建它有點不同)。然後,您從您的表中選擇並加入您的理貨表,其中tally.N> = LowRange和tally.N <= HighRange。 –

+0

看起來好像是一個Numbers表格(只是一個列中有整數的表格)。加入> = LowRange和<= HighRange。 –

回答

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; 

如果上面沒有產生足夠的號碼,你可以使用cross join S IN的CTE得到更多。

每個數據庫都有其他生成數字的方法,但是這在兩個數據庫中都適用。

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<[email protected] 
) 

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') 
0

你可以做到這一點作爲一個遞歸與 - 子句(又名遞歸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中工作(我相信

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 
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; 
0
也應該在SQL Server基於下面的示例數據工作)

也許不是一個好方法,但它適用於我;

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)