2017-10-30 9 views
3

SQLで動的にパーセンテージを計算する方法は?動的に計算されたSQLの割合

のは、あなたが次の表は、Classesと呼ばれる持っているとしましょう:クリスのために、私はそう

Morning = 50% 
Afternoon = 50% 
Evening = 0 % 

ClassSessionを期待してい

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% 

を期待しています(3つのセッション)は比較のために一定でなければならない

これまでのところ、私は次のSQL文を試してみました:

Select 
    ClassSession, 
    (Count(ClassSession) * 100/(Select Count(*) From Classes)) as Percentage 
From 
    Classes 
Where 
    StudentName = 'Chris' 
Group By 
    ClassSession 
+0

あなたはStudentName条件を必要とするテーブルが大きい場合は、

まず、テストデータ1学生のAA時間のデータを取得するためにwhere句のコメントを解除サブクエリでも同様です。相関サブクエリにする。 – jarlh

+5

ご使用のデータベースで質問にタグを付けてください。 –

+0

リマインダーありがとう私はシステム間キャッシュをタグ付けしました –

答えて

1

一つの方法は、条件付きの集約およびウィンドウ関数を使用しています。

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; 

これは、ゼロが現れ、そのイベントを保証します。

2

特定のセッションでクラスを持たない生徒のために、難しい部分がゼロを表示しています。

これは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に指示します。したがって、studentnameclasssessionがない場合は、その学生に追加してください。

また、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 ║ 
╚══════════════════════════════════════════════════════════════════╝ 
+0

データベースはシステム間キャッシュですが単純なSQLでありますが、答えが良い方向になります –

0

は、ここでSQL Server 2008およびアップを使用して、多かれ少なかれ、従来の方法です。

これは、少なくとも1人の生徒がいるすべてのクラスのすべての生徒のデータを返します。

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 
+0

ありがとうフィリップ、データベースはシステム間キャッシュですが、 –

関連する問題