I've read a lot of the examples on self join, but they don't seem to cover the case where some fields are not in some rows.
For eg, I have a database with:
testId, testItem, testResult
And the rows:
1,test1,1
1,test2,0
1,test3,1
2,test1,0
2,test4,1
2,test5,1
I would like the output:
testItem,a.testId,b.testId,a.testResult,b.testResult
test1,1,2,1,0
test2,1,NULL,0,NULL
test3,1,NULL,1,NULL
test4,NULL,2,NULL,1
test5,NULL,2,NULL,1
Essentially, I want to compare each testItem (test1->test5) from two different testIds (1 and 2) and compare their testResult values, factoring in testIds that may not have the same test Items.
Given your exact requirement, you can try this:
select testItem
, max(case when testID = 1 then testID else null end) as testID1
, max(case when testID = 2 then testID else null end) as testID2
, max(case when testID = 1 then testResult else null end) as testResult1
, max(case when testID = 2 then testResult else null end) as testResult2
from mytable
where testID in (1,2)
group by testItem
This makes a lot of assumptions about your data, so take it with a grain of salt.
It looks like you want a FULL OUTER JOIN, which is not supported in MySQL. You can emulate this with a UNION of two queries: a LEFT JOIN query and RIGHT JOIN which throws out matching rows.
Something like this will return the specified resultset:
SELECT a.testItem
, a.testId AS `a.testId`
, b.testId AS `b.testId`
, a.testResult AS `a.testResult`
, b.testResult AS `b.testResult`
FROM mytable a
LEFT
JOIN mytable b
ON b.testItem = a.testItem
AND b.testId = 2
WHERE a.testId = 1
AND a.testItem IN ('test1','test2','test3','test4','test5')
UNION ALL
SELECT d.testItem
, c.testId
, d.testId
, c.testResult
, d.testResult
FROM mytable d
LEFT
JOIN mytable c
ON c.testItem = d.testItem
AND c.testId = 1
WHERE d.testId = 2
AND d.testItem IN ('test1','test2','test3','test4','test5')
AND c.testId IS NULL
ORDER
BY 1,2,4
(I included the predicates on testItem IN ('test1' thru 'test5') because you specified that as a requirement; those predicates could be removed if you want all values for testItem included.)
SQLFiddle Demo
select testItem,
group_concat(IFNULL(testId,'null') separator ', ') testIds,
group_concat(IFNULL(testResult, 'null') separator ', ') testResults
from table_name group by testItem;
Related
I need put a column result in to horizontal position, like SUM(CASE WHEN status = 'On Hold' THEN 1 ELSE 0 END) AS 'word' do, I tried a subquery and alias AS too but I didn't have had success. I think that JOIN is to multiple tables, and UNION to get results in same column.
I'm using this page as reference
https://www.mysqltutorial.org/mysql-case-function/
mysql Table: phpvms_pireps
pilotid|flightnum|submitdate|accepted
My sql code:
SELECT DISTINCT `phpvms_pireps`.`pilotid`
, `phpvms_pireps`.`accepted`
, `phpvms_pireps`.`flightnum`
, `phpvms_pireps`.`submitdate`
FROM phpvms_pireps
WHERE ((`phpvms_pireps`.`flightnum` in ('A-1', 'A-2', 'A-3', 'A-4')))
AND submitdate BETWEEN '2020-04-09' AND '2020-04-11'
ORDER
BY `phpvms_pireps`.`pilotid` ASC
The result:
And I want to achieve this:
I'm using php/html, How I can get that result?
Thank you very much!
You are describing a pivot table. Consider using conditional aggregation:
select
pilotid,
max(case when flightnum = 'A-1' then accepted end) a1,
max(case when flightnum = 'A-2' then accepted end) a2,
max(case when flightnum = 'A-3' then accepted end) a3,
max(case when flightnum = 'A-4' then accepted end) a4
from phpvms_pireps
where
flightnum in ('A-1', 'A-2', 'A-3', 'A-4')
and submitdate between '2020-04-09' and '2020-04-11'
group by pilotid
order by pilotid
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>;
I have this query:
SELECT i.d, COUNT(id) AS dr, COUNT(id2) AS dn, SUM(eq) AS eq_sum, COUNT(thx) AS thx_count
FROM dsd
INNER JOIN
(
SELECT COUNT(id) AS d FROM ds
) i
Now I want to use WHERE only to column thx like WHERE thx="y" , so that it will count only all values with "y".
But If I just add WHERE at the end of the query it will affect other columns as well which I don't want to.
How to do this?
Then change your COUNT(thx) AS thx_count to below using CASE expression like
COUNT(CASE WHEN thx = 'y' THEN 1 ELSE 0 END) AS thx_count
(OR)
SUM(CASE WHEN thx = 'y' THEN 1 ELSE 0 END) AS thx_count
Having some trouble figuring out the logic to this. See the two queries below:
Query 1:
SELECT cId, crId, COUNT(EventType)
FROM Data
WHERE EventType='0' OR EventType='0p' OR EventType='n' OR EventType = 'np'
GROUP BY crId;
Query 2:
SELECT cId, crId, COUNT(EventType) AS Clicks
FROM Data
WHERE EventType='c'
GROUP BY crId;
Was just wondering if there was a way to make the column that I would get at the end of query 2 appear in query 1. Since the where statements are different, not really sure where to go, and any subquery that I've wrote just hasn't worked.
Thanks in advance
SELECT cId, crId,
SUM(CASE WHEN EventType='0' OR EventType='0p' OR EventType='n' OR EventType = 'np' THEN 1 ELSE 0 END) AS Count_1,
SUM(CASE WHEN EventType='c' THEN 1 ELSE 0 END) AS Count_2
FROM Data
WHERE EventType IN ('0','0p','n','np','c')
GROUP BY crId;
You can join the two, using the second as a correlated subquery.
SELECT
Data.cId,
Data.crId,
COUNT(EventType) AS event_type_count,
click_counts.Clicks
FROM
Data
/* Correlated subquery retrieves the Clicks (EventType 'c') per cId */
LEFT JOIN (
SELECT cId, crId, COUNT(EventType) AS Clicks
FROM Data
WHERE EventType='c'
GROUP BY crId
) AS click_count ON Data.cId = click_count.cId AND Data.crId = click_count.crId
/* OR chain replaced with IN() clause */
WHERE Data.EventType IN ('0','0p','n','np')
/* This GROUP BY should probably also include Data.cId... */
GROUP BY Data.crId;
You can do this all querying from the table once and using CASE statements.
SELECT cId, crId,
SUM(CASE WHEN EventType IN ('0', '0p', 'n', 'np') THEN 1 ELSE 0 END) as events,
SUM(CASE WHEN EventType = 'c' THEN 1 ELSE 0 END) as clicks
FROM Data
WHERE EventType IN ('0', '0p', 'n', 'np', 'c')
GROUP BY crId;
You want to use IN?
SELECT cId, crId, COUNT(EventType) as Clicks
FROM Data
WHERE EventType IN ('0','0p','n','np','c')
GROUP BY crId;
:) PUtting myself in right direction ;)
sqlfiddle demo
select id, crid,
count(case when type <> 'c'
then crid end) count_others,
count(case when type ='c'
then crid end) count_c
from tb
group by crid
;
I am trying to get the count of females and males in the gender field of a table.
Is there a way to get the count of each in one query?
Something like:
select * from table count(where gender = 'm') as total_males, count(where gender = 'f') as total_females;
or will it require two queries?
select count(*) from table where gender = 'm';
select count(*) from table where gender = 'f';
This is basically a PIVOT. MySQL does not have a pivot so you can use an aggregate function with a CASE statement to perform this:
select
sum(case when gender = 'm' then 1 else 0 end) Total_Male,
sum(case when gender = 'f' then 1 else 0 end) Total_Female
from yourtable
See SQL Fiddle with Demo
Or using COUNT:
select
count(case when gender = 'm' then 1 else null end) Total_Male,
count(case when gender = 'f' then 1 else null end) Total_Female
from yourtable;
See SQL Fiddle with Demo
Something like this will work:
SELECT SUM(IF(t.gender='m',1,0)) AS total_males
, SUM(IF(t.gender='f',1,0)) AS total_females
FROM mytable t
The "trick" here is that we are using a conditional test to return either a 0 or a 1 for each row, and then adding up the 0's and 1's. To make this a little more clear, I am using the SUM aggregate function rather than COUNT, although COUNT could be used just as easily, though we'd need to return a NULL in place of the zero.
SELECT COUNT(IF(t.gender='m',1,NULL)) AS total_males
, COUNT(IF(t.gender='f',1,NULL)) AS total_females
FROM mytable t
Consider that the two expressions in the SELECT list of this query:
SELECT COUNT(1)
, SUM(1)
FROM mytable t
Will return the same value.
If you want to avoid the MySQL IF function, this can also be done using the ANSI SQL CASE expression:
SELECT SUM( CASE WHEN t.gender = 'm' THEN 1 ELSE 0 END )) AS total_males
, SUM( CASE WHEN t.gender = 'f' THEN 1 ELSE 0 END )) AS total_females
FROM mytable t
select sum(case when gender='m' then 1 else null end) as total_males, sum(case when gender='f' then 1 else null end) as total_females from ...
Should work just fine!
If your only issue is to avoid two queries, you can always write two queries as subselects of one query.
Select (select 1 from dual) as one, (select 2 from dual) as two from dual
This would work for your scenario, too.