convert rows to columns in mysql - 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.

Related

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

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'
...

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, filtering but counting for different values

I'm writing a simple football database, and in that database, I want teams are played in UEFA but count the number of wins in the UEFA.
Teams can play UEFA and results should be 'win' 'draw' or 'lose'
To do that, I wrote this query but I do not know how should I change the count statement, because this query gives the number of matches for each team that is played in UEFA.
SELECT t.name, count(*) as Wins
FROM Teams t, Matches m
WHERE competion = 'UEFA' AND t.name = m.team
GROUP BY t.name
With the appropriate criteria, it will look something like:
SELECT t.name, count(*) as matches,
sum(case when result = "win" then 1 else 0 end) as wins,
sum(case when result = "draw" then 1 else 0 end) as draws,
sum(case when result = "loss" then 1 else 0 end) as losses
FROM Teams t, Matches m
WHERE competion = 'UEFA' AND t.name = m.team
GROUP BY t.name

mysql grouping a status field

I have a table
id, location, status
1, london, 1
2, london, 0
3, boston, 1
4, boston, 1
I'd like my query to generate something like this: -
location, status_1, status_0
london, 1, 1
boston, 2, 0
so far I have: -
select count(id) as freq, location from my_table
group by location order by freq desc;
I'm completely lost as to where to go from here.
That sort of transformation is better done in whatever client is issuing the query, but if you have to do it in the database, then
select location,
sum(status = 1) AS status_1,
sum(status = 0) AS status_0
from my_table
group by location
it's a bit hackish, but the 'status = 1' when status really is 1 will evaluate to a boolean true, which MySQL will politely cast to an integer '1', which then gets summed up. Same goes for when status is 0 and status = 0 evaluates to true.
So you want to count the records for each status per city?
In the query below, I group by location (like your did), and then add a sum for each state. Inside the sum is a case, that either returns 1 if the record matches the desired state, or 0 otherwise. That way, you effectively count the number of records for each state per location.
select
a.location,
sum(case when a.status = 1 then 1 else 0 end) as status_1,
sum(case when a.status = 0 then 1 else 0 end) as status_0
from
YourTable a
group by
a.location
select location,
sum(case when status = 1 then 1 else 0 end) as status_1,
sum(case when status = 0 then 1 else 0 end) as status_0,
from my_table
group by location;

MYSQL different conditions in a single query

Hello
I have following columns in mysql table: rating1, rating2, price, cond, approved
Is it possible to select results like this:
select
average rating1 + rating2 as total_rating,
average rating1 as rating1,
average rating2 as rating2,
average price if cond = '1' as price_used
average price if cond = '2' as price_new
where approved = '1'
So far I have:
SELECT
(AVG(t.rating1) + AVG(t.rating2)) / 2 AS total_rating
AVG(t.rating1) AS rating1,
AVG(t.rating2) AS rating2,
---- price statements?? ----
FROM t
WHERE 1=1
AND t.approved = '1'
Many thanks and excuse me for my English
Try this:
SELECT (AVG(t.rating1) + AVG(t.rating2)) / 2 AS total_rating,
AVG(t.rating1) AS rating1,
AVG(t.rating2) AS rating2,
AVG(IF(cond='1', price, NULL)) price_used,
AVG(IF(cond='2', price, NULL)) price_new
FROM t
WHERE 1=1
AND t.approved = '1'
EDIT: Updated the query to get desired result.
Standard SQL, works across "all" major dbms:
select (avg(t.rating1) + avg(t.rating2)) / 2 as total_rating
,avg(t.rating1) as rating1
,avg(t.rating2) as rating2
,avg(case when cond = '1' then price end) as price_used
,avg(case when cond = '2' then price end) as price_new
from t
where t.approved = '1'
I don't think doing an average on the If statement will work. But here is the syntax for the IF.
IF(condition, value_to_display_if_true, value_to_display_if_false)
So, for example, IF(1=1, 'true', 'false') would always display 'true' for this column because 1 does = 1.