Encuentra el número anterior en la columna que no falta en una secuencia

Aug 18 2020

Tengo una tabla con una columna que debe contener números en una secuencia completa, por simplicidad diremos 101 a 110. Sin embargo, esta tabla se basa en información poco confiable para ser ingresada manualmente, por lo que los números en la secuencia se pierden. También hay una columna de fecha en la misma tabla a la que debo hacer referencia, más sobre eso en un momento. Se me ha desafiado a encontrar todos los números de secuencia que faltan junto con el número de secuencia anterior que se ingresó, la fecha en que se ingresó y el siguiente número de secuencia con la fecha en que se ingresó. Encontrar los números de secuencia que faltan es sencillo, es obtener los registros relevantes anteriores y siguientes con los que estoy luchando. Entonces, si mis datos se veían así;

table, th, td {
  border: 1px solid black;
  border-collapse: collapse;
}
<html>

<body>
  <table>
    <tr>
      <th>Seq No</th>
      <th>Date Input</th>
    </tr>
    <tr>
      <td>101</td>
      <td>01-JAN-20</td>
    </tr>
    <tr>
      <td>102</td>
      <td>05-JAN-20</td>
    </tr>
    <tr>
      <td>104</td>
      <td>07-JAN-20</td>
    </tr>
    <tr>
      <td>105</td>
      <td>08-JAN-20</td>
    </tr>
    <tr>
      <td>106</td>
      <td>09-JAN-20</td>
    </tr>
    <tr>
      <td>108</td>
      <td>10-JAN-20</td>
    </tr>
    <tr>
      <td>109</td>
      <td>11-JAN-20</td>
    </tr>
    <tr>
      <td>110</td>
      <td>12-JAN-20</td>
    </tr>
  </table>
</body>

</html>

Mi conjunto de resultados se vería así;

table, th, td {
  border: 1px solid black;
  border-collapse: collapse;
}
<html>
<body>
  <table>
    <tr>
      <th>Missing Seq No</th>
      <th>Previous Date</th>
      <th>Next Date</th>
      <th>Notes</th>
    </tr>
    <tr>
      <td>103</td>
      <td>05-JAN-20</td>
      <td>07-JAN-20</td>
      <td>Dates from found seq nos 102 and 104</td>
    </tr>
    <tr>
      <td>107</td>
      <td>09-JAN-20</td>
      <td>10-JAN-20</td>
      <td>Dates from found seq nos 106 and 108</td>
    </tr>
  </table>
</body>
</html>

Pero sin la columna de notas, está ahí para mayor claridad.

Puedo llegar a una respuesta, pero el sql es tan grande y difícil de manejar que es casi inútil. Gracias.

Respuestas

2 GMB Aug 18 2020 at 21:01

Si desea una fila por espacio, puede usar las funciones de ventana:

select 
    lag_seq_no last_sequence_number,
    lag_date_input last_date_input,
    seq_no next_sequence_number,
    date_input next_date_input
from (
    select 
        t.*,
        lag(seq_no) over(order by date_input) lag_seq_no,
        lag(date_input) over(order by date_input) lag_date_input
    from mytable t
) t
where seq_no > lag_seq_no + 1

Por otro lado, si tiene números que faltan consecutivos y desea una fila para cada uno, entonces necesita algún tipo de recursividad:

with 
    data(seq_no, date_input, lag_seq_no, lag_date_input) as (
        select 
            t.*,
            lag(seq_no) over(order by date_input) lag_seq_no,
           lag(date_input) over(order by date_input) lag_date_input
        from mytable t
    ),
    cte (seq_no, date_input, lag_seq_no, lag_date_input) as (
        select seq_no, date_input, lag_seq_no + 1, lag_date_input
        from data
        where seq_no > lag_seq_no + 1
        union all
        select seq_no, date_input, lag_seq_no + 1, lag_date_input
        from cte
        where seq_no > lag_seq_no + 1
) 
select 
    lag_seq_no missing_seq_no,
    lag_date_input last_date_input,
    date_input next_date_input
from cte