Adding two columns in mysql distinguish the count of male and female - mysql

I am trying to add two new columns to my query to be able to get the count of males and females
SELECT adggeth.reg01_maininfo.techname AS TechName
,adggeth.reg01_maininfo.techmobile AS Mobile
,monthname(adggeth.lng02_rpt_b_calvedets.calvdatealv) AS "Calving Month"
,count(adggeth.lng02_rpt_b_calvedets.sex) AS "No of Calves"
FROM adggeth.reg01_maininfo
INNER JOIN adggeth.lng02_maininfo ON adggeth.reg01_maininfo.techmobile = adggeth.lng02_maininfo.aitechid
INNER JOIN adggeth.lng02_rpt_b_calvedets ON adggeth.lng02_maininfo.hh_id = adggeth.lng02_rpt_b_calvedets.hh_id
AND adggeth.lng02_maininfo.visitdate = adggeth.lng02_rpt_b_calvedets.visitdate
GROUP BY adggeth.reg01_maininfo.techname
,adggeth.reg01_maininfo.techmobile
,monthname(adggeth.lng02_rpt_b_calvedets.calvdatealv);
I need to count the number of my female and male calves where
lng02_rpt_b_calvedets.sex = 1 refers to male calves
lng02_rpt_b_calvedets.sex = 2 refers to female calves

Just found my answer
SELECT
adggeth.reg01_maininfo.techname AS TechName,
adggeth.reg01_maininfo.techmobile AS Mobile,
MONTHNAME(
adggeth.`serv00_rpt_calvdtls2`.`calvdatealv2`
) AS "Calving Month",
COUNT(
adggeth.`serv00_rpt_calvdtls2`.`sex2`
) AS "No of Calves",
COUNT(
IF (
adggeth.serv00_rpt_calvdtls2.sex2 = 2,
adggeth.serv00_rpt_calvdtls2.sex2,
NULL
)
) AS 'Femal Calf',
COUNT(
IF (
adggeth.serv00_rpt_calvdtls2.sex2 = 1,
adggeth.serv00_rpt_calvdtls2.sex2,
NULL
)
) AS 'Male Calf'
FROM
adggeth.reg01_maininfo
INNER JOIN adggeth.`serv00_maininfo`
ON adggeth.reg01_maininfo.techmobile = adggeth.`serv00_maininfo`.`aitechid`
INNER JOIN adggeth.`serv00_rpt_calvdtls2`
ON adggeth.`serv00_maininfo`.`fid` = adggeth.`serv00_rpt_calvdtls2`.`fid`
AND adggeth.`serv00_maininfo`.`regdate` = adggeth.`serv00_rpt_calvdtls2`.`calvdatealv2`
GROUP BY adggeth.reg01_maininfo.techname,
adggeth.reg01_maininfo.techmobile,
MONTHNAME(
adggeth.`serv00_rpt_calvdtls2`.`calvdatealv2`
)

You can use a count call on a case expression that filters the calves according to their sex:
COUNT (CASE adggeth.lng02_rpt_b_calvedets.sex WHEN 1 END) as "No of Male Calves",
COUNT (CASE adggeth.lng02_rpt_b_calvedets.sex WHEN 2 END) as "No of Female Calves"

You can also use COUNT aggregation with IF function:
COUNT (IF(adggeth.lng02_rpt_b_calvedets.sex = 1, 1, NULL) ) AS Male_Calves_Count,
COUNT (IF(adggeth.lng02_rpt_b_calvedets.sex = 2, 1, NULL) ) AS Female_Calves_Count,

While COUNT will not count NULLs, and therefore it is possible to use some condition which returns NULL if it's not the value you're looking for, it's much simpler to use SUM instead. Boolean expressions in MySQL return 1 or 0, so you can add up their values directly.
SELECT
SUM(adggeth.serv00_rpt_calvdtls2.sex2 = 2) AS 'Female Calf',
SUM(adggeth.serv00_rpt_calvdtls2.sex2 = 1) AS 'Male Calf'
...

Related

I want to find the sum of the counts of tables in SQL

Please find below the Query i use
select cm.city_name,
count(case when k.listing_status_uid=1 then 1 end ) as 'Active',
count(case when k.listing_status_uid=3 then 1 end ) as 'Bad_listing',
count(case when k.listing_status_uid=4 then 1 end ) as 'proj_scrapped',
count(case when k.listing_status_uid=5 then 1 end ) as 'proj_on_hold',
count(case when k.listing_status_uid=6 then 1 end ) as 'sold_out',
count(case when k.listing_status_uid=7 then 1 end ) as 'others'
from ksl_listing_master k
join ksl_locality_master lm on lm.locality_uid=k.listing_locality
join ksl_city_master cm on cm.city_uid=lm.city_uid
join ksl_listing_status ls on ls.listing_status_uid=k.listing_status_uid
group by cm.city_name
This gives an output like the below one
Now I want the sum of each individual column.
Below the city names Sum should be there
I want the individual sum of Active, Bad_listing, proj_scrapped, proj_on_hold, sold_out, and others in the same Query.
If I understand correctly, you just want a summary row. You can do this using with rollup:
select . . .
group by cm.city_name with rollup;
You seems want :
select cm.city_name,
sum(k.listing_status_uid = 1) as 'Active',
sum(k.listing_status_uid = 3) as 'Bad_listing',
sum(k.listing_status_uid = 4) as 'proj_scrapped',
. . .
sum(k.listing_status_uid in (1,3,4)) as 'total'
from ksl_listing_master k join
ksl_locality_master lm
on lm.locality_uid = k.listing_locality join
ksl_city_master cm
on cm.city_uid=lm.city_uid join
ksl_listing_status ls
on ls.listing_status_uid = k.listing_status_uid
group by cm.city_name;

COUNT multiple types of same column

In my current query:
SELECT COUNT(WC.ID) AS "Regions"
FROM WHOLE_FEATURES_PDB_CHAINS AS WC
;
I COUNT(WC.ID) AS "Regions" .
However, we have multiple regions with WC.Type can be 1,2,3,4. I need to count each type occurrence into COUNT(WC.ID) AS "Region_1", COUNT(WC.ID) AS "Region_2" ... depending on WC.Type.
Is there any way to solve this in one query? I am looking at MySQL IF, yet do not know how to integrate it into the count function.
I need it to be in one row (the shown query here is reduced, it's a larger query)
SELECT COUNT(WC.ID) AS "Region_1" , COUNT(WC.ID) AS "Region_2" ...
Here is the complete query if anyone is interested:
SELECT PCS.PDB_id, PCS.Chain, PPA.ENSEMBL_start, PPA.ENSEMBL_end, PPA.eValue, PIN.TITLE AS "pdbTitle", COUNT(WC.ID) AS "Regions"
FROM PDB_Chains AS PCS
LEFT JOIN WHOLE_FEATURES_PDB_CHAINS AS WC ON WC.PDB_CHAIN_ID = PCS.idPDB_chains, PDB_protein_alignment PPA, PDB_INFOS PIN
WHERE PCS.idPDB_chains = PPA.idPDB_Chains
AND PCS.PDB_id = PIN.PDB_ID
AND PPA.idProteins = (SELECT idProteins from Proteins WHERE ENSEMBL_protein_id = "'+submittedID+'")
GROUP BY PCS.PDB_id, PCS.Chain ORDER BY PCS.PDB_id;
Here's the working solutin based on your kind answers
SELECT PIN.TITLE AS "pdbTitle", COUNT(CASE WHEN WC.STRUCTURAL_FEATURES_ID = 1 then 1 end) AS "PPInterface" , COUNT(CASE WHEN WC.STRUCTURAL_FEATURES_ID = 4 then 1 end) AS "flexibleRegions"
FROM PDB_Chains AS PCS LEFT JOIN WHOLE_FEATURES_PDB_CHAINS AS WC ON WC.PDB_CHAIN_ID = PCS.idPDB_chains, PDB_protein_alignment PPA, PDB_INFOS PIN
WHERE PCS.idPDB_chains = PPA.idPDB_Chains
AND PCS.PDB_id = PIN.PDB_ID
AND PPA.idProteins = (SELECT idProteins from Proteins WHERE ENSEMBL_protein_id = "ENSP00000256078.4")
GROUP BY PCS.PDB_id, PCS.Chain ORDER BY PCS.PDB_id;
You can use case when statement inside your aggregate function.
Try this .
count(case when WC.type = 1 then 1 end) as region_1, similarly repeat for another column.
Select
...
...
sum(if WC.ID = 1 then 1 else 0) as Region1,
sum(if WC.ID = 2 then 1 else 0) as Region2,
sum(if WC.ID = 3 then 1 else 0) as Region3,
sum(if WC.ID = 4 then 1 else 0) as Region4
Might do what you want.
You can use GROUP BY with COUNT to get the required result, e.g.:
SELECT WC.Type, COUNT(WC.ID) AS "Regions"
FROM WHOLE_FEATURES_PDB_CHAINS AS WC
GROUP BY WC.Type;
Update
If you want the counts as pivoted column for each region then you can write inner SELECT queries, e.g.:
SELECT
(SELECT COUNT(ID) FROM WHOLE_FEATURES_PDB_CHAINS WHERE type = 1) AS "Region_1",
(SELECT COUNT(ID) FROM WHOLE_FEATURES_PDB_CHAINS WHERE type = 2) AS "Region_2",
other_column
FROM WHOLE_FEATURES_PDB_CHAINS AS WC
WHERE <some condition>;

MySQL How to make a SELECT SUM from Table and multiplication from other SEARCH?

I have this query
SELECT ps_ur AS UR, COUNT(ps_ur) AS Value
FROM patient_services
GROUP BY UR
UNION ALL
SELECT eng_ur AS UR, COUNT(eng_ur) AS Value
FROM engagements
WHERE LENGTH( eng_ur )>0
GROUP BY UR
Result:
UR Value
002035 3
002400 2
005441 4
...
Now I need to calculate from Patient table Male/Female and multiply by the Value
Like this but right
SELECT
SUM( CASE WHEN patient_gender = 'Male' THEN 1 ELSE 0 END ) Male,
SUM( CASE WHEN patient_gender = 'Female' THEN 1 ELSE 0 END ) Female
FROM patients WHERE patient_ur
How to do this?
In that case you want wrap the first as inner query. Something like below. Now you can access the Value field saying xxx.Value and multiply or do whatever processing needed. Not sure where you want to multiply and thus couldn't reflect it in suggested query. Probably that's left as homework for you.
SELECT
SUM( CASE WHEN patient_gender = 'Male' THEN 1 ELSE 0 END ) Male,
SUM( CASE WHEN patient_gender = 'Female' THEN 1 ELSE 0 END ) Female
FROM patients JOIN (
SELECT ps_ur AS UR, COUNT(ps_ur) AS `Value`
FROM patient_services
GROUP BY UR
UNION ALL
SELECT eng_ur AS UR, COUNT(eng_ur) AS `Value`
FROM engagements
WHERE LENGTH( eng_ur )>0
GROUP BY UR ) xxx ON patients.patient_ur = xxx.UR

How to split SQL query results into columns based on two WHERE conditions and two calculated COUNT fields?

I have the following (simplified) database schema:
Persons:
[Id] [Name]
-------------------
1 'Peter'
2 'John'
3 'Anna'
Items:
[Id] [ItemName] [ItemStatus]
-------------------
10 'Cake' 1
20 'Dog' 2
ItemDocuments:
[Id] [ItemId] [DocumentName] [Date]
-------------------
101 10 'CakeDocument1' '2016-01-01 00:00:00'
201 20 'DogDocument1' '2016-02-02 00:00:00'
301 10 'CakeDocument2' '2016-03-03 00:00:00'
401 20 'DogDocument2' '2016-04-04 00:00:00'
DocumentProcessors:
[PersonId] [DocumentId]
-------------------
1 101
1 201
2 301
I have also set up an SQL fiddle to play with: http://www.sqlfiddle.com/#!3/e6082
The relation logic is the following: every Person can work on zero or infinite number of ItemDocuments (many-to-many); each ItemDocument belongs to exactly one Item (one-to-many). Item has status 1 - Active, 2 - Closed
What I need is a report that fulfills the following requirements:
for each person in Persons table, display count of Items that have ItemDocuments related to this person
the counts should be split in two columns by ItemStatus
the query should be filterable by two optional date periods (using two BETWEEN conditions on ItemDocuments.Date field) and the Item counts should also be split into two periods
if a Person does not have any ItemDocuments assigned, it still should be shown in the results with all count values set to 0
if a Person has more than one ItemDocument for an Item, the Item still should be counted only once
Essentially, here is how the results should look like if I use both periods to NULL (to read all the data):
[PersonName] [Active Items for period 1] [Closed Items for period 1] [Active Items for period 2] [Closed Items for period 2]
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
'Peter' 1 1 1 1
'John' 1 0 1 0
'Anna' 0 0 0 0
While I can create an SQL query for each requirement separately, I have a problem to understand how to combine all of them together into one.
For example, I can split ItemStatus counts in two columns using
COUNT(CASE WHEN t.ItemStatus = 1 THEN 1 ELSE NULL END) AS Active,
COUNT(CASE WHEN t.ItemStatus = 2 THEN 1 ELSE NULL END) AS Closed
and I can filter by two periods (with max/min date constants from MS SQL server specification to avoid NULLs for optional period dates) using
between coalesce(#start1, '1753-01-01') and coalesce(#end1, '9999-12-31')
between coalesce(#start2, '1753-01-01') and coalesce(#end2, '9999-12-31')
but how to combine all of this together, considering also JOINs between tables?
Is there any technique, join or MS SQL Server specific approach to do this in efficient way?
My first attempt seems to work as required but it looks like ugly subquery duplications multiple times:
DECLARE #start1 DATETIME, #start2 DATETIME, #end1 DATETIME, #end2 DATETIME
-- SET #start2 = '2017-01-01'
SELECT
p.Name,
(SELECT COUNT(1)
FROM Items i
WHERE i.ItemStatus = 1 AND EXISTS(
SELECT 1
FROM DocumentProcessors AS dcp
INNER JOIN ItemDocuments AS idc ON dcp.DocumentId = idc.Id
WHERE dcp.PersonId = p.Id AND idc.ItemId = i.Id
AND idc.Date BETWEEN COALESCE(#start1, '1753-01-01') AND COALESCE(#end1, '9999-12-31')
)
) AS Active1,
(SELECT COUNT(*)
FROM Items i
WHERE i.ItemStatus = 2 AND EXISTS(
SELECT 1
FROM DocumentProcessors AS dcp
INNER JOIN ItemDocuments AS idc ON dcp.DocumentId = idc.Id
WHERE dcp.PersonId = p.Id AND idc.ItemId = i.Id
AND idc.Date BETWEEN COALESCE(#start1, '1753-01-01') AND COALESCE(#end1, '9999-12-31')
)
) AS Closed1,
(SELECT COUNT(1)
FROM Items i
WHERE i.ItemStatus = 1 AND EXISTS(
SELECT 1
FROM DocumentProcessors AS dcp
INNER JOIN ItemDocuments AS idc ON dcp.DocumentId = idc.Id
WHERE dcp.PersonId = p.Id AND idc.ItemId = i.Id
AND idc.Date BETWEEN COALESCE(#start2, '1753-01-01') AND COALESCE(#end2, '9999-12-31')
)
) AS Active2,
(SELECT COUNT(*)
FROM Items i
WHERE i.ItemStatus = 2 AND EXISTS(
SELECT 1
FROM DocumentProcessors AS dcp
INNER JOIN ItemDocuments AS idc ON dcp.DocumentId = idc.Id
WHERE dcp.PersonId = p.Id AND idc.ItemId = i.Id
AND idc.Date BETWEEN COALESCE(#start2, '1753-01-01') AND COALESCE(#end2, '9999-12-31')
)
) AS Closed2
FROM Persons p
I'm not absolutely sure if I really got what you want, but you might try this
WITH AllData AS
(
SELECT p.Id AS PersonId
,p.Name AS Person
,id.Date AS DocDate
,id.DocumentName AS DocName
,i.ItemName AS ItemName
,i.ItemStatus AS ItemStatus
,CASE WHEN id.Date BETWEEN COALESCE(#start1, '1753-01-01') AND COALESCE(#end1, '9999-12-31') THEN 1 ELSE 0 END AS InPeriod1
,CASE WHEN id.Date BETWEEN COALESCE(#start2, '1753-01-01') AND COALESCE(#end2, '9999-12-31') THEN 1 ELSE 0 END AS InPeriod2
FROM Persons AS p
LEFT JOIN DocumentProcessors AS dp ON p.Id=dp.PersonId
LEFT JOIN ItemDocuments AS id ON dp.DocumentId=id.Id
LEFT JOIN Items AS i ON id.ItemId=i.Id
)
SELECT PersonID
,Person
,COUNT(CASE WHEN ItemStatus = 1 AND InPeriod1 = 1 THEN 1 ELSE NULL END) AS ActiveIn1
,COUNT(CASE WHEN ItemStatus = 2 AND InPeriod1 = 1 THEN 1 ELSE NULL END) AS ClosedIn1
,COUNT(CASE WHEN ItemStatus = 1 AND InPeriod2 = 1 THEN 1 ELSE NULL END) AS ActiveIn2
,COUNT(CASE WHEN ItemStatus = 2 AND InPeriod2 = 1 THEN 1 ELSE NULL END) AS ClosedIn2
FROM AllData
GROUP BY PersonID,Person

convert rows to columns in mysql

I have a table in database that looks like:
I am trying to create query which gives me result like:
And when I was searching trough the forum I did found information about converting rows to columns using aggregate function and/or using predefined statement. From example what I did found I did try following queries however they doesn't work I don't understand how they work so I simply copy the query. I did try to use my data in it:
select fk_playerID as name, roundID as roundNo, score
from(
roundID,
CASE WHEN roundID = 1 THEN score END AS 1,
CASE WHEN roundID = 2 THEN score END AS 2,
CASE WHEN roundID = 3 THEN score END AS 3,
from cup
) cup group by fk_playerID
and the second one:
SELECT fk_playerID as name, roundID as roundNo, score
MAX(CASE WHEN'roundID' = 1, THEN score end) roundNo1,
MAX(CASE WHEN'roundID' = 2, THEN score end) roundNo2,
MAX(CASE WHEN'roundID' = 3, THEN score end) roundNo3
FROM cup
ORDER BY fk_playerID
And finally my question is how my query must look like and also I need a little explanation how it works.
The second one is pretty close:
SELECT c.fk_playerID,
p.Name
MAX(CASE WHEN c.roundID = 1 THEN c.score END) AS roundNo1,
MAX(CASE WHEN c.roundID = 2 THEN c.score END) AS roundNo2,
MAX(CASE WHEN c.roundID = 3 THEN c.score END) AS roundNo3
FROM cup c
JOIN Player p on c.fk_playerID = p.ID
GROUP BY c.fk_playerID, p.Name
You are grouping by fk_playerID. Lets consider player = 1. This
CASE WHEN roundID = 1 THEN score END
will produce the following set for score: {1, null, null}. Max will return 1.
CASE WHEN roundID = 2 THEN score END
will produce the following set for score: {null, 1, null}. Max will return 1.
CASE WHEN roundID = 3 THEN score END
will produce the following set for score: {null, null, 1}. Max will return 1.
The same for player = 19.