I have these two tables:
Person
Name Gender RegionID
Bob Male 1
Mary Female 2
Jane Female 3
Chris Male 1
Paul Male 2
Matt Male 2
Jenny Female 1
Region
ID Region
1 North
2 South
3 Central
I would like to end up with a table like this:
Region Male Female
North 2 1
South 2 1
Central 0 1
I first tried to get the resulting table with the region's ID in there so no join required:
select RegionID, Gender, count(Name) from Person group by RegionID
But the Gender field is coming back undefined. And didn't really know where to go from there.
As tagged, I'm using the alasql JavaScript library.
Try to look at this:
SELECT A.Region
, SUM(CASE WHEN Gender = 'Male' Then 1 else 0 end) Male
, SUM(CASE WHEN Gender = 'Female' Then 1 else 0 end) Female
FROM Region A
Inner Join Person B
On A.ID = B.RegionID
Group By A.Region
You can use this
select region
,sum(case when b.Gender='Male' then 1 else 0 end) Male
,sum(case when b.Gender='Female' then 1 else 0 end) Female
from Region a
inner join Person b on a.[Id]=b.RegionID
group by a.[Id],a.Region
order by [id]
In tsql you can pivot, which might be easier if you have more than a couple of values to pivot on:
Select * from
( select Region ,Gender
from Region a
inner join Person b on a.[Id]=b.RegionID ) p
pivot
( count(Gender)
for Gender
IN ([Male],[Female])
) pivottable
If you add a third gender, nonbinary like this
insert into Person values ('Kim','Nonbinary',3)
You can easily extend you query to account for that:
Select * from
( select Region ,Gender
from Region a
inner join Person b on a.[Id]=b.RegionID ) p
pivot
( count(Gender)
for Gender
IN ([Male],[Female],[Nonbinary])
) pivottable
order by a.[id]
For anyone looking for the final solution in alasql, this is what I came up with thanks to the help from this page:
var res = alasql("SELECT regionData.Title \
, SUM(CASE WHEN peopleData.Gender = 'Male' THEN 1 ELSE 0 END) AS Male \
, SUM(CASE WHEN peopleData.Gender = 'Female' THEN 1 ELSE 0 END) AS Female \
FROM ? regionData LEFT JOIN ? peopleData \
ON regionData.ID = peopleData.RegionID\
GROUP BY regionData.Title", [regionData, bensData]);
Related
CAMPAIGN table
ID
campaign_name
1
Campaign A
2
Campaign B
PARTICIPANT table
ID
campaign_id
participant_name
1
1
Alice
2
1
Ben
CUSTOM_FIELD table
ID
campaign_id
field_name
1
1
Gender
2
1
Age
FIELD_ANSWER table
ID
participant_id
field_id
answer
1
1
1
Female
2
1
2
24
3
2
1
Male
4
2
2
28
With these tables in above, can we query a result as shown below?
Campaign Name
Participant Name
Gender
Age
Campaign A
Alice
Female
24
Campaign A
Ben
Male
28
Using pivoting logic we can try:
SELECT
c.campaign_name,
p.participant_name,
MAX(CASE WHEN cf.field_name = 'Gender' THEN fa.answer END) AS Gender,
MAX(CASE WHEN cf.field_name = 'Age' THEN fa.answer END) AS Age
FROM CAMPAIGN c
INNER JOIN PARTICIPANT p
ON p.campaign_id = c.ID
INNER JOIN FIELD_ANSWER fa
ON fa.participant_id = p.ID
INNER JOIN CUSTOM_FIELD cf
ON cf.ID = fa.field_id AND cf.campaign_id = c.ID
GROUP BY
c.campaign_name,
p.participant_name;
Here is a demo in SQL Server, though the above query should run on most other database as well.
I have table of people, another table of cars and a third table to join them since they have a many to many relationship. I want to select people who own a certain set of cars and group them by a region property on the person. So for example I would want to find all American's who own a Honda and a Nissan.
Example:
people table
id name region
1 Jon America
2 Jane Europe
3 Mike America
cars table
id make
1 Honda
2 Toyota
3 Nissan
people_cars table
person_id car_id
1 1
1 3
2 2
3 1
Desired result:
region own_honda_and_nissan
America 1
Europe 0
An idea for a SQL expression I have is:
SELECT
people.region,
CASE WHEN SUM(CASE WHEN cars.name IN ('Honda', 'Nissan') THEN 1 ELSE 0 END) = 2 THEN 1 ELSE 0 AS own_honda_and_nissan
FROM people
JOIN people_cars ON people_cars.person_id = people.id
JOIN cars ON people_cars.car_id = cars.id
GROUP BY people.region
HAVING
SUM(CASE WHEN cars.name IN ('Honda', 'Nissan') THEN 1 ELSE 0 END) = 2
ORDER BY own_honda_and_nissan DESC
This works if you group by people.id but once they get grouped by region it no longer works.
Use two levels of aggregation:
SELECT p.pregion, COUNT(*) as own_honda_and_nissan
FROM (SELECT pid, p.region,
FROM people p JOIN
people_cars pc
ON pc.person_id = p.id JOIN
cars c
ON pc.car_id = c.id
WHERE c.name IN ('Honda', 'Nissan')
GROUP BY p.id, p.region
HAVING COUNT(DISTINCT c.name) = 2
) p
GROUP BY p.region
ORDER BY own_honda_and_nissan DESC
I have the following 3 tables;
Table_Names:
user_id Name
------------------
1 Mark
2 Tom
3 Ana
Table_Language:
language_id Language
-----------------------
1 English
2 German
Table_Name_Lang
id user_id language_id
---------------------------
1 1 1
2 1 2
3 2 1
4 3 2
How can I create a query to show the expected results like those below?
Name Expr_1_Eng Expr_1_Ger
---------------------------------
Mark English German
Tom English
Ana German
Thanks Tok
I would do:
select n.name,
max(case when l.language = 'English' then l.language end) as has_English,
max(case when l.language = 'German' then l.language end) as has_German
from names n join
name_lang nl
on nl.user_id = n.user_id join
lang l
on nl.language_id = l.language_id
group by n.name
You can try to use JOIN with condition aggregate function
SELECT Name,
MAX(CASE WHEN tnl.language_id = 1 then tl.Language end),
MAX(CASE WHEN tnl.language_id = 2 then tl.Language end)
FROM
Table_Name_Lang tnl
JOIN Table_Names tn on tnl.language_id = tn.language_id
JOIN Table_Language tl on tl.user_id = tnl.user_id
GROUP BY Name
I think you should use pivot:
select n.name,[0] as language_one,[1] as language_two,[2],[3] from
(select n.name,tl.language
tablename n
left join Table_Name_Lang tnl on n.userid=tnl.userid
left join table_language tl on tl.id=tnl.id
group by n.name,tl.language
)T
pivot
(
language
for name in [0],[1],[2],[3]
)AS PivotTable;
I have a column with
Country
-------
Canada
India
USA
India
China
Canada
I want to update this table by inserting another column called M_U which can only have 0 or 1
If country occurs more than once = 1
If country occurs only once = 0
output
-------
Canada 1
India 1
USA 0
India 1
China 0
Canada 1
This should work for you:
select a.country, case when b.c >1 then 1 else 0 end
from countries a
join (
select Country, count(*) as c from countries group by Country
) b on b.country = a.country
You should use windows functions for this:
select t.*,
(case when count(*) over (partition by country) > 1 then 1 else 0 end) as flag
from t;
This is essential a_horse_with_no_name's answer. I'll delete it if that answer is undeleted.
I have the following table, Persons_Companies, that shows a relation between persons and companies knowns by these persons:
PersonID | CompanyID
1 1
2 1
2 2
3 2
4 2
Imagining that company 1 = "Google" and company 2 is = "Microsoft", I would like to know the query to have the following result:
PersonID | Microsoft | Google
1 0 1
2 1 1
3 1 0
4 1 0
Until this moment I have something similar:
select PersonID,
case when CompanyID=1 then 1 else 0
end as Google,
case when EmpresaID=2 then 1 else 0
end as Microsoft
from Persons_Companies
My problem is with the persons that knows both companies, I can't imagine how could this query be.
What is the SQL query?
select PersonID,
case when EXISTS (
SELECT 1
FROM Persons_Companies pc1
WHERE pc.PersonID = pc1.PersonID and pc1.CompanyID = 1 ) then 1 else 0
end as Google,
case when EXISTS (
SELECT 1
FROM Persons_Companies pc2
WHERE pc.PersonID = pc2.PersonID and pc2.CompanyID = 2 ) then 1 else 0
end as Microsoft
from Persons_Companies pc
SELECT personId, sum(case companyId when 1 then 1 else 0 end) google,
sum(case companyId when 2 then 1 else 0 end) microsoft
from Persons_Companies
group by personId
order by personId;
I think this is what you want: http://pastie.org/881092
select
p.person_id,
if(ms.company_id is null,0,1) as 'microsoft',
if(ora.company_id is null,0,1) as 'oracle',
if(mysql.company_id is null,0,1) as 'mysql'
from
person p
left outer join person_company ms on p.person_id = ms.person_id and ms.company_id = 1
left outer join person_company ora on p.person_id = ora.person_id and ora.company_id = 2
left outer join person_company mysql on p.person_id = mysql.person_id and mysql.company_id = 3
order by
p.person_id;
There is a problem with both answers, because there is an assumption that Google and Microsoft will always be the only companies on the table. I believe the query should be generic.
I am not too sure but I think a combination of a cross tab and CTE will work well.