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) 因为每个值不是相互连续的。
- poin_max F 级应为 9。
- poin_min B 级应为 70。
但是,如果该值始终是一个序列,那么我的查询 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不正好低于当前最小值。
我有一个名为 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) 因为每个值不是相互连续的。
- poin_max F 级应为 9。
- poin_min B 级应为 70。
但是,如果该值始终是一个序列,那么我的查询 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不正好低于当前最小值。