Flatten a response to an SQL query - mysql

I am trying to get a flat table for a question and answer table with mysql. This are my tables.
PollQuestion
PollID | Question| A | B | C | D | E | TimeStamp
PollReponse
PollReponseID | PollID | UserID | Answer
In the PollAnswer table I get Five answers as VARCHAR A, B, C, D, E.
I have written a query to group the answers by A, B, C, D, E.
select q.Question
, q.PollID
, r.Answer
, count(r.Answer)
from pollQuestions q
, pollResponse r
where q.PollID = r.PollID
group
by r.Answer
, q.Question
, q.PollID
order
by r.PollID;
Which gives me a response as follows.
Question | PollID | Answer | count
alpha | 1 | A | 2
alpha | 1 | B | 3
alpha | 1 | C | 4
alpha | 1 | D | 0
alpha | 1 | E | 0
betas | 2 | A | 3
betas | 2 | B | 4
betas | 2 | C | 4
betas | 2 | D | 6
betas | 2 | E | 0
I want to flatten the answer like this.
Question | PollID | countA | countB | countC | countD | countE
alpha | 1 | 2 | 2 | 4 | 0 | 0
betas | 2 | 3 | 4 | 4 | 6 | 0
Is there anyway I can achieve this without changing the table structure?
Any pointer would be appreciated.

You can try to use condition aggregate function.
select
pollQuestions.Question,
pollQuestions.PollID,
count(CASE WHEN pollResponse.Answer ='A' THEN 1 END) countA,
count(CASE WHEN pollResponse.Answer ='B' THEN 1 END) countB,
count(CASE WHEN pollResponse.Answer ='C' THEN 1 END) countC,
count(CASE WHEN pollResponse.Answer ='D' THEN 1 END) countD,
count(CASE WHEN pollResponse.Answer ='E' THEN 1 END) countE
from pollQuestions
JOIN pollResponse on pollQuestions.PollID = pollResponse.PollID
group by
pollQuestions.Question,
pollQuestions.PollID
order by
pollResponse.PollID;
NOTE
I would use JOIN instead of comma , because JOIN syntax is clearer than , about connect two tabls.

You can use group by with sum(case when...) like below:
select pq.Question, pq.PollID,
sum(case when pr.Answer = 'A' then 1 else 0 end) as 'countA',
sum(case when pr.Answer = 'B' then 1 else 0 end) as 'countB',
sum(case when pr.Answer = 'C' then 1 else 0 end) as 'countC',
sum(case when pr.Answer = 'D' then 1 else 0 end) as 'countD',
sum(case when pr.Answer = 'E' then 1 else 0 end) as 'countE'
from PollQuestion pq
left join PollResponse pr on pq.PollID = pr.PollID
group by pq.Question, pq.PollID

Related

Mysql display query data and count

Just an amateur here needing a little help.
I have a table named tbl_inspection_areas.area_description
columns 'area_description' and 'display_tab'.
I want a query that returns 'area_description','display_tab' and the number of times each display tab occurs.
Like in the drawing below.
| tbl_inspection_areas.area_description | tbl_inspection_areas.display_tab | count |
_____________________________________________________________________________________________
| engine | 38 | 2 |
| transmission | 38 | |
| interior | 39 | 1 |
| wheels | 40 | 3 |
| glass | 40 | |
| lights | 40 | |
This is the best I have come up with, but it only displays 3 rows and the count is in 3 seperate columns.
Any help would be great.
SELECT
tbl_inspection_areas.area_description,
tbl_inspection_areas.display_tab,
SUM(CASE WHEN tbl_inspection_areas.display_tab = '38' THEN 1 ELSE 0 END) AS count1,
SUM(CASE WHEN tbl_inspection_areas.display_tab = '39' THEN 1 ELSE 0 END) AS count2,
SUM(CASE WHEN tbl_inspection_areas.display_tab = '40' THEN 1 ELSE 0 END) AS count3,
SUM(CASE WHEN tbl_inspection_areas.display_tab = '46' THEN 1 ELSE 0 END) AS count4
FROM tbl_inspection_areas
GROUP BY tbl_inspection_areas.display_tab
SELECT
tbl_inspection_areas.area_description,
tbl_inspection_areas.display_tab,
COUNT(tbl_inspection_areas.display_tab)
FROM tbl_inspection_areas
GROUP BY tbl_inspection_areas.area_description,
tbl_inspection_areas.display_tab,

Mysql - Create view with case and count

I'm trying to create a view with CASE and COUNT from this two tables
t_jobs
| job_id |
+--------+
| 1 |
| 2 |
| 3 |
| 4 |
t_emails
| email_id | job_id | email_log |
+----------+--------+-----------+
| 1 | 1 | OK |
| 2 | 1 | ERROR |
| 3 | 2 | ERROR |
| 4 | 3 | OK |
The result should be this
view_jobs
| job_id | email_check | email_total |
+--------+-------------+-------------+
| 1 | 1 | 2 |
| 2 | 1 | 1 |
| 3 | 0 | 1 |
| 4 | 0 | 0 |
I'm trying in this way but with no success
SELECT
j.job_id,
CASE WHEN MAX( e.email_log != 'OK' ) THEN 1 ELSE 0 END email_check
COUNT( e.email_log ) AS email_total
FROM t_jobs j
LEFT OUTER JOIN `t_emails` `e` ON `j`.`job_id` = `e`.`job_id`
GROUP BY
j.job_id;
Can you tell me how can I do?
Thanks
I guess you need a simple conditional aggregation -
SELECT j.job_id,
COUNT(CASE WHEN e.email_log <> 'OK' THEN 1 ELSE NULL END) email_check,
COUNT(e.email_log) AS email_total
FROM t_jobs j
LEFT OUTER JOIN `t_emails` `e` ON `j`.`job_id` = `e`.`job_id`
GROUP BY j.job_id;
You just forgot a comma(,) at end of second column.
I also modified your condition a little bit.
Here email_check 1 denotes that job_id has error
0 denotes it has no error.
SELECT
j.job_id,
CASE WHEN MIN( e.email_log ) = 'error' THEN 1 ELSE 0 END as email_check,
COUNT( e.email_log ) AS email_total
FROM t_jobs j
LEFT OUTER JOIN `t_emails` `e` ON `j`.`job_id` = `e`.`job_id`
GROUP BY
j.job_id;

One row result with multiple join in MySQL

I have 3 tables like the following.
Table "mansioni":
id_mansione | desc_mansione
1 | production
2 | office
3 | transport
Table "dipendente": store id, name and surname:
id_dip | nome_dip | cognome_dip
1 | piero | rossi
2 | marco | rossi
Table dipendenti_iddip: store the association between "dipendente" and table "mansioni"
iddip_mansione | num_mansione | id_mansione
1 | 1 | 1
1 | 2 | 2
2 | 1 | 2
2 | 2 | 3
Now I need a query that give me a result like this:
id_dip | nome_dip | cognome_dip | mansione1 | mansione2 | mansione3
1 | piero | rossi | production| office |
2 | marco | rossi | office | transport |
I arrived to the following query but with this I can only see the "id_mansione" and not the "desc mansione" field
select i.id_dip,
i.nome_dip,
i.cognome_dip,
max(case when t.num_mansione='1' then t.id_mansione end) Mansione1,
max(case when t.num_mansione='2' then t.id_mansione end) Mansione2,
max(case when t.num_mansione='3' then t.id_mansione end) Mansione3
from dipendente i
left join dipendenti_iddip t
on i.id_dip = t.iddip_mansione
group by i.id_dip, i.nome_dip, i.cognome_dip
How can I arrive to my result?
Thanks...
Add join on mansioni and replace t.id_mansione with m.desc_mansione
select i.id_dip,
i.nome_dip,
i.cognome_dip,
max(case when t.num_mansione = '1' then m.desc_mansione end) Mansione1,
max(case when t.num_mansione = '2' then m.desc_mansione end) Mansione2,
max(case when t.num_mansione = '3' then m.desc_mansione end) Mansione3
from dipendente i
join dipendenti_iddip t
on i.id_dip = t.iddip_mansione
join mansioni m on m.id_mansione = t.id_mansione
group by i.id_dip

Join two table and count, avoid zero if record is not available in second table

I have following tables products and tests.
select id,pname from products;
+----+---------+
| id | pname |
+----+---------+
| 1 | prd1 |
| 2 | prd2 |
| 3 | prd3 |
| 4 | prd4 |
+----+---------+
select pname,testrunid,testresult,time from tests;
+--------+-----------+------------+-------------+
| pname | testrunid | testresult | time |
+--------+-----------+------------+-------------+
| prd1 | 800 | PASS | 2017-10-02 |
| prd1 | 801 | FAIL | 2017-10-16 |
| prd1 | 802 | PASS | 2017-10-02 |
| prd1 | 803 | NULL | 2017-10-16 |
| prd1 | 804 | PASS | 2017-10-16 |
| prd1 | 805 | PASS | 2017-10-16 |
| prd1 | 806 | PASS | 2017-10-16 |
+--------+-----------+------------+-------------+
I like to count test results for products and if there is no result available,for a product just show a zero for it. something like following table:
+--------+------------+-----------+----------------+---------------+
| pname | total_pass | total_fail| pass_lastweek | fail_lastweek |
+--------+------------+-----------+----------------+---------------+
| prd1 | 5 | 1 | 3 | 1 |
| prd2 | 0 | 0 | 0 | 0 |
| prd3 | 0 | 0 | 0 | 0 |
| prd4 | 0 | 0 | 0 | 0 |
+--------+------------+-----------+----------------++--------------+
I have tried different queries like following, which is just working for one product and is incomplete:
SELECT pname, count(*) as pass_lastweek FROM tests where testresult = 'PASS' AND time
>= '2017-10-11' and pname in (select pname from products) group by pname;
+-------------+---------------+
| pname | pass_lastweek |
+-------------+---------------+
| prd1 | 3 |
+-------------+---------------+
it looks so basic but still I am unable to write it, any idea?
Use conditional aggregation. The COUNT function count NULL values as zeros automatically, therefore, there is no need to take care of that.
select p.pname,
count(case when testresult = 'PASS' then 1 end) as total_pass,
count(case when testresult = 'FAIL' then 1 end) as total_fail,
count(case when testresult = 'PASS' and time >= curdate() - INTERVAL 6 DAY then 1 end) as pass_lastweek ,
count(case when testresult = 'FAIL' and time >= curdate() - INTERVAL 6 DAY then 1 end) as fail_lastweek ,
from products p
left join tests t on t.pname = p.pname
group p.id, p.pname
Generally, you need to LEFT JOIN the first table with the second one before you group. The join will give you a row for each product (even if there are no test results to join it to; INNER JOIN would exclude products with no associated tests) + an additional row for each test result (beyond the first). Then you can group them.
SELECT products.*, tests.* FROM products
LEFT JOIN tests ON products.pname = tests.pname
GROUP BY products.id
Also, I would strongly recommend using a product_id column in the tests table, rather than using pname (if a products.pname changes, your whole DB breaks unless you also update the pname field in kind for every test result). The general query would then look like this:
SELECT products.*, tests.* FROM products
LEFT JOIN tests ON products.id = tests.product_id
GROUP BY products.id
I used 2 queries , the first with conditional count and the second one is to change all null values into 0 :
select pname,
case when total_pass is null then 0 else total_pass end as total_pass,
case when total_fail is null then 0 else total_fail end as total_fail,
case when pass_lastweek is null then 0 else pass_lastweek end as pass_lastweek,
case when fail_lastweek is null then 0 else fail_lastweek end asfail_lastweek from (
select products.pname,
count(case when testresult = 'PASS' then 1 end) as total_pass,
count(case when testresult = 'FAIL' then 1 end) as total_fail,
count(case when testresult = 'PASS' and time >= current_date -7 DAY then 1 end) as pass_lastweek ,
count(case when testresult = 'FAIL' and time >= current_date -7 DAY then 1 end) as fail_lastweek ,
from products
left join tests on tests.pname = products.pname
group 1 ) t1

mysql find values und typs with same timestamp and insert in new table

have a mysql database which looks like this:
|Timestamp | Typ | Value |
|01-01-2011 | temperature1 | 2|
|01-01-2011 | temperature2 | 3 |
|01-01-2011 | humidity1 | 98 |
I will transform this tabel to something lik this:
|Timestamp | temperature1 | temperature2 | humidity1 |
|01-01-2011 | 2 | 3 | 98 |
So i want for every typ a new column and all values with same timestamp in one row.
Try this:
SELECT A.Timestamp,
SUM(CASE WHEN A.Typ = 'temperature1' THEN A.Value ELSE 0 END) AS temperature1,
SUM(CASE WHEN A.Typ = 'temperature2' THEN A.Value ELSE 0 END) AS temperature2,
SUM(CASE WHEN A.Typ = 'humidity1' THEN A.Value ELSE 0 END) AS humidity1
FROM tableA A
GROUP BY A.Timestamp;