Sum two counts from 2 different tables in sql - sql

I have two tables on db:
1. memberOne
memberName | gender
===================
Jack | M
Steve | M
Audrey | F
2. memberTwo
memberName | gender
===================
Sarah | F
Steve | M
Audrey | F
Alvin | M
I want to display this view:
Gender | Total
=======================
M | 4
F | 3
I performed this code
SELECT t.Gender, COUNT(t.Gender) Total FROM memberOne t
GROUP BY t.Gender
UNION ALL
SELECT d.Gender, COUNT(d.Gender) Total FROM memberTwo d
GROUP BY d.Gender
;
And this is what I got:
Gender | Total
------------- ----------
M 2
F 1
M 2
F 2
How can I sum the total of M and F from each table? Should I use condition to check the gender?
Any helps would be appreciated, thanks.

You need to use UNION ALL and then apply COUNT
SELECT
gender as Gender,
COUNT(*) as Total
FROM
(
SELECT gender
FROM memberOne
UNION ALL
SELECT gender
FROM memberTwo
) group by gender

One approach here would be to union together only the genders from the two tables, and then do a single aggregation to get the male and female counts.
SELECT
gender,
COUNT(*) AS total
FROM
(
SELECT gender
FROM memberOne
UNION ALL
SELECT gender
FROM memberTwo
) t
GROUP BY gender
ORDER BY gender DESC
Demo here:
Rextester

Wrap your last query in another query that sums the count of M and F.
SELECT
G, SUM(Total)
FROM
(SELECT
t.Gender G, COUNT(t.Gender) Total
FROM
memberOne t
GROUP BY
t.Gender
UNION ALL
SELECT
d.Gender G, COUNT(d.Gender) Total
FROM
memberTwo d
GROUP BY
d.Gender)
GROUP BY
gender

One way to accomplish your goal working off your initial query would be:
select Gender, sum(Total) Total
From (your existing query) q
group by q.Gender
A different way would be:
select Gender, Count(Gender) Total
from
( select Gender from membeOne
Union all
Select Gender from memberTwo ) q
group by q.Gender

SELECT n.Gender, COUNT(n.Gender) Total FROM
(
SELECT t.Gender, COUNT(t.Gender) Total FROM memberOne t
GROUP BY t.Gender
UNION ALL
SELECT d.Gender, COUNT(d.Gender) Total FROM memberTwo d
GROUP BY d.Gender
) n
GROUP BY n.Gender
reiterating select and group by after last query

Related

How to select varying count of items per colum value?

I work with Postgresql.
I have a sql code
SELECT lp."RegionId", COUNT(w."Id") FROM public.workplace w
GROUP BY lp."RegionId"
that returns to me
RegionId | Count
1 | 3
2 | 12
3 | 5
I have table 'person'. Each person have RegionId.
So i for region 1 i want to select first 3 persons, for region 2 select first 12 persons, for region 3 select first 5 persons.
So how can i use it as subquery to table 'person'?
WITH (SELECT lp."RegionId", COUNT(w."Id") FROM public.workplace w
GROUP BY lp."RegionId") AS pc
SELECT * FROM public.person p
???????
limit pc."Count"
???
Something like:
SELECT p.*
FROM (SELECT *, row_number() OVER (PARTITION BY RegionId ORDER BY PersonId) AS rn
FROM person) AS p
JOIN (SELECT RegionId, count(*) AS cnt
FROM workplace
GROUP BY RegionId) AS r ON p.RegionId = r.RegionId
WHERE p.rn <= r.cnt
ORDER BY p.RegionId, p.PersonId;

Pivot group multi column SQL

In SQL, how can I merge multiple columns into one column with multiple rows?
Example:
name | age | gender
------+-------+---------
John | 20 | M
Jill | 21 | F
Exam | 22 | M
I want to get this table:
Exam | John | Jill
------+-------+---------
22 | 21 | 20
M | F | M
You can do like this.
Use two PIVOT query with UNION ALL to combine them
SELECT CAST(Exam AS VARCHAR(10)) Exam,
CAST(Jill AS VARCHAR(10)) Jill,
CAST(John AS VARCHAR(10)) John
FROM
(
select age,name
from T
) as x
PIVOT
(
MAX(Age) FOR name IN ([Exam],[John],[Jill])
)AS P1
UNION ALL
SELECT Exam,Jill,John FROM
(
select name,gender
from T
) as x
PIVOT
(
MAX(gender) FOR name IN ([Exam],[John],[Jill])
)AS P1
sqlfiddle:http://sqlfiddle.com/#!18/a437d/6
You can do this using a single query -- basically unpivot and conditional aggregation:
select max(case when v.name = 'Exam' then v.val end) as exam,
max(case when v.name = 'John' then v.val end) as john,
max(case when v.name = 'Jill' then v.val end) as jill
from t cross apply
(values (t.name, cast(t.age as varchar(10)), 1),
(t.name, t.gender, 2)
) v(name, val, which)
group by which;
Here is the SQL Fiddle.
You can convert the values to whatever character type you like for compatibility among the values. You want to put numeric values and strings in the same column, so they have to have the same type.

SQL - GROUP BY and COUNT

I have a table with Column - D and E.
I want to get D, Distinct E in each D, Count of total number of entry for each D. How to write SQL for this ?
Data:
D | E
-----
1 | K
1 | K
1 | A
2 | S
2 | S
2 | S
2 | S
Desired o/p:
D | E | Total_E_in_D
----------------------
1 | K | 3
1 | A | 3
2 | S | 4
SELECT D,E,Count(E in each D)
FROM table
GROUP BY D,E.
Last column should give me the total number of entries for each D.
The specific answer to the question is:
select dept, count(*) as numemployees, count(distinct emp) as numDistinctEmployees
from d1
group by dept;
This just seems quite unusual, because the it assumes that employees would be in the same department more than once.
EDIT:
Strange data format, but just use aggregation with analytic functions:
select dept, emp, sum(count(*)) over (partition by dept) as numEmployees
from d1
group by dept, emp;
You can group on the department and the employee, and join in a query where you group on the department to count the employees:
select
e.Dept,
e.Emp
d.EmpCount
from
table e
inner join (
select
Dept,
count(distinct Emp) as EmpCount
from
table
group by
Dept
) d on d.Dept = e.Dept
group by
e.Dept, e.Emp
You could also use a subquery to count the employees:
select
e.Dept,
e.Emp,
(
select
count(distinct Emp)
from
table d
where
d.Dept = e.Dept
) as EmpCount
from
table e
group by
e.Dept, e.Emp
how's this?
select dept, emp, (select count(*) from table t2 where t2.dept = t1.dept) noEmps
from table t1

Limit number of occurances in output group-by sql query

I have this query
select rep, companyname,count(companyname) as [count], Commission from customers
group by repid,companyname,Commission
It returns lets say
rep companyname count commision
1 ABC 1 10%
2 XYZ 2 10%
2 XYZ 1 20%
3 JKL 4 10%
3 JKL 1 30%
Desire output is
rep companyname count commision
2 XYZ 2 10%
2 XYZ 1 20%
3 JKL 4 10%
3 JKL 1 30%
I would like to have an output so that I show the only those companies who are repeated twice or more in the result. How do I modify the above query. I made the query simple (remove where clause).
I would use a subquery to get the non-unique company names like this.
select rep, companyname,count(companyname) as [count], Commission from customers
where companyname in (
select c1.companyname from customers c1
group by c1.companyname having count(*) >= 2
)
group by repid,companyname,Commission
I think this will match your requirements. I couldn't think of a way of doing it without some sort of sub query or CTE:
select
rep, companyname, [count], commission
from (
select
rep, companyname,count(companyname) as [count], Commission,
count(1) over (PARTITION by companyname) as [companycount]
from customers
group by repid,companyname,Commission
) sub
where companycount > 1
select rep
, companyname
, count(*) as [count] --- equivalent to count(companyname)
, Commission
from customers c
where exists
( select *
from customers c2
where c2.companyname = c.companyname
and ( c2.repid <> c.repid
or c2.Commission <> c.Commission
)
and ( extra-conditions )
)
and ( extra-conditions )
group by repid, companyname, Commission
Add a HAVING clause after your group by, e.g. HAVING count(companyName) > 1
You're looking for the HAVING keyword, which is essentially a WHERE condition for your GROUP BY
select rep, companyname,count(companyname) as [count], Commission from customers
group by repid,companyname,Commission
having count(companyname) > 1

Selecting records with most recent date for each 'order'

I have information in the format of the sample table below. Each file can have multiple grades, I need to select the most recent grade (based on completion date) for each file. If there is a file w/ the same completion dates, I would select the best grade (a being best and subsequent letters being a lesser grade). This seems easy, but for some reason having a brain fart
Sample Table:
ID_PK File_No Grade Completion_Date
1 Smith A 10/1/2010
2 Smith C 9/25/2010
3 Davis B 11/1/2010
4 Johnson D 12/5/2010
5 Johnson A 11/1/2010
6 Johnson C 10/1/2010
7 Miller X 9/1/2010
8 Miller F 12/1/2010
9 Miller D 10/1/2010
Ideal Results:
1 Smith A 10/1/2010
3 Davis B 11/1/2010
4 Johnson D 12/5/2010
8 Miller F 12/1/2010
uSING WINDOWING FUNCTION IS MORE EFFICIENT and also simpler as
with cte AS(
select '1' AS ID_no,'Smith' AS FILE_NO,'A' AS GRADE,
CAST('10/1/2010' AS DATE) AS CREATION_DATE
union all
select '2','Smith','C','9/25/2010'
union all
select '3','Davis','B','11/1/2010'
union all
select '4','Johnson','D','12/5/2010'
union all
select '5','Johnson','A','11/1/2010'
union all
select '6','Johnson','C','10/1/2010'
union all
select '7','Miller','X','9/1/2010'
union all
select '8','Miller','F','12/1/2010'
union all
select '9','Miller','D','10/1/2010')
SELECT X.ID_NO,X.FILE_NO,X.GRADE,X.CREATION_DATE FROM(
SELECT ID_NO,FILE_NO,GRADE,CREATION_DATE ,
ROW_NUMBER() OVER(PARTITION BY FILE_NO ORDER BY CREATION_DATE DESC,GRADE ASC ) AS RN
FROM CTE)AS X
WHERE X.RN=1
ORDER BY ID_NO
try this (untested):
select max_grade.*
from `Sample Table` st
inner join (
select File_No, max(Completion_Date) as Completion_Date
from `Sample Table`
group by File_No
) max_date on st.Completion_Date = max_date.CompletionDate
inner join (
select File_No, Completion_Date, max(Grade) as Grade
from `Sample Table`
group by File_No, Completion_Date
) max_grade on st.File_No = max_grade.File_No and st.Completion_Date = max_grade.Completion_Date
Note that you may need to modify the syntax and table name for your particular DB.
I created a table with your example data. I tested the following query against the table and everything seem to work correctly and matched the example results.
SELECT
ID_PK,
StudentGrade.File_No,
MIN(StudentGrade.Grade),
StudentGrade.Completion_Date
FROM
(
SELECT File_No, MAX(Completion_Date) Completion_Date
FROM StudentGrade
GROUP BY File_No
) Student
INNER JOIN StudentGrade ON
Student.File_No = StudentGrade.File_No
AND StudentGrade.Completion_Date = Student.Completion_Date
GROUP BY ID_PK, StudentGrade.File_No, StudentGrade.Completion_Date
ORDER BY ID_PK