我有一个oracle表,其结构类似于:
School {
Student_Id,
Student_Name,
Class,
Sport,
Club
}
我想写一个查询来获取所有属于X班、Y运动或Z俱乐部的学生。
但我想根据OR条件的顺序对结果进行排序。
也就是说,所有属于X班的学生都将排在第一位,排在Y体育的学生之前。然后Z俱乐部的学生会来。
此外,没有重复的结果。如果约翰是来自X班的话;也属于运动Y,那么他应该只出现一次,并且在运动Y的所有结果之上。
这就是我理解问题的方式:
SQL> with school (student_name, class, sport, club) as
2 (select 'Scott', 'x', 'a', 'c' from dual union all
3 select 'Mike' , 'b', 'c', 'z' from dual union all
4 select 'Kate' , 'x', 'y', 'z' from dual union all
5 select 'John' , 'x', 'b', 'd' from dual union all
6 select 'Vito' , 'd', 'e', 'g' from dual
7 )
8 select * from school
9 where class = 'x' or sport = 'y' or club = 'z'
10 order by case when class = 'x' then 1 end,
11 case when sport = 'y' then 2 end,
12 case when club = 'z' then 3 end;
STUDENT CLASS SPORT CLUB
------- ----- ----- -----
Kate x y z
Scott x a c
John x b d
Mike b c z
SQL>
如果不是这样,请公布样本数据和预期结果。
我会把它写成:
select s.*
from school s
where class = 'X' or sport = 'Y' or club = 'Z'
order by (case when class = 'X' then 1
when sport = 'Y' then 2
when club = 'Z' then 3
end)
如果不想重复这些条件,可以使用子查询、CTE,或者在Oracle12C中使用横向连接:
select s.*
from school s cross join lateral
(select (case when class = 'X' then 1
when sport = 'Y' then 2
when club = 'Z' then 3
end) as ord
from dual
) x
where x.ord is not null
order by x.ord
select student_id
, case when class='X' then 1
when sport = 'Y' then 2
when club='Z' then 3
else 4
end as Ordr
from School
WHERE class='X' or sport = 'Y' or club='Z'
Order by ordr
解释:
WHERE class='X' or sport = 'Y' or club='Z'
只需实现您想要的过滤。
自定义排序是通过创建一个名为ordr
的附加列并在ORDER BY
子句中使用它来实现的。此列是使用case语句创建的。它的编写顺序很重要,因为CASE表达式的计算结果是第一个true条件,若并没有true条件,它的计算结果就是ELSE部分。
因此,所有参加X班的学生都将获得1的分数,无论他们的运动和俱乐部如何。
如果一个学生没有参加X类,表达式将尝试评估该学生是否参加了运动Y,如果是这样,则无论其他列值如何,该学生都将获得2的排序。
然后,如果该学生既没有参加X班,也没有参加Y运动,则case表达式将检查该学生是否在Z俱乐部。如果这是真的,则他将获得3的排序。
最后,如果一个学生既不在X班,也不参加Y运动,也不在Z俱乐部,他将被分配4的顺序。
默认情况下,ORDER BY
是ASCENDING
,意味着1将出现在2之前,依此类推
通过上面的解释,你可以看出这个算法没有做的是,优先考虑参加X班、Y运动、Z俱乐部的学生,而不是只参加X班的学生。