SQL 查询以检查始终继续的列

SQL Query to checks on the column that always continue

我有一个名为 GRADE 的 table 并且有列 GRADE_NAME、POIN_FROM、POIN_TO。 等级 table 看起来像这样:

GRADE_NAME        POIN_MIN       POIN_MAX
A                      90           100
B                      75            89
C                      50            69
D                      30            49
E                      10            29
F                       0            10

现在,我想编写一个 sql 查询来检查 poin_min 和 poin_max 列中的所有值是否有效。 在这种情况下,如果 poin_min 和 poin_max 包含上述值,我的查询应该 return 1 (false) 因为每个值不是相互连续的。

但是,如果该值始终是一个序列,那么我的查询 return 0(真)。

这是我试过的:

SELECT CASE WHEN SUM(CEK) = 100 THEN '0' ELSE '1' END AS RESULT
FROM (
    SELECT POIN_MAX - POIN_MIN AS CEK
    FROM GRADE
    ORDER BY GRADE_NAME ASC
)

如您所见,这是行不通的。因为虽然SUM(CEK) = 100,但是数值不一定是sequence.

我正在使用 oracle,但如果有人知道如何使用其他 dbms 解决此问题,请分享,这将非常有帮助。

ps :此 table 的行是动态的。用户可以为 grade_name 添加一些 ROW,例如 G、H 等,但 poin_min 和 poin_max 始终为 0 到 100。

谢谢,

鲁巴马拉姆

一个选项是将每个范围扩展为其单独的值,您可以使用 recursive subquery factoring(在 11GR2 或更高版本中);然后查看所有年级的总体列表。例如,仅针对 F:

with r (grade_name, poin, poin_max) as (
  select grade_name, poin_min, poin_max
  from grade
  union all
  select r.grade_name, r.poin + 1, r.poin_max
  from r
  where r.poin < r.poin_max
)
select grade_name, poin
from r
where grade_name = 'F';

GRADE_NAME       POIN
---------- ----------
F                   0 
F                   1 
F                   2 
F                   3 
F                   4 
F                   5 
F                   6 
F                   7 
F                   8 
F                   9 
F                  10 

要查看是否存在任何差异,您可以比较各种计数:

with r (grade_name, poin, poin_max) as (
  select grade_name, poin_min, poin_max
  from grade
  union all
  select r.grade_name, r.poin + 1, r.poin_max
  from r
  where r.poin < r.poin_max
)
select count(poin), count(distinct poin), min(poin), max(poin)
from r
having count(poin) != 101
or count(distinct poin) != 101
or min(poin) != 0
or max(poin) != 100;

COUNT(POIN) COUNT(DISTINCTPOIN)  MIN(POIN)  MAX(POIN)
----------- ------------------- ---------- ----------
         97                  96          0        100 

或者如果您只想要原始的 0/1 结果:

with r (grade_name, poin, poin_max) as (
  select grade_name, poin_min, poin_max
  from grade
  union all
  select r.grade_name, r.poin + 1, r.poin_max
  from r
  where r.poin < r.poin_max
)
select case when count(poin) != 101 or count(distinct poin) != 101
  or min(poin) != 0 or max(poin) != 100 then 1 else 0 end as result
from r;

    RESULT
----------
         1 

你也可以更大胆一点,报告实际的问题值:

with r (grade_name, poin, poin_max) as (
  select grade_name, poin_min, poin_max
  from grade
  union all
  select r.grade_name, r.poin + 1, r.poin_max
  from r
  where r.poin < r.poin_max
),
n as (
  select level - 1 as poin from dual
  connect by level <= 101
)
select coalesce(n.poin, r.poin),
  count(r.poin), min(r.grade_name), max(r.grade_name)
from n
full outer join r on r.poin = n.poin
group by coalesce(n.poin, r.poin)
having count(r.poin) != 1
or count(n.poin) != 1
order by coalesce(n.poin, r.poin);

COALESCE(N.POIN,R.POIN) COUNT(R.POIN) MIN(R.GRADE_NAME) MAX(R.GRADE_NAME)
----------------------- ------------- ----------------- -----------------
                     10             2 E                 F                 
                     70             0                                     
                     71             0                                     
                     72             0                                     
                     73             0                                     
                     74             0                                     

这里 n 是另一个 CTE,它只生成所有预期的有效值,递归 CTE 的外部连接让您可以看到任何缺失、重复或不应该存在的值.例如,如果您将 A 的范围改为 90-101,它还会报告:

                    101             1 A                 A                 

SQL Fiddle including a range with 101; although you'd hopefully already have a constraint on the range of valid values so you wouldn't be able to create a record like that in the first place. And another Fiddle 其中值是连续的。

这是一个关于窗口函数的想法:使用上一行和下一行的 poin_max(按 poin_min 排序)创建一个 CTE,然后 运行 你的检查:

with my_grade as (
select
  lead(poin_max) over (order by poin_min) next_max
, lag(poin_max) over (order by poin_min) prev_max
, poin_min
, poin_max
from grade
)
select
  case when prev_max is null and poin_min <> 0 then 1 else 0 end min_error
, case when next_max is null and poin_max <> 100 then 1 else 0 end max_error
, case when prev_max is not null and poin_min <> prev_max + 1 then 1 else 0 end step_error
, poin_min, poin_max
, prev_max, next_max
from my_grade;

如果最小值不为零,您将在 min_error 中得到 1,如果最大值不为 100,则在 max_error 中得到 1,如果前一个最大值在最后一列中得到 1不正好低于当前最小值。