I have two tables as follows:
Enclosure
+-------+--------------+-----------+-----------+
| name | serialnumber | VCenabled | BCenabled |
+-------+--------------+-----------+-----------+
| ENC01 | 12345 | | |
| ENC02 | 45678 | | |
| ENC03 | 11222 | | |
+-------+--------------+-----------+-----------+
Interconnect
+-------------+-----------+-----------------------+
| description | baynumber | enclosureserialnumber |
+-------------+-----------+-----------------------+
| VC | 1 | 12345 |
| VC | 2 | 12345 |
| BC | 3 | 12345 |
| VC | 1 | 45678 |
| BC | 3 | 45678 |
+-------------+-----------+-----------------------+
I need to update the VCenabled and BCenabled columns in the Enclosure table. VCenabled should contain a count of the corresponding rows in the Interconnect table. Likewise for BCenabled.
Here is what I need to end up with:
+-------+--------------+-----------+-----------+
| name | serialnumber | VCenabled | BCenabled |
+-------+--------------+-----------+-----------+
| ENC01 | 12345 | 2 | 1 |
| ENC02 | 45678 | 1 | 1 |
| ENC03 | 11222 | | |
+-------+--------------+-----------+-----------+
I was able to come up with this SQL query, but I'm not having much luck turning this into an update. Also, this query works if I run it in Flyspeed Query but if I run it in MySQL Workbench, I get a 1064 error: Error in SQL syntax.
Select
enclosure.name,
enclosure.vcenabled,
count(*)
From
enclosure Inner Join
interconnect On interconnect.enclosureserialnumber = enclosure.serialnumber
Where
interconnect.description like '%VC%'
Group By
enclosure.serialnumber
Any help would be appreciated.
try this :
update enclosure t1,
(select count(*) as x,enclosureserialnumber from interconnect where description='VC') t2,
(select count(*) as y,enclosureserialnumber from interconnect where description='BC') t3
set t1.VCenabled = t2.x,t1.BCenabled=t3.x
where t1.serialnumber=t2.enclosureserialnumber
and t2.serialnumber=t3.enclosureserialnumber
Sample
UPDATE
Enclosure e
INNER JOIN (
SELECT
enclosureserialnumber,
SUM(CASE WHEN description = 'VC' THEN 1 ELSE 0 END) AS VC,
SUM(CASE WHEN description = 'BC' THEN 1 ELSE 0 END) AS BC
FROM
Interconnect
GROUP BY
enclosureserialnumber
) q1
ON e.serialnumber = q1.enclosureserialnumber
SET
VCenabled = q1.VC,
BCenabled = q1.BC;
This should work using a subquery with the update:
update Enclosure e
join (
select enclosureserialnumber,
sum(case when i.description = 'VC' then 1 else 0 end) vcsum,
sum(case when i.description = 'BC' then 1 else 0 end) bcsum
from Interconnect i
group by i.enclosureserialnumber
) i
on e.serialnumber = i.enclosureserialnumber
set e.VCenabled = i.vcsum,
e.BCenabled = i.bcsum;
SQL Fiddle Demo
update Enclosure as E1 set E1.VCenabled = (select count(*) from Interconnect as I where I.enclosureserialnumber = E1.serialnumber and I.description = 'VC');
similar for BC
Tested... if any error occurs, please check for any spelling typos.
for output to my system....
http://pastebin.com/B0bUDYX6
Related
I have a table veicoli (vehicles) like this:
-------------------------------
| ID | Modello | Targa |
-------------------------------
| 1 | IVECO | XA123WE |
-------------------------------
| 2 | IVECO | CF556XD |
-------------------------------
| 3 | FIAT | AS332ZZ |
-------------------------------
| 4 | GOLF | GF567YU |
-------------------------------
For each vehicle I have none, one or multiple revisioni_veicolo (revisions) (the one with bigger DateExpiring is the one I need to check if revision is still valid or not based on today date)
-------------------------------------------------------------------
| ID | veicoli_ID | DateExpiring | Pass_Success |
-------------------------------------------------------------------
| 1 | 1 | 2019-07-01 | 1
------------------------------------------------------------------
| 2 | 1 | 2020-10-01 | 0
-------------------------------------------------------------------
| 3 | 2 | 2019-11-25 | 1
-------------------------------------------------------------------
| 4 | 2 | 2018-10-20 | 1
-------------------------------------------------------------------
| 5 | 4 | 2017-10-20 | 1
-------------------------------------------------------------------
Based on my example above (today is 2019-10-29):
Vehicle: ID = 1 has a revision still active (2020-10-01) but not passed (Pass_success = 0)
Vehicle: ID = 2 has a revision still active (2019-11-25) and passed (Pass_success = 1)
Vehicle: ID = 3 has no revision yet
Vehicle: ID = 4 has revision, but no active revision (last expired on 2017-10-20) but the last one passed the check (Pass_success = 1)
What I need is to have 3 new custom columns created dynamically on my query result:
-------------------------------------------------------------------------------------------
| ID | Modello | Targa | RevisionPresent | RevisionStillActive | LastRevisionPassed |
-------------------------------------------------------------------------------------------
| 1 | IVECO | XA123WE | true | true | false
-------------------------------------------------------------------------------------------
| 2 | IVECO | CF556XD | true | true | true
-------------------------------------------------------------------------------------------
| 3 | FIAT | AS332ZZ | false | false | false
-------------------------------------------------------------------------------------------
| 4 | GOLF | GF567YU | true | false | true
-------------------------------------------------------------------------------------------
I tried to start with my old post: MYSQL INNER JOIN to get 3 types of result
But I'm very confused using nested JOIN
I tried starting a fiddle but i'm stuck on syntax error: http://sqlfiddle.com/#!9/3c70bf/2
You need a LEFT JOIN of the tables and conditional aggregation:
select v.ID, v.Modello, v.Targa,
max(r.DataScadenzaRevisione is not null) RevisionPresent,
coalesce(max(r.DataScadenzaRevisione >= current_date()), 0) RevisionStillActive,
max(case when r.DataScadenzaRevisione = g.maxdate then r.EsitoPositivo else 0 end) LastRevisionPassed
from veicoli v
left join revisioni_veicolo r on r.veicoli_ID = v.id
left join (
select veicoli_id, max(DataScadenzaRevisione) maxdate
from revisioni_veicolo
group by veicoli_id
) g on g.veicoli_ID = v.id
group by v.ID, v.Modello, v.Targa
See the demo.
Results:
| ID | Modello | Targa | RevisionPresent | RevisionStillActive | LastRevisionPassed |
| --- | ------- | ------- | --------------- | ------------------- | ------------------ |
| 1 | IVECO | XA123WE | 1 | 1 | 0 |
| 2 | IVECO | CF556XD | 1 | 1 | 1 |
| 3 | FIAT | AS332ZZ | 0 | 0 | 0 |
| 4 | GOLF | GF567YU | 1 | 0 | 1 |
...
LEFT JOIN (SELECT a.veicoli_ID, a.EsitoPositivo AS StatoUltimaRevisione,
a.DataScadenzaRevisione FROM revisioni_veicolo) a
...
There's two things wrong with this.
The alias a is defined for this subquery, so you can't reference it inside the subquery. But you don't need to qualify the columns in this subquery anyway - you didn't do this in other subqueries, so I'm not sure why you did it in this case.
You don't have any join condition for this join. MySQL is a little bit inconsistent about when join conditions are required. But in this case, you need one.
After I tested the query with these two corrections, it works.
Basically you just need to look at the last revision of each vehicule to produce that resultset.
You can do the filtering with a correlated subquery:
select
v.ID,
v.Modello,
v.Targa,
(DataScadenzaRevisione >= now()) RevisionPresent,
(DataScadenzaRevisione >= now() and EsitoPositivo = 1) RevisionStillActive,
(EsitoPositivo = 1) LastRevisionPassed
from
veicoli v
left join revisioni_veicolo r
on r.veicoli_ID = v.ID
and r.DataScadenzaRevisione = (
select max(DataScadenzaRevisione)
from revisioni_veicolo r1
where r1.veicoli_ID = v.ID
)
You can check the results with your sample data in this db fiddle.
Or you can use a window function (this requires MySQL 8.0):
select
v.ID,
v.Modello,
v.Targa,
(DataScadenzaRevisione >= now()) RevisionPresent,
(DataScadenzaRevisione >= now() and EsitoPositivo = 1) RevisionStillActive,
(EsitoPositivo = 1) LastRevisionPassed
from (
select
v.*,
r.*,
row_number() over(partition by ID order by r.DataScadenzaRevisione desc) rn
from veicoli v
left join revisioni_veicolo r on r.veicoli_ID = v.ID
) where coaelesce(rn, 1) = 1
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;
Currently, I'm using this nice query:
select
users.name,
sum(race_results.winnings) as total_winnings,
count(CASE WHEN race_results.place=1 THEN 1 ELSE 0 END) AS times_won_first_place
from users
inner join race_results
where race_results.userid = users.id and race_results.place = 1
group by users.id
order by total_winnings desc
to get this
************************************************
| name | total_winnings | times_won_first_place |
| Bob | 4000 | 4 |
| John | 1000 | 1 |
************************************************
the race_results table looks like this
*******************************************
| id | raceid | userid | place | winnings |
| 1 | 1 | 1 | 1 | 1000 |
| 2 | 1 | 2 | 5 | 50 |
| 3 | 1 | 3 | 6 | 50 |
| 4 | 2 | 1 | 1 | 1000 |
| 5 | 2 | 2 | 3 | 250 |
*******************************************
I would like to include four three more columns for something like this
***************************************************************************
| name | total_winnings | total_races | 1st_place | 2nd_place | 3rd_place |
| Bob | 4000 | 5 | 4 | 0 | 0 |
| John | 1000 | 5 | 1 | 1 | 1 |
***************************************************************************
If I were to do separate queries for the new columns, I'd use
select count(raceid) from race_results where userid = 1
select count(raceid) from race_results where userid = 1 and place = 1
select count(raceid) from race_results where userid = 1 and place = 2
select count(raceid) from race_results where userid = 1 and place = 3
to do separate queries would be easy but with the existing query I had to use CASE just to get the count of times a user won 1st place. (using
count(CASE WHEN race_results.place=2 THEN 1 ELSE 0 END)
returns the same results).
How would I nest these or join them into my existing query to get what I want?
You can do it this way:
select
users.name,
sum(race_results.winnings) as total_winnings,
count(*) AS total_races,
sum(race_results.place = 1) AS times_won_first_place ,
sum(race_results.place = 2) AS times_won_second_place,
sum(race_results.place = 3) AS times_won_third_place
from users
inner join race_results
where race_results.userid = users.id
group by users.id
order by total_winnings desc;
With ANSI standard SQL you could use case expressions inside the sum function but since MySQL (and some other databases) evaluate boolean expressions to 1 for true you can replace the case expression with the just the condition to evaluate and then just sum them.
So instead of CASE WHEN race_results.place=1 THEN 1 ELSE 0 END you can do sum(race_results.place=1) and save some space and typing :)
See this SQL Fiddle for an example.
I have a table having following structure:
| pid | email | email_type |
| 1 | x | 1 |
| 1 | y | 2 |
| 1 | z | 3 |
| 2 | ab | 1 |
| 3 | cd | 2 |
Now I want my result for the pid parameter in format for email_type[1 & 2] only:
Case pid=1
| pid | email_p | email_w |
| 1 | x | y |
Case pid=2
| 2 | ab | NULL |
Case pid=3
| 3 | NULL | cd |
Here email_p represents email_type=1 & email_w represents email_type=2
I am using following query, and its working fine except for a case pid=2. Case I & Case III are successfully fetched. Please provide some solution with good explanation(if possible).
SELECT `e`.`pid`, `e`.`email` AS `email_p`, `e1`.`email` AS `email_w` FROM `table1` AS `e` LEFT JOIN `table1` AS `e1` ON e.pid=e1.pid AND e1.email_type=2 WHERE (e.pid IN (1) AND e.email_type=1)
It fails when e.pid = 2 and it returns empty result set & please provide solution e.pid IN (1,2,3) holds good for required format.#MYSQL
Try This
SELECT pid,
MAX(CASE WHEN email_type=1 THEN email END ) as email_p ,
MAX(CASE WHEN email_type=2 THEN email END ) as email_w
FROM tableName
WHERE email_type IN (1,2)
GROUP BY pid
SQL Fiddle DEMO
I have 2 tables on 2 different databases :
db1.table1
+--------------+--------------------------+
| Username | Message |
+--------------+--------------------------+
| jamesbond | I need some help |
| jamesbond | I need some help |
| jamesbond | I need some help |
| jamesbond | Mission accomplished |
+--------------+--------------------------+
db2.table2
+--------------------------+--------------+
| Message | Status |
+--------------------------+--------------+
| I need some help | Ok |
| I need some help | Ok |
| I need some help | Bad |
+--------------------------+--------------+
when I do 'INNER JOIN' those tables using this SQL syntax :
SELECT A.Username, A.Message
SUM(CASE WHEN `status` = 'Ok' THEN 1 ELSE 0 END) AS StatOK,
SUM(CASE WHEN `status` = 'Bad' THEN 1 ELSE 0 END) AS StatBAD
FROM db1.table1 as A
INNER JOIN db2.table2 as B
ON A.Message = B.Message
WHERE A.Username = 'jamesbond'
GROUP BY A.Username, A.Message
I got this result :
+--------------+--------------------------+--------+---------+
| Username | Message | StatOK | StatBAD |
+--------------+--------------------------+--------+---------+
| jamesbond | I need some help | 2 | 1 |
+--------------+--------------------------+--------+---------+
how to get result like this (message without status on DB2 still appear, but the SUM result can be ZERO or NULL) :
+--------------+--------------------------+--------+---------+
| Username | Message | StatOK | StatBAD |
+--------------+--------------------------+--------+---------+
| jamesbond | I need some help | 2 | 1 |
| jamesbond | Mission accomplished | NULL | NULL |
+--------------+--------------------------+--------+---------+
You need a Left Outer Join, It will get the rows from Left tables and if it doesn't match with Right table then You'll get NULL.
SELECT A.Username, A.Message
SUM(CASE WHEN `status` = 'Ok' THEN 1 ELSE 0 END) AS StatOK,
SUM(CASE WHEN `status` = 'Bad' THEN 1 ELSE 0 END) AS StatBAD
FROM db1.table1 as A
LEFT OUTER JOIN db2.table2 as B
ON A.Message = B.Message
WHERE A.Username = 'jamesbond'
GROUP BY A.Username, A.Message