SQL: Combine Duplicate Rows And Case Statement Values in Final Data Output - sql

I'm working on a SQL query that counts duplicate records that are based on a text field I am working with: where datasource = 'Web' or 'Internal'. I am currently using a case statement to count the number of times a record shows that value. My question is how do I combine the two results into one record that shows a count of both.
I'm attaching a query of what I currently have working, what my output is and what I would like the end result to look like.
SELECT id
,lastname
,firstname
,datasource
,CASE
WHEN (
(Datasource = 'Web')
)THEN Count(Datasource)
ELSE 0
END WebData
,CASE
WHEN (
(Datasource = 'Internal')
) THEN Count(Datasource)
ELSE 0
END InternalData
,count(id) as countid
FROM Table
GROUP BY
id
,lastname
,firstname
,datasource
This currently returns:
12345 Jack Boss Internal 0 1 1
12241 Eric Graves Internal 0 1 1
13300 Su Lynn Web 1 0 1
13300 Su Lynn Internal 0 1 1
13914 Mark Ross Internal 0 2 2
14008 Mitch Smith Internal 0 1 1
I would like it to return:
12345 Jack Boss 0 1 1
12241 Eric Graves 0 1 1
13300 Su Lynn 1 1 2
13914 Mark Ross 0 2 2
14008 Mitch Smith 0 1 1
Thanks

You need to add the outer select for current query with the Group on the the columsn you want to do the aggrigate.Just add the Outer select to your query,
SELECT
data.id,
data.lastname,
data.firstname,
SUM(data.WebData) AS WebData,
SUM(data.InternalData) AS InternalData,
SUM(data.countid) AS Countid
FROM
(
SELECT id,lastname,
firstname,datasource,
CASE WHEN Datasource = 'Web' THEN Count(Datasource) ELSE 0 END WebData,
CASE WHEN Datasource = 'Internal' THEN Count(Datasource)ELSE 0 END InternalData,
count(id) AS Countid
FROM Table
GROUP BY
id,lastname,firstname,datasource
) AS data
GROUP BY
data.id,data.firstname,data.lastname

Related

SQL: SUM OR COUNT with CASE WHEN condition in multiple criteria

Course name
Section number
Course type
MATH 101
1
In person
MATH 101
2
In person
MATH 101
3
Online
MATH 101
4
In person
SOC 101
1
In person
SOC 101
2
In person
SOC 101
3
In person
ENGL 201
1
In person
ENGL 201
2
Online
ENGL 201
3
Online
ENGL 201
4
In person
PHY 101
1
Online
PHY 101
2
Online
From this table, I'd like to count Courses with only an 'In person' course, an 'Online' course, and both course types.
The query I tried is below.
SELECT
SUM(CASE WHEN coursetype = 'Inperson' AND coursetype = 'Online' THEN 1 ELSE 0 END) AS bothtype,
SUM(CASE WHEN coursetype = 'Online' THEN 1 ELSE 0 END) AS Onlineonly,
SUM(CASE WHEN coursetype = 'Inperson' THEN 1 ELSE 0 END) AS Onlineonly
From Course
The result what I expected is
bothtpye
Onlineonly
Inpersononly
2
1
1
but I got
bothtpye
Onlineonly
Inpersononly
0
7
6
Please advise me to get through this.
Thank you.
My solution uses double conditional aggregation.
SELECT SUM (CASE WHEN In_Person > 0 AND Online > 0 THEN 1 ELSE 0 END) as bothtype,
SUM (CASE WHEN In_Person > 0 AND Online = 0 THEN 1 ELSE 0 END) as inpersononly,
SUM (CASE WHEN In_Person = 0 AND Online > 0 THEN 1 ELSE 0 END) as onlineonly
FROM (
SELECT Course_name,
SUM(CASE WHEN Course_type='In Person' THEN 1 ELSE 0 END) as In_Person,
SUM(CASE WHEN Course_type='Online' THEN 1 ELSE 0 END) as Online
FROM Course
GROUP BY Course_name
) tot
DEMO Fiddle
SUGGESTION ( using PL/SQL ! ) :
CREATE PROCEDURE countCourses(OUT bothtype INT,OUT Inpersononly INT,OUT Onlineonly INT)
begin
SELECT COUNT(*) INTO bothtype FROM Course;
select COUNT(*) INTO Inpersononly FROM Course
WHERE courseType = "In person";
select COUNT(*) INTO Onlineonly FROM Course
WHERE courseType = "Online";
end;
call countCourses(#bothtype,#Inpersononly,#Onlineonly);
SELECT #bothtype,#Inpersononly,#Onlineonly;
EXPLICATION :
Creating procedure to store the count of each type of course in OUT variable
Call the procedure with convenient parameters
Select out given parameters

How to get Result 1 for all user_ids that at least one time have source as paid

How to get Result=1 for all user_ids that at least one time have source as paid. I mean not just for one row where source=paid, but for all rows for this user_id.
Result column does not exist in the table! We should get it somehow using the code!
Row Table
source session_number user_id
NULL 1 12345
NULL 2 12345
NULL 3 12345
NULL 4 12345
NULL 1 67890
paid 2 67890
NULL 3 67890
Desired Table
source session_number user_id result
NULL 1 12345 0
NULL 2 12345 0
NULL 3 12345 0
NULL 4 12345 0
NULL 1 67890 1
paid 2 67890 1
NULL 3 67890 1
You seem to want a window function. It would seem to be:
select t.*,
max(case when source = 'paid' then 1 else 0 end) over (partition by userid) as result
from t;
In Postgres, you can return a boolean as:
select t.*,
bool_or(source = 'paid') over (partition by userid) as result
from t;
use exists
select a.* from table_name a
where exists( select 1 from table_name b where a.userid=b.userid
and b.source='paid')
and result=1
With subquery
SELECT *,
CASE
WHEN user_id IN
(
SELECT user_id
FROM table_name
WHERE source = 'paid'
)
THEN 1
ELSE 0
END AS result
FROM table_name

SQL grouping into ranges?

I have a table "USER_ACTIVITY" like this:
USER_ID, LOGINS, CITY
1 2 NY
2 4 NY
3 10 NY
15 0 WS
...
And I want to have a result like this:
CITY, DEAD_USERS, LOW_ACTIVITY, HIGH_ACTIVITY
NY 0 2 1 ....
This is about normal Oracle-SQL in Exaplus.
I really do not know how I can specify ranges on my own. Thank you!
Use COUNT with a CASE expression:
SELECT City,
COUNT( CASE WHEN logins = 0 THEN 1 END ) AS dead,
COUNT( CASE WHEN logins BETWEEN 1 AND 3 THEN 1 END ) AS low_activity,
COUNT( CASE WHEN logins > 3 THEN 1 END ) AS high_activity
FROM user_activity
GROUP BY City

How to apply answer key on students' responses

I conducted a MCQs type test for students in Eng, math, and science
Students solved their test on a sheet readable by the OMR/OCR.
The machine produced responses of the students in follwoig way:-
Student ID Subject Q1 Q2 Q3 Q4 ......
201 English 3 1 4 1 ......
201 Math 3 2 1 1 ....
201 Science 2 1 2 3 ....
202 English 3 1 4 1 ......
202 Math 3 2 1 1 ....
202 Science 2 1 2 3 ....
-
-
-
How can i apply answer key on this data e.g for English my answer key is:
2 2 4 1 .....
would you pleas suggest a query for this situation
SELECT
StudentId
,CASE WHEN Q2 = ?ANSWER? then 1 ELSE 0 END
,CASE WHEN Q3 = ?ANSWER? then 1 ELSE 0 END
,CASE WHEN Q4 = ?ANSWER? then 1 ELSE 0 END
,CASE WHEN Q5 = ?ANSWER? then 1 ELSE 0 END
FROM
Table
Where subject = 'English'
One of possible solutions replace ?ANSWER? with something from your answer key
Other would be to generate tables like:
CREATE TABLE EnglishKey(
QuestionId int,
Answer int)
Then insert your values in this way:
INSERT INTO EnglishKey VALUES (1,3),(2,4),(....)
Replacing 1 with question number and answer with proper answer.
And then creating a SELECT should be easy
SELECT
a.StudentID
CASE WHEN a.Q1 <> a.A1 THEN 0 ELSE 1 end AS Result1,
CASE WHEN a.Q2 <> a.A2 THEN 0 ELSE 1 end AS Result2,
CASE WHEN a.Q3 <> a.A3 THEN 0 ELSE 1 end AS Result3,
CASE WHEN a.Q4 <> a.A4 THEN 0 ELSE 1 end AS Result4,
CASE WHEN a.Q5 <> a.A5 THEN 0 ELSE 1 end AS Result5,
CASE WHEN a.Q6 <> a.A6 THEN 0 ELSE 1 end AS Result6,
CASE WHEN a.Q7 <> a.A7 THEN 0 ELSE 1 end AS Result7,
CASE WHEN a.Q8 <> a.A8 THEN 0 ELSE 1 end AS Result8
FROM
StudentTable a
INNER JOIN AnswerTable b ON a.[SUBJECT] = b.[SUBJECT]
This answer presumes that you have the answers in a seperate table and can join on subject.
If you find it a pain to write out all the case statements (could have 100s of questions) you can quickly build these queries in Microsoft Excel or open office by breaking up the statement across multiple columns, have it fill in the 1,2,3,4s etc and then copy paste once happy.

SQL: Select criteria for two tables, compare 1 field, return using condition

These are the tables in the query. Want to compare the ID_Skills in the following 2 tables. And in the returning table from the select query, display ID_Skills with condition saying whether or not TrainingRequired (Yes/No)
tblEmployeeCurrentSkills
ID_EmployeeCurrentSkills ID_Employee ID_Skills
1 1 1
2 1 2
3 2 1
tblSkillsRequired
ID_SkillsRequired ID_Employee ID_Skills ID_Position
1 1 1 1
2 1 2 1
3 1 3 1
4 2 3 2
tblSkills
ID_Skills Skill
1 Reading
2 Wiring
3 Stapling
tblPosition
ID_Position Position
1 Tech1
2 Stapler
tblEmployee
ID_Employee EmployeeName
1 Hannah
2 Bob
SQL for qrySkillsGap table - determines whether training is necessary
SELECT tblEmployee.[Employee Name],
tblSkillsRequired.ID_Skills,
tblSkills.Skill,
IIf([tblEmployeeCurrentSkills].[ID_Skills]
Like [tblSkillsRequired].[ID_Skills],"No","Yes") AS TrainingRequired
FROM (tblSkills
INNER JOIN tblSkillsRequired
ON tblSkills.ID_Skills = tblSkillsRequired.ID_Skills)
INNER JOIN (tblEmployee INNER JOIN tblEmployeeCurrentSkills
ON tblEmployee.ID_Employee = tblEmployeeCurrentSkills.ID_Employee)
ON tblSkills.ID_Skills = tblEmployeeCurrentSkills.ID_Skills;
This is the current output:
EmployeeName ID_Skill TrainingRequired
Hannah 1 No
Hannah 1 No
Hannah 2 No
Bob 1 No
Bob 1 No
I want it to display this:
EmployeeName ID_Skill TrainingRequired
Hannah 1 No
Hannah 2 No
Hannah 3 Yes
Bob 1 No
Bob 3 Yes
Thanks for any help!
I was able to create the tables you provided and used a union to bring together the employee skills and required skills.
SELECT te.EmployeeName
, emp.ID_Skills
, CASE WHEN MIN(emp.TrainingRequired) = 0 THEN 'No'
ELSE 'Yes'
END AS TrainingRequired
FROM dbo.tblEmployee AS te
JOIN (SELECT tecs.ID_Employee
, tecs.ID_Skills
, 0 AS TrainingRequired
FROM dbo.tblEmployeeCurrentSkills AS tecs
UNION
SELECT tsr.ID_Employee
, tsr.ID_Skills
, 1 AS TrainingRequired
FROM dbo.tblSkillsRequired AS tsr
) emp
ON te.ID_Employee = emp.ID_Employee
GROUP BY te.ID_Employee
, te.EmployeeName
, emp.ID_Skills
ORDER BY te.ID_Employee
, emp.ID_Skills