Oracle 11G R2 SQL rows to columns - sql

I have a table of bank staff information that looks like this:
branchNumber Position firstName lastName staffNumber
------------ -------- --------- -------- -----------
25 Manager john doe 11111
25 Secretary robert paulson 11112
25 Secretary cindy lu 11113
66 Manager tim timson 22223
66 Manager jacob jacobson 22224
66 Secretary henry henryson 22225
66 Supervisor paul paulerton 22226
I am actually done with this, but I completed the assignment using SQL common table expressions, and I can't use them in this project, I need them in this format.
branchNumber numOfManagers numOfSecretaries numOfSupervisors totalEmployees
------------ ------------- ---------------- ---------------- --------------
25 1 2 0 3
66 2 1 1 4
My issue is getting multiple columns with information from a row, I have this so far,
SELECT branchNumber, COUNT(*) AS numOfManagers
FROM Staff
WHERE position = 'Manager'
GROUP BY branchNumber, Position;
This outputs the correct information for numOfManagers, but making the next three columns eludes me without using CTE's. I tried sub selects too, with no luck. Anybody have any ideas?

You can use something like this:
select branchnumber,
sum(case when Position ='Manager' then 1 else 0 end) numofManagers,
sum(case when Position ='Secretary' then 1 else 0 end) numofSecretaries,
sum(case when Position ='Supervisor' then 1 else 0 end) numofSupervisors,
count(*) totalEmployees
from yourtable
group by branchnumber
See SQL Fiddle with Demo
Or you can use the PIVOT function:
select branchnumber,
'Manager', 'Secretary', 'Supervisor',
TotalEmployees
from
(
select t1.branchnumber,
t1.position,
t2.TotalEmployees
from yourtable t1
inner join
(
select branchnumber, count(*) TotalEmployees
from yourtable
group by branchnumber
) t2
on t1.branchnumber = t2.branchnumber
) x
pivot
(
count(position)
for position in ('Manager', 'Secretary', 'Supervisor')
) p;
See SQL Fiddle with Demo

Related

Count values separately until certain amount of duplicates SQL

I need a Statement that selects all patients and the amount of their appointments and when there are 3 or more appointments that are taking place on the same date they should be counted as one appointment
That is what my Statement looks so far
SELECT PATSuchname, Count(DISTINCT AKTDATUM) AS AKTAnz
FROM tblAktivitaeten
LEFT OUTER JOIN tblPatienten ON (tblPatienten.PATID=tblAktivitaeten.PATID)
WHERE (AKTDeleted<>'J' OR AKTDeleted IS Null)
GROUP BY PATSuchname
ORDER BY AKTAnz DESC
The result should look like this
PATSuchname Appointments
----------------------------------------
Joey Patner 13
Billy Jean 15
Example Name 13
As you can see Joey Patner has 13 Appointments, in the real table though he has 15 appointments but three of them have the same Date and because of that they are only counted as 1
So how can i write a Statement that does exactly that?
(I am new to Stack Overflow, sorry if the format I use is wrong and tell me if it is.
In the table it looks like this.
tblPatienten
----------
PATSuchname PATID
------------------------
Joey Patner 1
Billy Jean 2
Example Name 3
tblAktivitaeten
----------
AKTDatum PATID AKTID
-----------------------------------------
08.02.2021 1 1000 ----
08.02.2021 1 1001 ---- So these 3 should counted as 1
08.02.2021 1 1002 ----
09.05.2021 1 1003
09.07.2021 2 1004 -- these 2 shouldn't be counted as 1
09.07.2021 2 1005 --
Two GROUP BY should do it:
SELECT
x.PATID, PATSuchname, SUM(ApptCount)
FROM (
SELECT
PATID, AKTDatum, CASE WHEN COUNT(*) < 3 THEN COUNT(*) ELSE 1 END AS ApptCount
FROM tblAktivitaeten
GROUP BY
PATID, AKTDatum
) AS x
LEFT JOIN tblPatienten ON tblPatienten.PATID = x.PATID
GROUP BY
x.PATID, PATSuchname

How to use 'Count', based on a particular column in SQL

I have a query and which give the count greater than 1, but what I expect is I need the result to be based on particular column(Rollno.) How to achieve it.
Table Studies
NAME RollNo DeptType InternalStaff_1 InternalStaff_2
----------- ----------- ----------- --------------- ---------------
Anu 5 CompSci Eve Antony
Joy 13 Architecture Elizabeth George
Adam 2 Mech Grady Lisa
Adam 2 Mech Grady Kim
Anu 5 CompSci Eve Antony
The below query gives me Count but not as expected
SELECT DISTINCT S.Name
, S.RollNo
, COUNT(S.RollNo) AS [Count]
, S.DeptType
, S.InternalStaff_1
, S.InternalStaff_2
FROM DataMining.dbo.Studies S
WHERE StartDate >= '20210325'--#StartDate
AND StartDate <= '20210407'--#EndDate
GROUP BY S.Name, S.RollNo, S.DeptType, S.InternalStaff_1, S.InternalStaff_2
HAVING COUNT(S.RollNo) > 1
ORDER BY RollNo
The query gave me the below result
NAME RollNo Count DeptType InternalStaff_1 InternalStaff_2
----------- ----------- ----------- ----------- --------------- ---------------
Anu 5 2 CompSci Eve Antony
But the expected result is
NAME RollNo Count DeptType InternalStaff_1 InternalStaff_2
----------- ----------- ----------- ----------- --------------- ---------------
Anu 5 2 CompSci Eve Antony
Adam 2 2 Mech Grady NULL
As you can see the expected result is having a different InternalStaff_2 name for Adam which is not considered on the present result.
May I know how to over come this?
Note: I need the results to be displayed based on Rollno but I also need the InternalStaff_2 to be included in the result.
Hmmm . . . If I understand correctly, you want NULL if the internal staff columns do not match. That would be:
SELECT S.Name, S.RollNo, COUNT(*) AS [Count], S.DeptType,
(CASE WHEN MIN(S.InternalStaff_1) = MAX(S.InternalStaff_1) THEN MIN(S.InternalStaff_1) END) as InternalStaff_1,
(CASE WHEN MIN(S.InternalStaff_2) = MAX(S.InternalStaff_2) THEN MIN(S.InternalStaff_2) END) as InternalStaff_2
FROM DataMining.dbo.Studies S
WHERE StartDate >= '20210325' AND --#StartDate
StartDate <= '20210407' --#EndDate
GROUP BY S.Name, S.RollNo, S.DeptType
HAVING COUNT(*) > 1
ORDER BY RollNo;
Here is a db<>fiddle that shows that this basically works.
like this?
I do not confirm your needs, but the internalstaff_2 column can refer to STRING_AGG() to replace the nested subquery in the following script.
SELECT DISTINCT S.Name
, S.RollNo
, COUNT(S.RollNo) AS [Count]
, S.DeptType
, S.InternalStaff_1
, (SELECT CASE WHEN COUNT(DISTINCT InternalStaff_2) = 1 THEN MIN(InternalStaff_2) ELSE null END
FROM #temp AS i
WHERE i.NAME = S.NAME and i.RollNo = S.RollNo and i.DeptType = S.DeptType and i.InternalStaff_1 = S.InternalStaff_1) as InternalStaff_2
FROM #temp S
GROUP BY S.[Name], S.RollNo, S.DeptType, S.InternalStaff_1
HAVING COUNT(S.RollNo) > 1
ORDER BY RollNo

Separate distinct values in to columns

Hi all I am quite new to SQL. I have a table (TABLE1) with two columns as below
Name age
--------
jim 18
jim 21
dave 18
dave 18
john 23
john 41
I need to create a view in SSMS which lists distinct ages for each name in a separate column as below
Jim Dave John
---------------
18 18 23
21 41
I have tried a sub query like
SELECT DISTINCT AGE FROM TABLE1 WHERE NAME = JIM
But I encountered a sub query cannot return more than one value.
You can use row_number() & do aggregation :
select max(case when name = 'jim' then age end) as jim,
max(case when name = 'dave' then age end) as dave,
max(case when name = 'john' then age end) as john
from (select t.*, row_number() over (partition by name order by age) as seq
from table t
) t
group by seq;

sum of multiple fields in group by clause and create single row

I have a table like this.
Id Name Test Subject Marks
----------------------------
1 Alex 1 Maths 40
1 Alex 2 Maths 80
1 Alex 1 Sociology 55
1 Alex 2 Sociology 70
1 Alex 3 Sociology 60
2 Mark 1 Maths 30
2 Mark 2 Maths 60
2 Mark 1 Sociology 40
2 Mark 2 Sociology 50
2 Mark 3 Sociology 30
What I need is a group by on Id, Name, Subject and sum(Marks) in a single row, to give a result like:
Id Name Maths Sociology
-----------------------
1 Alex 120 185
2 Mark 90 120
I can get this as:
Id Name Marks
--------------
1 Alex 120
2 Mark 90
or:
Id Name Marks
-------------
1 Alex 185
2 Mark 120
I tried multiple options but I'm getting multiple rows for each ID.
The query below is not working:
select
Id, Name, Sum(Marks) where Subject = 'Maths' as Maths,Sum(Marks ) where Subject = 'Sociology' as Sociology
from
Table
group by
Id, Name;
I get this error:
"Error while compiling statement: FAILED: ParseException line 3:66 missing EOF at 'as' near ''Maths''
You are looking for PIVOT. Try :
create table #tbl(Id int, Name varchar(20), Test int, Subject varchar(20), Marks int)
insert into #tbl values
(1,'Alex',1,'Maths', 40 ),
(1,'Alex',2,'Maths', 80 ),
(1,'Alex',1,'Sociology', 55),
(1,'Alex',2,'Sociology', 70),
(1,'Alex',3,'Sociology', 60),
(2,'Mark',1,'Maths', 30 ),
(2,'Mark',2,'Maths', 60 ),
(2,'Mark',1,'Sociology', 40),
(2,'Mark',2,'Sociology', 50),
(2,'Mark',3,'Sociology', 30)
--select * from #tbl
SELECT ID,Name,Maths,Sociology
FROM(
SELECT ID, Name, Subject, Marks
FROM #tbl
) tbl
PIVOT(
SUM(Marks) FOR Subject IN (Maths, Sociology)
) piv
output:
ID Name Maths Sociology
----------- ---- ------------ -----------
1 Alex 120 185
2 Mark 90 120
You can use a case expression to effectively filter the values going into your sum:
select Id
,Name
,sum(case when Subject = 'Maths' then Marks else 0 end) as Maths
,sum(case when Subject = 'Sociology' then Marks else 0 end) as Sociology
from Table
group by Id
,Name;
If you are looking to do this across a lot of different subject values however, you will need to look at using pivot:
select Id
,[Name]
,[Maths]
,[Sociology]
from (select Id, [Name], [Subject], Marks from #t) as t
pivot(sum(Marks)
for [Subject] in(Maths,Sociology)
) as p;
Another solution using PIVOT operator:
SELECT
ID
,Name
,Maths
,Sociology
FROM(
SELECT
ID
,Name
,Subject
,Marks
FROM your_table
) tbl
PIVOT(
SUM(Marks) FOR Subject IN (Maths, Sociology)
) pvt
You can use below query :
select id,name,maths_marks,sociology_marks
from
(select id,name,test,subject,marks
from table)
pivot(sum(marks) for subject in ('Maths' as Maths_marks,'Sociology' as Sociology_marks);

Oracle 10g : SQL merging rows into single rows

I have a query that return below data structure :
Course Math Science Computer Chemistry
------ ---- ------- -------- ---------
CI101 98
CI101 87
CI101 78
CI101 102
CI101 23
CI101 56
CI101 89
CI101 45
How can have it be in the following structure using SQL:
Course Math Science Computer Chemistry
------ ---- ------- -------- ---------
CI101 98 78 23 45
CI101 87 102 56
CI101 89
Here is SQL I tried:
select course,
case
when subject = 'MATH' then
count
end as MATH,
case
when subject = 'SCIENCE' then
count
end as SCIENCE,
case
when subject = 'COMPUTER' then
count
end as COMPUTER,
case
when subject = 'CHEMISTRY' then
count
end as CHEMISTRY
from t_course
GROUP BY course, subject, count
Table Structure :
Course Subject Count
------ ------- -----
CI101 Math 98
....
Thanks ahead.
try this:
As I dont have Oracle and I didnt see any answer for this question, I have done this in sql server. This can be easily converted to Oracle sql.
I think, the only part requires conversion is ROW_NUMBER() over(order by [count]) as row_num which is basically to give a sequence number to each set
select CO.course,MA.count as 'MATH',SC.count as 'SCIENCE',CO.count as 'COMPUTER',CH.count as 'CHEMISTRY' from
(select course,[count],ROW_NUMBER() over(order by [count]) as row_num from t_course where subject = 'MATH')MA full outer join
(select course,[count],ROW_NUMBER() over(order by [count]) as row_num from t_course where subject = 'SCIENCE')SC on SC.row_num=MA.row_num full outer join
(select course,[count],ROW_NUMBER() over(order by [count]) as row_num from t_course where subject = 'COMPUTER')CO on CO.row_num=SC.row_num full outer join
(select course,[count],ROW_NUMBER() over(order by [count]) as row_num from t_course where subject = 'CHEMISTRY')CH on CO.row_num=CH.row_num
Please see the SQL fiddle Demo here