SQL Queries - Count total of rows with Case when statement - sql

I will like to count to get the correct number of rows when the [Location] column match a certain value.
Below is my table:
Student
Marks
Location
Date
Kenn
66
UK
09-01-2022
Kenn
89
UK
09-01-2022
Kenn
77
Canada
09-01-2022
Below SQL queries is what I have tried:
SELECT [Student]
,COUNT(CASE WHEN [Location] = 'UK' THEN [Marks] ELSE 0 END) AS UK
,COUNT(CASE WHEN [Location] = 'Canada' THEN [Marks] ELSE 0 END) AS Canada
FROM table_name
GROUP BY [Student]
But the output is
Student
UK
Canada
Kenn
3
3
What I expected to see is:
Student
UK
Canada
Kenn
2
1
Please advise if anything wrong with my SQL queries?
Thank you!!

Use sum instead
SELECT [Student]
,SUM(CASE WHEN [Location] = 'UK' THEN 1 ELSE 0 END) AS UK
,SUM(CASE WHEN [Device] = 'Canada' THEN 1 ELSE 0 END) AS Canada
FROM table_name
GROUP BY [Student]

Related

Count results that have different column value related to same ID

I'm new to SQL and looking for help on how to best do this.
I have 2 tables with the following columns:
Investors: Round ID, Investor Name, Investor City, Investor Country
Rounds: Round ID, Company Name, Company City, Company Country
I joined them to get this result
Round ID
Investor Country
Company Country
1
US
Spain
1
UK
Spain
1
Spain
Spain
2
France
Germany
2
UK
Germany
3
UK
Italy
3
Italy
Italy
I will need to get the number of investors (per round ID) which have their country different from the Company Country, So like for Round 1 I will have 2, for Round 2 it's 0 and for round 3 it's 1.
How could I do this?
Thank you for your help!
Just use conditional aggregation:
select round,
sum(case when investor_country <> company_company then 1 else 0 end) as cnt
from t
group by round;
Looking at your expected output, I think you need the count = 0 in case there do not exists a single record for investor country = company country and if there is, then you need all other record count.
You can use conditions as follows:
select round_id,
case when count(case when investor_country = company_company then 1 end) = 0
then 0
else count(case when investor_country <> company_company then 1 end)
end as cnt
from your_table t
group by round_id;
If you need diffrent counts:
SELECT
RoundId,
SUM(IIF(InvestorCountry != CompanyCountry,1,0)) AS Count
FROM
YOUR_TABLE_OR_VIEW
GROUP BY
RoundId
If you need difrent count and when all result of a same Round are difrent you want zero:
SELECT
t.RoundId,
IIF(t.Count = t.DiffrentCount,0,t.DiffrentCount) 'Count'
FROM
(
SELECT
RoundId,
SUM(1) AS 'Count',
SUM(IIF(InvestorCountry != CompanyCountry,1,0)) AS 'DiffrentCount',
FROM
YOUR_TABLE_OR_VIEW
GROUP BY
RoundId
)t

How to count the number of times a specific text string appears and group it by other columns

I have a table population_table that contains columns with a user_id, provider_name, and city. I want to count the number of times a user appears in each city, per provider. So for instance, I would want the output to look something like this:
provider_name | Users | Atlanta | Chicago | New York
______________________________________________________
Alpha 100 50 25 25
Beta 200 100 75 25
Kappa 500 300 100 100
I tried using:
select provider_name, count (distinct user_id) AS Users, count(city) AS City
from population_table
group by provider_name
How can I write this query to get the breakdown of the users per provider per city?
I think you want conditional aggregation. It is not clear from your description that count(distinct) is necessary. So I would try this first:
select provider_name, count(*) AS Users,
sum(case when city = 'Atlanta' then 1 else 0 end) as Atlanta,
sum(case when city = 'Chicago' then 1 else 0 end) as Chicago,
sum(case when city = 'New York' then 1 else 0 end) as New_York
from population_table
group by provider_name;
If count(distinct) is necessary:
select provider_name, count(distinct user_id) AS Users,
count(distinct case when city = 'Atlanta' then user_id end) as Atlanta,
count(distinct case when city = 'Chicago' then user_id end) as Chicago,
count(distinct case when city = 'New York' then user_id end) as New_York
from population_table
group by provider_name
If you have a variable number of cities, I do not know how to supply the list in SparkSQL. But using pyspark, you could create output table from input like this:
counts = input.groupBy('provider_name', 'city').count().cache()
countsPerProvider = counts.groupBy('provider_name').count().withColumnRenamed("count", "users")
pivoted = counts.groupBy("provider_name").pivot("city").sum('count')
table = pivoted.join(countsPerProvider, pivoted["provider_name"] == countsPerProvider["provider_name"]).select(pivoted["*"], countsPerProvider["users"])

Transact-SQL Select Query Giving duplicate values

first off, thank you for taking the time to look at this.
I am trying to collect data from 3 tables and make a reference chart that allows the end user to see the stored data.
Basically I have 3 tables for this example:
USERS:
USER_PK USER_ID USER_NAME
1 10000 Bob
2 10001 Sally
3 10003 Joe
4 10004 Susan
SKILL_TYPE:
SKILL_PK SKILL_NAME
11 Point of Sale
22 Digital Sales
33 Customer Service
44 Specialist Support
SKILL_ASSOCIATION:
SKILL_ASSOC_PK SKILL_PK USER_PK START_DATE STOP_DATE Priority
99 11 1 36526 500000 2
88 11 2 36527 500000 3
77 22 1 36526 500000 3
66 33 3 36528 500000 1
55 44 4 36525 500000 1
444 33 4 36525 500000 4
(I know I've probably broken some rules with cataloging this data I did it in SQL Express, however it is only an example and not representative of the real data I am using)
My Select Query Returns an unwanted result with multiple lines for each USER:
Statement:
SELECT USERS.[USER_NAME], USERS.[USER_ID],
(CASE WHEN ST.SKILL_NAME ='Point of Sale' Then SA.[PRIORITY] END) AS 'POS',
(CASE WHEN ST.SKILL_NAME ='Digital Sales' Then SA.[PRIORITY] END) AS 'DS',
(CASE WHEN ST.SKILL_NAME ='Customer Service' Then SA.[PRIORITY] END) AS 'CS',
(CASE WHEN ST.SKILL_NAME ='Specialist Support' Then SA.[PRIORITY] END) AS 'Spec'
FROM USERS
INNER JOIN [dbo].[SKILL_ASSOCIATION] AS SA ON SA.USER_PK = USERS.USER_PK
INNER JOIN SKILL_TYPE AS ST ON ST.SKILL_PK = SA.SKILL_PK
Result:
USER_NAME USER_ID POS DS CS Spec
Bob 10000 2 NULL NULL NULL
Sally 10001 3 NULL NULL NULL
Bob 10000 NULL 3 NULL NULL
Joe 10003 NULL NULL 1 NULL
Susan 10004 NULL NULL NULL 1
Susan 10004 NULL NULL 4 NULL
I've tried using distinct as well with similar results.
Desired Results:
NAME ID POS DS CS Spec
Bob 1 2 3
Sally 2 3
Joe 1
Susan 4 1
I have very limited Query access with this SQL Server and cannot create/modify or delete from it to accomplish my objective.
Any guidance would be much appreciated!
Thanks,
Steven
Your expected output implies that an aggregation by user along with taking the MAX of each of the CASE expressions should work:
SELECT
u.[USER_NAME],
u.[USER_ID],
MAX(CASE WHEN ST.SKILL_NAME = 'Point of Sale' THEN SA.[PRIORITY] END) AS POS,
MAX(CASE WHEN ST.SKILL_NAME = 'Digital Sales' THEN SA.[PRIORITY] END) AS DS,
MAX(CASE WHEN ST.SKILL_NAME = 'Customer Service' THEN SA.[PRIORITY] END) AS CS,
MAX(CASE WHEN ST.SKILL_NAME = 'Specialist Support' THEN SA.[PRIORITY] END) AS Spec
FROM USERS u
INNER JOIN [dbo].[SKILL_ASSOCIATION] AS SA
ON SA.USER_PK = u.USER_PK
INNER JOIN SKILL_TYPE AS ST
ON ST.SKILL_PK = SA.SKILL_PK
GROUP BY
u.[USER_NAME],
u.[USER_ID];

SQL script to change the structure of the table

I am working on a SQL database (Microsoft SQL Server 2008)
I have a table like this
Country Gender Number
---------+---------------+-----------+
Russia Male 50000
Russia Female 40000
Russia Unknown 30000
India Male 45678
India Female 21354
China Male 37878
China Female 45686
China Unknown 24534
France Male 45378
France Female 49783
Is there an sql select script that can return a table like this:
Country Male Female Unknown
---------+---------------+-----------+-----------------+
Russia 50000 40000 30000
India 45678 21354 0
China 37878 45686 24534
France 45378 49783 0
Please note that some countries do not have "Unkown" data so in this case it should be 0.
I tried a couple of things but I did not get any close results. Thanks for any help.
You can use pivot operator for such kind of queries:
select Country,
IsNull([Male], 0) Male,
IsNull([Female], 0) Female,
IsNull([Unknown], 0) Unknown
from TableName t
pivot (sum(Number) for Gender in ([Male], [Female], [Unknown])) p
or ... pivot max(Number) for ... if you know that (Country, Gender) combination is unique in original data.
you can also use this query
select
T.Country,
max(case when T.Gender = 'Male' then T.Number else 0 end) as Male,
max(case when T.Gender = 'Female' then T.Number else 0 end) as Female,
max(case when T.Gender = 'Unknown' then T.Number else 0 end) as Unknown
from Table1 as T
group by T.Country
sql fiddle demo

sql- display the table of records in the following format

Question Part 1
I am having a Roles table which specifies the level and status of each candidate.
name id status level location country
==========================================================
RAJ 1 PENDING MAJOR BANGALORE INDIA
SAM 2 ACTIVE LEAD KOLKATA INDIA
ANN 3 CLOSED SENIOR HYDERABAD INDIA
BEN 4 APPROVED MINOR PUNE INDIA
JACK 5 APPROVED MINOR PUNE INDIA
REC 6 ACTIVE LEAD BANGALORE INDIA
VESPER 7 ACTIVE LEAD BANGALORE INDIA
KISHOR 8 ACTIVE LEAD HYDERABAD INDIA
I need to generate a report for count of candidtes in each level and how many are there
in particlular status based on the selected location and country. I may not be able to explain clearly. but i hope the below picture will help you to assist me.
status MINOR MAJOR LEAD SENIOR Total
==========================================================
PENDING 0 1 0 0 1
ACTIVE 0 0 4 0 4
CLOSED 0 0 0 1 1
APPROVED 2 0 0 0 2
Question Part 2
How can I rename the values in status column that are displayed after executing above query. Suppose I want to display status Pending as 'Delayed response', Active as 'Online'.
;WITH PivotSource AS
(
SELECT id,status,LEVEL
FROM Roles
)
SELECT status,
MINOR,
MAJOR,
LEAD,
SENIOR,
MINOR+MAJOR+LEAD+SENIOR AS Total
FROM PivotSource
PIVOT (COUNT(id) FOR LEVEL IN (MINOR,MAJOR,LEAD,SENIOR) ) AS Pvt;
A PIVOT-less solution:
SELECT
status,
MINOR = COUNT(CASE level WHEN 'MINOR' THEN 1 END),
MAJOR = COUNT(CASE level WHEN 'MAJOR' THEN 1 END),
LEAD = COUNT(CASE level WHEN 'LEAD' THEN 1 END),
SENIOR = COUNT(CASE level WHEN 'SENIOR' THEN 1 END),
Total = COUNT(*)
FROM Roles
GROUP BY status
You need to use a pivot table. Here is an example:
http://blog.sqlauthority.com/2008/06/07/sql-server-pivot-and-unpivot-table-examples/
regarding Question Part 2:
WITH PivotSource AS ( SELECT id,status,LEVEL FROM Roles ) SELECT
Status= case Status when 'Pending' then 'Delayed Response'
when 'Active' then 'online'
else 'unknown' End,
MINOR,MAJOR,LEAD, SENIOR,MINOR+MAJOR+LEAD+SENIOR AS Total
FROM PivotSource
PIVOT (COUNT(id) FOR LEVEL IN (MINOR,MAJOR,LEAD,SENIOR) ) AS Pvt;