SQL 动态计算的百分比
SQL Percentage calculated dynamically
如何在SQL中动态计算百分比?
假设您有一个名为 Classes
的关注 table:
ClassSession StudentName
---------------------------------
Evening Ben
Morning Chris
Afternoon Roger
Evening Ben
Afternoon Ben
Morning Roger
Morning Ben
Afternoon Chris
假设 Ben
,我预计
Evening = 50 %
Afternoon = 25%
Morning = 25%
我期待克里斯
Morning = 50%
Afternoon = 50%
Evening = 0 %
所以ClassSession
(三个session)应该是比较不变的
到目前为止,我已经尝试了以下 SQL 语句:
Select
ClassSession,
(Count(ClassSession) * 100 / (Select Count(*) From Classes)) as Percentage
From
Classes
Where
StudentName = 'Chris'
Group By
ClassSession
一种方法使用条件聚合和 window 函数:
Select ClassSession,
(sum(case when StudentName = 'Chris' then 100.0 else 0 end) /
sum(sum(case when StudentName = 'Chris' then 100.0 else 0 end)) over ()
) as Percentage
From Classes
Group By ClassSession;
这将确保出现零的事件。
困难的部分是让零出现在给定会话中没有任何 类 的学生。
这是 PARTITION
外连接的作业。
select c.studentname,
s.classsession,
round(ratio_to_report(count(c.classsession))
over ( partition by c.studentname),2) pct
from c partition by ( studentname )
right outer join ( SELECT distinct classsession from c ) s
on s.classsession = c.classsession
group by c.studentname, s.classsession
order by c.studentname, s.classsession;
注意联接中的 PARTITION
关键字。这告诉 Oracle 为每个分区执行外部连接。因此,如果给定的 studentname
没有 classsession
,请为该学生添加它。
此外,ratio_to_report
是计算百分比的好函数。
这是一个完整的示例,其中包含数据:
with c (ClassSession, StudentName) AS (
SELECT 'Evening', 'Ben' FROM DUAL UNION ALL
SELECT 'Morning', 'Chris' FROM DUAL UNION ALL
SELECT 'Afternoon', 'Roger' FROM DUAL UNION ALL
SELECT 'Evening', 'Ben' FROM DUAL UNION ALL
SELECT 'Afternoon', 'Ben' FROM DUAL UNION ALL
SELECT 'Morning', 'Roger' FROM DUAL UNION ALL
SELECT 'Morning', 'Ben' FROM DUAL UNION ALL
SELECT 'Afternoon', 'Chris' FROM DUAL)
select c.studentname,
s.classsession,
round(ratio_to_report(count(c.classsession))
over ( partition by c.studentname),2) pct
from c partition by ( studentname )
right outer join ( SELECT distinct classsession from c ) s on s.classsession = c.classsession
group by c.studentname, s.classsession
order by c.studentname, s.classsession;
╔══════════════════════════════════════════════════════════════════╗
║ STUDENTNAME CLASSSESSION PCT ║
╠══════════════════════════════════════════════════════════════════╣
║ ----------- ------------ -------------------------------------- ║
║ Ben Afternoon 0.25 ║
║ Ben Evening 0.5 ║
║ Ben Morning 0.25 ║
║ Chris Afternoon 0.5 ║
║ Chris Evening 0 ║
║ Chris Morning 0.5 ║
║ Roger Afternoon 0.5 ║
║ Roger Evening 0 ║
║ Roger Morning 0.5 ║
╚══════════════════════════════════════════════════════════════════╝
这是使用 SQL Server 2008 及更高版本的或多或少的传统方法。 (在以后的版本中可能会有更方便的方法使用统计窗口函数来编写它。)
这将 return 至少一个 class 中所有学生的数据,所有 class 至少有一个学生的数据。如果表很大,取消注释 where
子句以一次获取一个学生的数据
一、测试数据:
CREATE TABLE #Test
(
ClassSession varchar(20) not null
,StudentName varchar(20) not null
)
INSERT #Test values
('Evening', 'Ben')
,('Morning', 'Chris')
,('Afternoon', 'Roger')
,('Evening', 'Ben')
,('Afternoon', 'Ben')
,('Morning', 'Roger')
,('Morning', 'Ben')
,('Afternoon', 'Chris')
SELECT *
from #Test
以及查询:
WITH cteClasses
as (-- First, get the list of classes
SELECT distinct ClassSession
from #Test
)
,cteStudents
as (-- Next, get a list of all students
SELECT
StudentName
,count(*) * 1.00 ClassCount
from #Test
--where StudenName = @StudentParameter
group by StudentName
)
-- Mush them all together, and...
SELECT
st.StudentName
,cl.ClassSession
,count(te.StudentName) / st.ClassCount * 100 Percentage
from cteStudents st
cross join cteClasses cl
left join #Test te
on te.ClassSession = cl.ClassSession
and te.StudentName = st.StudentName
group by
st.StudentName
,cl.ClassSession
,st.ClassCount
order by
st.StudentName
,cl.ClassSession
如何在SQL中动态计算百分比?
假设您有一个名为 Classes
的关注 table:
ClassSession StudentName
---------------------------------
Evening Ben
Morning Chris
Afternoon Roger
Evening Ben
Afternoon Ben
Morning Roger
Morning Ben
Afternoon Chris
假设 Ben
,我预计
Evening = 50 %
Afternoon = 25%
Morning = 25%
我期待克里斯
Morning = 50%
Afternoon = 50%
Evening = 0 %
所以ClassSession
(三个session)应该是比较不变的
到目前为止,我已经尝试了以下 SQL 语句:
Select
ClassSession,
(Count(ClassSession) * 100 / (Select Count(*) From Classes)) as Percentage
From
Classes
Where
StudentName = 'Chris'
Group By
ClassSession
一种方法使用条件聚合和 window 函数:
Select ClassSession,
(sum(case when StudentName = 'Chris' then 100.0 else 0 end) /
sum(sum(case when StudentName = 'Chris' then 100.0 else 0 end)) over ()
) as Percentage
From Classes
Group By ClassSession;
这将确保出现零的事件。
困难的部分是让零出现在给定会话中没有任何 类 的学生。
这是 PARTITION
外连接的作业。
select c.studentname,
s.classsession,
round(ratio_to_report(count(c.classsession))
over ( partition by c.studentname),2) pct
from c partition by ( studentname )
right outer join ( SELECT distinct classsession from c ) s
on s.classsession = c.classsession
group by c.studentname, s.classsession
order by c.studentname, s.classsession;
注意联接中的 PARTITION
关键字。这告诉 Oracle 为每个分区执行外部连接。因此,如果给定的 studentname
没有 classsession
,请为该学生添加它。
此外,ratio_to_report
是计算百分比的好函数。
这是一个完整的示例,其中包含数据:
with c (ClassSession, StudentName) AS (
SELECT 'Evening', 'Ben' FROM DUAL UNION ALL
SELECT 'Morning', 'Chris' FROM DUAL UNION ALL
SELECT 'Afternoon', 'Roger' FROM DUAL UNION ALL
SELECT 'Evening', 'Ben' FROM DUAL UNION ALL
SELECT 'Afternoon', 'Ben' FROM DUAL UNION ALL
SELECT 'Morning', 'Roger' FROM DUAL UNION ALL
SELECT 'Morning', 'Ben' FROM DUAL UNION ALL
SELECT 'Afternoon', 'Chris' FROM DUAL)
select c.studentname,
s.classsession,
round(ratio_to_report(count(c.classsession))
over ( partition by c.studentname),2) pct
from c partition by ( studentname )
right outer join ( SELECT distinct classsession from c ) s on s.classsession = c.classsession
group by c.studentname, s.classsession
order by c.studentname, s.classsession;
╔══════════════════════════════════════════════════════════════════╗
║ STUDENTNAME CLASSSESSION PCT ║
╠══════════════════════════════════════════════════════════════════╣
║ ----------- ------------ -------------------------------------- ║
║ Ben Afternoon 0.25 ║
║ Ben Evening 0.5 ║
║ Ben Morning 0.25 ║
║ Chris Afternoon 0.5 ║
║ Chris Evening 0 ║
║ Chris Morning 0.5 ║
║ Roger Afternoon 0.5 ║
║ Roger Evening 0 ║
║ Roger Morning 0.5 ║
╚══════════════════════════════════════════════════════════════════╝
这是使用 SQL Server 2008 及更高版本的或多或少的传统方法。 (在以后的版本中可能会有更方便的方法使用统计窗口函数来编写它。)
这将 return 至少一个 class 中所有学生的数据,所有 class 至少有一个学生的数据。如果表很大,取消注释 where
子句以一次获取一个学生的数据
一、测试数据:
CREATE TABLE #Test
(
ClassSession varchar(20) not null
,StudentName varchar(20) not null
)
INSERT #Test values
('Evening', 'Ben')
,('Morning', 'Chris')
,('Afternoon', 'Roger')
,('Evening', 'Ben')
,('Afternoon', 'Ben')
,('Morning', 'Roger')
,('Morning', 'Ben')
,('Afternoon', 'Chris')
SELECT *
from #Test
以及查询:
WITH cteClasses
as (-- First, get the list of classes
SELECT distinct ClassSession
from #Test
)
,cteStudents
as (-- Next, get a list of all students
SELECT
StudentName
,count(*) * 1.00 ClassCount
from #Test
--where StudenName = @StudentParameter
group by StudentName
)
-- Mush them all together, and...
SELECT
st.StudentName
,cl.ClassSession
,count(te.StudentName) / st.ClassCount * 100 Percentage
from cteStudents st
cross join cteClasses cl
left join #Test te
on te.ClassSession = cl.ClassSession
and te.StudentName = st.StudentName
group by
st.StudentName
,cl.ClassSession
,st.ClassCount
order by
st.StudentName
,cl.ClassSession