我需要通过一个SQL查询实现以下逻辑

时间:2018-08-30 11:43:21

标签: sql oracle

我有一个带有Tel_num列的master_table。 Tel_num是11位数的数据,如02365785431。现在,当数字按顺序排列时,我必须将min用作start_num,将max用作end_num并填充其关联的line_value。 如果出现以下情况:

Tel_num    Line_value
023158100001   V1
023158100002   V1
023158100003   V1
023158100004   V1 
023158115645   V2
023158111546   V2
023158111547   V2
023158111617   V2
023158121110   V3
023158121111   V3

然后我想要类似的数字

Start_NUM                    End_NUM         Line_Value
023158100001                023158100004        V1
023158115645                023158111547        V2
023158111617                023158111617        V2
023158121110                023158121111        V3

有人可以帮忙吗?

5 个答案:

答案 0 :(得分:1)

这是一种“群岛”问题。这是使用数字和行号之间的差异的解决方案

select line_value, min(tel_num), max(tel_num)
from (select t.*,
             ( cast(tel_num as number) -
               row_number() over (partition by line_value order by tel_num)
             ) as grp
      from t
     ) t
group by line_value, grp;

之所以有用,是因为当tel_num值是连续的时,从tel_num值中减去一个递增的序列会返回一个恒定值。

Here是一个学期。请注意,结果与问题中指定的结果不同,因为023158115645不应与任何其他数字组合。

答案 1 :(得分:0)

您可以使用lag()来使用累积方法:

select line_value, min(Tel_num), max(Tel_num)
from (select t.*, sum(case when grp > 1 then 1 else 0 end) over (partition by line_value, grp order by Tel_num) as grp1
      from (select t.*, coalesce(cast(Tel_num as number) - lag(Tel_num) over (partition by line_value order by Tel_num), 1) as grp
            from table t
           ) t
     ) t
group by line_value, grp1;

编辑:似乎您只希望对组成Tel_num进行分组,那么您只需要一个分组:

select line_value, min(Tel_num), max(Tel_num)
from (select t.*, coalesce(cast(Tel_num as number) - lag(Tel_num) over (partition by line_value order by Tel_num), 1) as grp
      from table t
     ) t
group by line_value, grp;

答案 2 :(得分:0)

CREATE TABLE number (vnum varchar(20), number numeric);

INSERT INTO number (vnum, number)
  SELECT 'v1', 023158100001 UNION ALL
  SELECT 'V1', 023158100002 UNION ALL
  SELECT 'V1', 023158100003 UNION ALL
  SELECT 'V1', 023158100004 UNION ALL
  SELECT 'v2', 023158115645  UNION ALL
  SELECT 'V2', 023158111546  UNION ALL
  SELECT 'V2', 023158111547  UNION ALL
  SELECT 'V2', 023158111617  UNION ALL
  SELECT 'V3', 023158121110  UNION ALL
  SELECT 'V3', 023158121111  UNION ALL
  SELECT 'V3', 023158121112;

SELECT min(number), start_num, max(number), end_num, vnum line_value FROM number GROUP BY vnum;

答案 3 :(得分:0)

您可以使用分层查询:

Oracle设置

CREATE TABLE master_table ( line_value, tel_num ) AS
  SELECT 'V1', '023158100001' FROM DUAL UNION ALL
  SELECT 'V1', '023158100002' FROM DUAL UNION ALL
  SELECT 'V1', '023158100003' FROM DUAL UNION ALL
  SELECT 'V1', '023158100004' FROM DUAL UNION ALL
  SELECT 'V2', '023158115645' FROM DUAL UNION ALL
  SELECT 'V2', '023158111546' FROM DUAL UNION ALL
  SELECT 'V2', '023158111547' FROM DUAL UNION ALL
  SELECT 'V2', '023158111617' FROM DUAL UNION ALL
  SELECT 'V3', '023158121110' FROM DUAL UNION ALL
  SELECT 'V3', '023158121111' FROM DUAL UNION ALL
  SELECT 'V3', '023158121112' FROM DUAL;

查询1

SELECT CONNECT_BY_ROOT( tel_num ) AS start_num,
       tel_num AS end_num,
       line_value
FROM   master_table m
WHERE  CONNECT_BY_ISLEAF = 1
START WITH NOT EXISTS (
         SELECT 1
         FROM   master_table p
         WHERE  m.line_value = p.line_value
         AND    TO_NUMBER( m.tel_num ) - 1 = TO_NUMBER( p.tel_num )
       )
CONNECT BY PRIOR line_value = line_value
AND    PRIOR TO_NUMBER( m.tel_num ) + 1 = TO_NUMBER( m.tel_num )
ORDER BY line_value, start_num;

输出

START_NUM    END_NUM      LINE_VALUE
------------ ------------ ----------
023158100001 023158100004 V1
023158111546 023158111547 V2
023158111617 023158111617 V2
023158115645 023158115645 V2
023158121110 023158121112 V3

答案 4 :(得分:0)

Oracle支持公用表表达式(CTE),因此您可以这样做:

with ranked as (
    select Line_Value, Tel_Num, 
        row_number() over (partition by Line_value order by Tel_Num) as rowNum
    from master_table
)
, lastRow as (
    select Line_Value, max(rowNum) as lastRow
    from ranked
    group by Line_Value
)
select fn.Tel_Num, ln.Tel_Num, fn.Line_Value
from ranked fn
inner join ranked ln on fn.Line_Value = ln.Line_value
inner join lastRow lr on ln.Line_Value = lr.Line_Value and ln.rowNum = lr.lastRow
where fn.rowNum = 1
order by fn.Line_Value

说明:

  • 为每个Line_Value排序Tel_Num(升序),并为其分配行号
  • 找到每个Line_Value的最后一个rowNum值
  • 最终输出将是这些的综合
    • 排名,其中rowNum = 1,将为您提供该Line_Value的第一个Tel_Num
      • 我将其别名为fn表示第一个数字
    • 排名,加入lastRow,将为您提供该Line_Value的最后一个Tel_Num
      • 我将别名别名为ln表示最后一个数字
  • 您需要通过Line_Value将所有这些连接起来,这样我们每个Line_Value都会得到一个输出行
  • 您希望它按Line_Value排序