我有一张名为GRADE的表,其中包含GRADE_NAME,POIN_FROM,POIN_TO列。 GRADE表如下所示:
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包含如上所述的值,则我的查询应返回1(false),因为每个值不是相互顺序的。
但是,如果值始终是一个序列,那么我的查询返回0(true)。
这就是我的尝试:
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 ,但该值不一定是序列。
我正在使用oracle,但如果有人知道如何用另一个dbms解决这个问题请分享,这将非常有帮助。
ps:此表的行是动态的。用户可以为grade_name添加一些ROW,如G,H等,但poin_min和poin_max总是0到100。
谢谢,
鲁巴马拉姆
答案 0 :(得分:1)
一个选项是将每个范围扩展为各个值,您可以使用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的外部联接可以让您看到任何不应该丢失,重复或存在的CTE。例如,如果你改为A 90-101的范围,它也会报告:
101 1 A A
SQL Fiddle包括101的范围;虽然你希望已经对有效值的范围有一个约束,所以你不能在第一时间创建这样的记录。 another Fiddle其中值是连续的。
答案 1 :(得分:1)
这是一个关于窗口函数的想法:使用上一行和下一行的poin_max
创建一个CTE(按poin_min
排序),然后运行检查:
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;如果前一个最大值为n,则最后一列为1恰好低于当前最小值。