Oracle SQL Query Tuning for output - sql

I have an output such as below
select City, Gender, count(*) from tablename group by City, Gender ;
City Gender count(*)
Chennai Male 640000
Chennai Female 623000
Blore Male 500000
Blore Female 600000
Pune Male 700000
Pune Female 700000
But I am looking for getting the same output as like below
City Male Female
Chennai 640000 623000
Blore 500000 600000
Pune 700000 700000
Appreciate your help.
Thanks

You need conditional sum for this
select
City,
sum(case when Gender = 'Male' then 1 else 0 end) as Male,
sum(case when Gender = 'Female' then 1 else 0 end) as Female
from tablename group by City

Here is short code
select city,sum(male),sum(female) from tablename group by city;

Related

Generate a score for several row and certain values and sum all

I have a table as below
CustomerNumber CustomerName Type Gender Age Nationality Residance
584 John Denver Retail Male 50 English Domestic
137 Jennifer Hazel Retail Female 34 Jamaican Abroad
547 Daniel Gorbo Retail Male 78 French Domestic
I need to generate a total score depends on Type, Gender, Age, Nationality and Residance values. For example,
For gender, male value generates "1", female "0"
For age, if it is greater than 65 generates "3" else "0"
For Nationality if non-english than generate 2 else 0
Final table should look like this:
CustomerNumber CustomerName Type Gender Age Nationality Residance RiskScore
584 John Denver Retail Male 50 English Domestic 1
137 Jennifer Hazel Retail Female 34 Jamaican Abroad 2
547 Daniel Gorbo Retail Male 78 French Domestic 6
I tried to add sum and 'case when' to main code however i got the error of 'need group by function'
sum( case when gender = 'Male' then 1
when age>65 then 3
when nationality = 'Abroad' then 2 else 0 end ) as RiskScore
Any help would be appreciated..
select *,
(case when gender = 'Male' then 1 else 0 end +
case when age>65 then 3 else 0 end +
case when nationality <> 'English'
then 2 else 0 end) as risk_score from my_table;
Just change your condition accordingly
If I understand the question correctly, you do not need an aggregation. Use an addition and CASE expression to calculate the risk score:
SELECT
v.*,
RiskScore = (
CASE WHEN Gender = 'Male' THEN 1 ELSE 0 END +
CASE WHEN Age > 65 THEN 3 ELSE 0 END +
CASE WHEN Nationality <> 'English' THEN 2 ELSE 0 END
)
FROM (VALUES
(584, 'John Denver', 'Retail', 'Male', 50, 'French', 'Domestic'),
(137, 'Jennifer Hazel', 'Retail', 'Female', 34, 'Jamaican', 'Abroad'),
(547, 'Daniel Gorbo', 'Retail', 'Male', 78, 'English', 'Domestic')
) v (CustomerNumber, CustomerName, Type, Gender, Age, Nationality, Residance)
Result:
CustomerNumber CustomerName Type Gender Age Nationality Residance RiskScore
584 John Denver Retail Male 50 French Domestic 3
137 Jennifer Hazel Retail Female 34 Jamaican Abroad 2
547 Daniel Gorbo Retail Male 78 English Domestic 4
As per the logic shared by you, below query should give the correct result using CASE and adding the value without group by:
Demo
SELECT A.*, COALESCE(case when gender = 'Male' then 1 ELSE 0 END , 0) +
COALESCE(CASE WHEN age>65 then 3 ELSE 0 END , 0) +
COALESCE( CASE when Nationality <> 'English' then 2 else 0 end, 0 ) as RiskScore
FROM TABLE1 A;

Group By returning 1st column values twice

I have data that looks like:
ACC311 Female 3
ACC311 Female 1
ACC311 Female 4
ACC311 Male 4
ACC501 Male 4
ACC501 Male 4
ACC501 Male 4
ACC501 Male 4
.
.
.
Now I am using following query to get results
Select distinct coursecode, gender, Count(CQ) as CQ from Table1
group by Coursecode, gender
order by Coursecode
It is returning results as following, which is obviously not a correct
way as per required output (see below)
CourseCode Gender CQ
ACC311 Male 45
ACC311 Female 22
ACC501 Female 228
ACC501 Male 485
Where as I need to get following:
CourseCode Total Male Female CQ
ACC311 67 45 22 11
ACC501 713 485 228 111
Your query returns rows "twice" because you group by Coursecode, gender. DISTINCT won't help either.
The easiest way to get desired result is to use conditional aggregation:
SELECT Coursecode,
Count(CQ) AS CQ,
COUNT(gender) AS Total,
COUNT(CASE WHEN gender = 'Male' THEN 1 END) AS Male,
COUNT(CASE WHEN gender = 'Female' THEN 1 END) AS Female
FROM Table1
GROUP BY Coursecode

have trouble when table.field_name is needed in two columns based on different values

I have a person table that has a sex field and a few other fields. Looks like this
firstname lastname sex birthday
--------- -------- --- ---------
john doe 0 1960-01-25
jane doe 1 1990-02-01
john smith 0 1995-03-15
mary smith 1 1990-01-16
so sex = 0 means male sex = 1 means female.
I'd like to see this as a result assuming the current_date as 2014-02-04
Age Female Male
--- ------ ----
18 0 1
24 2 0
54 0 1
I have this
SELECT count(*) AS Female,
cast(DATEDIFF(CURRENT_DATE,person.birthday)/(365.256366) AS SIGNED) AS Age
FROM person
WHERE person.sex=1
GROUP BY Age
which gives me the above result without the Male col. I can do a similar one for Male and Age but no Female. How do merge the two to get all three columns?
You can do that as a conditional SUM:
SELECT SUM(CASE WHEN person.sex=1 THEN 1 ELSE 0 END) AS Female,
SUM(CASE WHEN person.sex=0 THEN 1 ELSE 0 END) AS Male,
cast(DATEDIFF(CURRENT_DATE,person.birthday)/(365.256366) AS SIGNED) AS Age
FROM person
GROUP BY Age
BTW your "age" calculation will be close but will not be right when you're on someone's exact birthday day.

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

Required single SQL query

I have a table with the name empdetail and columns:
Id Name Gender
1 ABC Male
2 XYZ Female
3 PQR Male
I want to change Gender of each emp from Male to Female and from Female to Male with single query
Result should be this:
1 ABC Female
2 XYZ Male
3 PQR Female
You Just need to use the CASE Statement
update <table>
set Gender= case when Gender='Male' then 'Female'
when Gender='Female' then 'Male'
end
SQL fiddle demo
select id,name,
(case when gender='Male'
then 'Female'
else 'Male'
end) as 'Gender'
from table
-------------------
update table set gender=(case when gender='Male'
then 'Female' else 'Male' end)