【问题标题】:How to fill a range of all values between Min and Max in SQL query?如何在 SQL 查询中填充 Min 和 Max 之间的所有值的范围?
【发布时间】:2015-10-21 01:53:26
【问题描述】:

我有以下看法:

select v.* from myview v;

PeriodID | StartMonth | EndMonth
102      |          1 |        4
103      |          3 |        7
104      |          4 |        11

我需要将此视图与此查询(另一个视图)混合。

select q.* from query q;

Somevalue| AnotherValue| PeriodId
   'abc' |         546 |      102
   'xyz' |         147 |      103
   'bnm' |         652 |      104

我需要:

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

如果我可以从startmonth to endmonth 获得一个集合并与 q 一起加入它,也许我可以得到我需要的。

来自:

PeriodID | StartMonth | EndMonth
102      |          1 |        4
103      |          3 |        7
104      |          4 |        11

收件人:

PeriodID |      Month
102      |          1
102      |          2
102      |          3
102      |          4

【问题讨论】:

    标签: sql oracle join collections plsql


    【解决方案1】:

    我更改了名称以使查询更清晰

    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
    

    【讨论】:

      【解决方案2】:
      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
      

      你可以用数字和join 将它构建到你的表中。

      【讨论】:

        【解决方案3】:

        给出相同结果的两种解决方案:

        SQL Fiddle

        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;
        

        查询 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
        

        查询 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 )
        

        Results

        | 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 |
        

        【讨论】:

          【解决方案4】:

          这是您问题的答案。

          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
          

          检查此SQLFiddle 并尝试根据您的情况进行调整。它肯定会奏效。

          快乐编码

          【讨论】:

          • 问题标记为 Oracle,这对于 Oracle 来说是无效的 SQL。它看起来像是 SQL Server 的答案。
          • 这里为 sql 附加了标签,并且我没有看到任何与 Oracle 相关的词。很抱歉给您带来不便
          • 即使它被only标记为sql,你的回答也是“错误的”。标签sql 代表查询语言 SQL,not 代表特定的DBMS 产品。您的代码不是 ANSI SQL。 SQL Server 的问题将用sql-server 标记。这个问题从一开始就被标记为oracle(即使是plsql而不是t-sql
          猜你喜欢
          • 1970-01-01
          • 2021-11-15
          • 1970-01-01
          • 2021-05-28
          • 1970-01-01
          • 1970-01-01
          • 2021-09-04
          • 1970-01-01
          • 2015-04-29
          相关资源
          最近更新 更多