Oracle SQL从表中查找连续的(至少5个)可用数字

时间:2018-10-09 14:33:42

标签: sql oracle

要求是在一个状态分别为“ Available”,“ Reserved”,“ Disconnected”等不同状态的数字表中进行搜索,以查找仅“ Available”连续且至少连续50个数字每次,并返回那些。 示例数据:

Number State
124    "Reserved"
125    "Available"
126    "Available"
127    "Disconnected"
128    "Available"
129    "Available"
130    "Available"
131    "Available"
132    "Available"
133    "Reserved"
.
.
.

因此,在上述情况下,至少应该返回128-132,因为它们是5个“可用”数字。然后,下一个连续的“可用”可能是7或10或15,一旦它们等于或大于5,也应该返回它们。 希望要求很明确。 谢谢。

4 个答案:

答案 0 :(得分:1)

如果您使用的是Oracle 12.1或更高版本,则Vamsi Prabhala的Answer中的TextView解决方案可能是最有效的。

对于较旧的版本,使用固定差异(又称为Tabibitosan)方法的解决方案可能是最好的。我会显示每个序列的计数(尽管严格来说您可能不需要)。

match_recognize

输出:

with
  sample_data as (
    select 124 as num, 'Reserved' as state     from dual union all
    select 125       , 'Available'             from dual union all
    select 126       , 'Available'             from dual union all
    select 127       , 'Disconnected'          from dual union all
    select 128       , 'Available'             from dual union all
    select 129       , 'Available'             from dual union all
    select 130       , 'Available'             from dual union all
    select 131       , 'Available'             from dual union all
    select 132       , 'Available'             from dual union all
    select 133       , 'Reserved'              from dual union all
    select 135       , 'Troubled'              from dual union all
    select 136       , 'Taken'                 from dual union all
    select 137       , 'Available'             from dual union all
    select 138       , 'Available'             from dual union all
    select 139       , 'Available'             from dual union all
    select 140       , 'Available'             from dual union all
    select 141       , 'Available'             from dual union all
    select 142       , 'Available'             from dual
  )
select   num, ct
from     (
           select num, count(*) over (partition by grp) ct
           from   (
                    select num, num - row_number() over (order by num) as grp
                    from   sample_data
                    where  state = 'Available'
                  )
         )
where    ct >= 5
order by num
;

答案 1 :(得分:0)

一种方法使用了很多延迟:

select t.*
from (select t.*,
             lag(state, 1) over (order by number) as state_1,
             lag(state, 2) over (order by number) as state_2,
             lag(state, 3) over (order by number) as state_3,
             lag(state, 4) over (order by number) as state_4
      from t
     ) t
where state = 'Available' and state_1 = state and state_2 = state and state_3 = state and state_4 = state;

这仅返回5(及其后的行),但是很容易找出较早的行。

考虑到这一点,有一种更简单的方法:

select t.*
from (select t.*,
             lag(number, 4) over (partition by state order by number) as number_state_4
      from t
     ) t
where state = 'Available' and
      number_state_4 = number - 4;

这是说'Available'的第四行是当前行减去4-或连续有5个“可用”。

当然,您也可以将其视为间隙和孤岛:

select state, min(number), max(number)
from (select t.*,
             row_number over (partition by state order by number) as seqnum
      from t
     ) t
where state = 'Available' 
group by state, number - seqnum
having count(*) >= 5

答案 2 :(得分:0)

如果您使用的是Oracle 12c版,则可以使用match_recognize,它会进行模式匹配以获取具有指定模式的行。

select *
from tbl
MATCH_RECOGNIZE (
         ORDER BY "number"
         ALL ROWS PER MATCH
         AFTER MATCH SKIP TO LAST AVAILABLE
         PATTERN(available{5,})
         DEFINE 
         available AS (status='Available')
       ) MR
ORDER BY "number"

答案 3 :(得分:0)

如果可以帮助您,则可以通过PLsql块轻松完成此操作:

Sub UpdateAllChartLines()

    Dim sht As Worksheet
    Dim chtObj As ChartObject
    Dim ser As Series
    Dim clr As Long

    Application.ScreenUpdating = False

    With Worksheets("TextElements")
        clr = RGB(.Range("K6").Value, .Range("K7").Value, .Range("K8").Value)
        myThickness = .Range("K9").Value
    End With

    For Each sht In ActiveWorkbook.Worksheets
        If sht.Name <> "Sheet1" Then '<<< can exclude sheets here
        If sht.Name <> "Sheet2" Then
            For Each chtObj In sht.ChartObjects
                For Each ser In chtObj.Chart.SeriesCollection
                        If ser.Name <> "Series1" Then
                        If ser.Name <> "Series2" Then
                        If ser.Name <> "Series3" Then
                        If ser.Name <> "Series4" Then
                            With ser
                                .MarkerStyle = xlMarkerStyleNone
                                .Format.Line.Visible = msoTrue
                                .Format.Line.ForeColor.RGB = clr
                                .Format.Line.Weight = myThickness
                                .Format.Glow.Radius = 0
                            End With
                        End If
                        End If
                        End If
                        End If
                Next ser
            Next chtObj
        End If
        End If
    Next sht

    Application.ScreenUpdating = True

End Sub