[英]How to fill a range of all values between Min and Max in SQL query?
I have the following view: 我有以下观点:
select v.* from myview v;
PeriodID | StartMonth | EndMonth
102 | 1 | 4
103 | 3 | 7
104 | 4 | 11
And I need to mix this view with this query (another view). 我需要将此视图与此查询(另一个视图)混合使用。
select q.* from query q;
Somevalue| AnotherValue| PeriodId
'abc' | 546 | 102
'xyz' | 147 | 103
'bnm' | 652 | 104
I need: 我需要:
Somevalue| AnotherValue| PeriodId | Month
'abc' | 546 | 102 | 1
'abc' | 546 | 102 | 2
'abc' | 546 | 102 | 3
'abc' | 546 | 102 | 4
'xyz' | 147 | 103 | 3
'xyz' | 147 | 103 | 4
'xyz' | 147 | 103 | 5
'xyz' | 147 | 103 | 6
'xyz' | 147 | 103 | 7
If I can get a collection from startmonth to endmonth
and join it with q, maybe I could get what I need. 如果我可以从
startmonth to endmonth
获得一个集合,并与q startmonth to endmonth
加入,也许我可以得到我所需要的。
from: 从:
PeriodID | StartMonth | EndMonth
102 | 1 | 4
103 | 3 | 7
104 | 4 | 11
to: 至:
PeriodID | Month
102 | 1
102 | 2
102 | 3
102 | 4
I changed names to make query clearer 我更改了名称以使查询更清晰
myview --> periods_table
query --> values_table
SELECT vl.*
,pr.month
FROM (SELECT periodid AS periodid
,LEVEL AS month
FROM periods_table t
WHERE LEVEL >= t.startmonth
GROUP BY periodid, LEVEL
CONNECT BY LEVEL <= t.endmonth) pr
, values_table vl
WHERE pr.periodid = vl.periodid
ORDER BY pr.periodid, pr.month
with t as (select 1 monthid from dual union all select 2 from dual
...)
select q.somevalue, q.anothervalue, m.periodid, t.monthid
from t
join myview m on t.monthid between m.startmonth and m.endmonth
join q on q.periodid = m.periodid
You can construct a months table with numbers and join
it to your table. 您可以用数字构造一个月表并将其
join
到表中。
Two solutions to give the same result: 给出相同结果的两种解决方案:
Oracle 11g R2 Schema Setup : Oracle 11g R2架构设置 :
CREATE TABLE myview ( PeriodID, StartMonth, EndMonth ) AS
SELECT 102, 1, 4 FROM DUAL
UNION ALL SELECT 103, 3, 7 FROM DUAL
UNION ALL SELECT 104, 4, 11 FROM DUAL;
CREATE TABLE query ( Somevalue, AnotherValue, PeriodId ) AS
SELECT 'abc', 546, 102 FROM DUAL
UNION ALL SELECT 'xyz', 147, 103 FROM DUAL
UNION ALL SELECT 'bnm', 652, 104 FROM DUAL;
Query 1 - Using Recursive Subquery Factoring : 查询1-使用递归子查询分解 :
WITH Periods ( PeriodID, Month, EndMonth ) AS (
SELECT PeriodID, StartMonth, EndMonth
FROM myview
WHERE StartMonth <= EndMonth
UNION ALL
SELECT PeriodID, Month + 1, EndMonth
FROM Periods
WHERE Month < EndMonth
)
SELECT p.PeriodID,
q.SomeValue,
q.AnotherValue,
p.Month
FROM Periods p
INNER JOIN
Query q
ON ( p.PeriodID = q.PeriodID )
ORDER BY PeriodID, Month
Query 2 - Using a Hierarchical Query : 查询2-使用分层查询 :
WITH Periods ( PeriodID, Month ) AS (
SELECT m.PeriodID,
t.COLUMN_VALUE
FROM myview m,
TABLE(
CAST(
MULTISET(
SELECT m.StartMonth + LEVEL - 1
FROM DUAL
CONNECT BY m.StartMonth + LEVEL - 1 <= m.EndMonth
)
AS SYS.ODCINUMBERLIST
)
) t
)
SELECT p.PeriodID,
q.SomeValue,
q.AnotherValue,
p.Month
FROM Periods p
INNER JOIN
Query q
ON ( p.PeriodID = q.PeriodID )
| PERIODID | SOMEVALUE | ANOTHERVALUE | MONTH |
|----------|-----------|--------------|-------|
| 102 | abc | 546 | 1 |
| 102 | abc | 546 | 2 |
| 102 | abc | 546 | 3 |
| 102 | abc | 546 | 4 |
| 103 | xyz | 147 | 3 |
| 103 | xyz | 147 | 4 |
| 103 | xyz | 147 | 5 |
| 103 | xyz | 147 | 6 |
| 103 | xyz | 147 | 7 |
| 104 | bnm | 652 | 4 |
| 104 | bnm | 652 | 5 |
| 104 | bnm | 652 | 6 |
| 104 | bnm | 652 | 7 |
| 104 | bnm | 652 | 8 |
| 104 | bnm | 652 | 9 |
| 104 | bnm | 652 | 10 |
| 104 | bnm | 652 | 11 |
Here is the answer of your question. 这是您问题的答案。
DECLARE @TABLE1 TABLE
(
PERIODID INT,
STARTMONTH INT,
ENDMONTH INT
)
DECLARE @TABLE2 TABLE
(
SOMEVALUE VARCHAR(20),
ANOTHERVALUE INT,
PERIODID INT
)
INSERT INTO @TABLE1 VALUES (102,1,3)
INSERT INTO @TABLE1 VALUES (103,3,7)
INSERT INTO @TABLE2 VALUES ('ABC',123,102)
INSERT INTO @TABLE2 VALUES ('BCD',234,103)
;WITH cte
AS (SELECT PERIODID, STARTMONTH [MONTH],ENDMONTH
FROM @TABLE1
UNION ALL
SELECT PERIODID, [MONTH] + 1,ENDMONTH
FROM cte
WHERE [MONTH] < ENDMONTH)
SELECT T2.SOMEVALUE,T2.ANOTHERVALUE, CTE.PERIODID,CTE.[MONTH] FROM CTE
INNER JOIN @TABLE2 T2 ON CTE.PERIODID = T2.PERIODID
ORDER BY CTE.PERIODID,CTE.MONTH
Check this SQLFiddle out and try to fit according to your scenario. 检查此SQLFiddle并尝试根据您的情况进行调整。 It will surely works.
它肯定会工作。
Happy Coding 快乐编码
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.