Joining four MySQL queries with same columns, different conditions - mysql

I have four queries that have 6 columns each. Each query is the same except for the WHERE clause is slightly different in each case. What I would like to see is each queries result for each column next to eachother for comparison.
Example result table headers: time(only one), calls1, calls2, calls3, calls4, work1, work2, work3, work4, tele1, tele2, tele3, tele4, comm1, comm2, comm3, comm4, techs1, techs2,techs3, techs4.
The actual queries are below. Please help me make a comparative query. T
SELECT CONCAT(hour(opened_dt),':',floor(minute(opened_dt)/15)*15) AS time, COUNT(*)/COUNT(DISTINCT DATE(opened_dt)) AS r_calls, ROUND(AVG(work_time),2)/60 AS r_work, ROUND(AVG(tele_time),2)/60 AS r_tele, ROUND(AVG(comm_time),2)/60 AS r_comm, IFNULL(COUNT(*)/COUNT(DISTINCT DATE(opened_dt)),0)/3 AS r_techs
FROM detail_head LEFT JOIN detail_detail ON detail_detail.detail_head_uid = detail_head.detail_head_uid
WHERE call_origins_uid != 5
AND DATE(opened_dt) >= (CURDATE() - INTERVAL 42 DAY)
AND dayname(opened_dt) = 'SUNDAY'
GROUP BY (hour(opened_dt)*100)+floor(minute(opened_dt)/15)
SELECT CONCAT(hour(opened_dt),':',floor(minute(opened_dt)/15)*15) AS time, COUNT(*)/COUNT(DISTINCT DATE(opened_dt)) AS calls, ROUND(AVG(work_time),2)/60 AS work, ROUND(AVG(tele_time),2)/60 AS tele, ROUND(AVG(comm_time),2)/60 AS comm, IFNULL(COUNT(*)/COUNT(DISTINCT DATE(opened_dt)),0)/3 AS techs
FROM detail_head LEFT JOIN detail_detail ON detail_detail.detail_head_uid = detail_head.detail_head_uid
WHERE call_origins_uid != 5
AND DATE(opened_dt) >= (CURDATE() - INTERVAL 42 DAY)
AND dayname(opened_dt) = 'SUNDAY'
AND call_origins_uid = 1
GROUP BY (hour(opened_dt)*100)+floor(minute(opened_dt)/15)
SELECT CONCAT(hour(opened_dt),':',floor(minute(opened_dt)/15)*15) AS time, COUNT(*)/COUNT(DISTINCT DATE(opened_dt)) AS calls, ROUND(AVG(work_time),2)/60 AS work, ROUND(AVG(tele_time),2)/60 AS tele, ROUND(AVG(comm_time),2)/60 AS comm, IFNULL(COUNT(*)/COUNT(DISTINCT DATE(opened_dt)),0)/3 AS techs
FROM detail_head LEFT JOIN detail_detail ON detail_detail.detail_head_uid = detail_head.detail_head_uid
WHERE call_origins_uid != 5
AND DATE(opened_dt) >= (CURDATE() - INTERVAL 42 DAY)
AND dayname(opened_dt) = 'SUNDAY'
AND call_origins_uid = 4
GROUP BY (hour(opened_dt)*100)+floor(minute(opened_dt)/15)
SELECT CONCAT(hour(opened_dt),':',floor(minute(opened_dt)/15)*15) AS time, COUNT(*)/COUNT(DISTINCT DATE(opened_dt)) AS calls, ROUND(AVG(work_time),2)/60 AS work, ROUND(AVG(tele_time),2)/60 AS tele, ROUND(AVG(comm_time),2)/60 AS comm, IFNULL(COUNT(*)/COUNT(DISTINCT DATE(opened_dt)),0)/3 AS techs
FROM detail_head LEFT JOIN detail_detail ON detail_detail.detail_head_uid = detail_head.detail_head_uid
WHERE DATE(opened_dt) >= (CURDATE() - INTERVAL 42 DAY)
AND dayname(opened_dt) = 'SUNDAY'
GROUP BY (hour(opened_dt)*100)+floor(minute(opened_dt)/15)

You could use 'CREATE TEMPORARY TABLE TableName1' for each table then write a query to put the columns in order then drop the tables when your done.

Related

How to select records but exclude if one type is outside a subquery?

We have multiple invStatus values (1-10) and want to exclude only one status type (1) BUT only those of that type that are a older than X number of days. So all records will show but NOT those who's invStatus = 1 and is older than X days. invStatus = 1 and younger than X days will be included in the recordset.
Do I select all records generically, then in a subquery filter those of status = 1 that are older than X days?
The query below uses NOT IN in an attempt to select those records to exclude but it is not working and also seems to be inefficient as it takes a couple seconds to execute.
SELECT
tblinventory.invId,
tblinventory.invTitle,
tblinventory.invStatus,
tblhouseinfo.Address,
tblhouseinfo.City,
tblhouseinfo.`State`,
tblhouseinfo.Zip,
tblhouseinfo.Update_date,
CURRENT_DATE() - INTERVAL 10 DAY AS dateEx
FROM
tblinventory
LEFT OUTER JOIN tblhouseinfo ON tblinventory.invId = tblhouseinfo.addInfoID
WHERE
invReleased = 0
AND invStatus NOT IN (SELECT invId from tblhouseinfo WHERE invStatus = 1
AND tblhouseinfo.Update_date < CURRENT_DATE() - INTERVAL 10 DAY )
ORDER BY
`tblhouseinfo`.`Update_date` DESC
I could filter the results with PHP on the page level but this also seems less than efficient and would prefer to perform this task using the best practices.
UPDATE:
There are a total of 155 rows.
All tblhouseinfo.Update_date (timestamp) values are "2017-09-06 10:53:17" (Aug 9th) accept three I changed for testing to "2017-07-06 10:53:17
" (July 6th)
Utilizing the suggestion for :
AND NOT (invStatus = 1 AND tblhouseinfo.Update_date > CURRENT_DATE() - INTERVAL 10 DAY )
60 records are excluded not the expected 3.
"2017-08-28" is the current result from CURRENT_DATE() - INTERVAL 10 DAY which should be within the 10 day range to select "2017-09-06 10:53:17" and only exclude the three records that are "2017-07-06 10:53:17"
FINAL WORKING SOLUTION/Query:
SELECT
tblinventory.invId,
tblinventory.invTitle,
tblinventory.invStatus,
tblhouseinfo.Address,
tblhouseinfo.City,
tblhouseinfo.`State`,
tblhouseinfo.Zip,
tblhouseinfo.Update_date,
CURRENT_DATE() - INTERVAL 10 DAY AS dateEx
FROM
tblinventory
LEFT OUTER JOIN tblhouseinfo ON tblinventory.invId = tblhouseinfo.addInfoID
WHERE
invReleased = 0
AND NOT (invStatus = 1 AND tblhouseinfo.Update_date < CURRENT_DATE() - INTERVAL 10 DAY )
ORDER BY
`tblhouseinfo`.`Update_date` DESC
SELECT
tblinventory.invId,
tblinventory.invTitle,
tblinventory.invStatus,
tblhouseinfo.Address,
tblhouseinfo.City,
tblhouseinfo.`State`,
tblhouseinfo.Zip,
tblhouseinfo.Update_date,
CURRENT_DATE() - INTERVAL 10 DAY AS dateEx
FROM
tblinventory
LEFT OUTER JOIN tblhouseinfo ON tblinventory.invId = tblhouseinfo.addInfoID
WHERE
invReleased = 0
AND NOT (invStatus = 1 AND tblhouseinfo.Update_date < CURRENT_DATE() - INTERVAL 10 DAY )
ORDER BY
`tblhouseinfo`.`Update_date` DESC
You don't need to select invID from the other table if you know you never want the ID #1 (invStatus 1). But you can also throw in an AND statement for the # of days.
I always use timestamps (in UNIX) for recording data entry / modification.
AND (timestamp >= beginTimestamp AND timeStamp <= endTimestamp)

get records of past two months excluding today's record list

I have two queries:
Following query return me the guards details who are working today:
One:
SELECT
`guards`.`surname`
, `contracted_guard`.`con_id`
, `guards`.`street`
, `shifts`.`advised_sign_in`
FROM
`guards`
LEFT JOIN `contracted_guard` ON `contracted_guard`.`guard_id` = `guards`.`gid`
LEFT JOIN `shifts` ON `shifts`.`guard_id` = `guards`.`gid`
WHERE advised_sign_in >=CURDATE()
AND advised_sign_in < CURDATE()+ INTERVAL 1 DAY
GROUP BY `guards`.`gid`
ORDER BY `guards`.`given_names` ASC
LIMIT 400
Now, the following second query returns me the guards details who are not working today but have signed in at least for once in past two months (This is because to get the list of active guards as system contains a huge guard list).
Query Two:
SELECT
`guards`.`surname`
, `contracted_guard`.`con_id`
, `guards`.`street`
, `shifts`.`advised_sign_in`
FROM
`guards`
LEFT JOIN `contracted_guard`
ON (`contracted_guard`.`guard_id` = `guards`.`gid`)
LEFT JOIN `shifts`
ON (`shifts`.`guard_id` = `guards`.`gid`)
WHERE (`shifts`. advised_sign_in !=CURDATE() AND advised_sign_in >= DATE_SUB(CURDATE(), INTERVAL 2 MONTH))
GROUP BY `guards`.`gid`
ORDER BY `guards`.`given_names` ASC;
The both queries work fine. But the problem is second query return the result of those guards also who are working today as well but with old date (THis is because they also have signed in in past two months). Although i want the list of guards excluding those guards who are working today but have worked in past two months.
Any hints will be highly appreciated .
You want to move the condition on the current date from the where to the having clause:
SELECT `guards`.`surname`, `contracted_guard`.`con_id`, `guards`.`street`, `shifts`.`advised_sign_in`
FROM `guards`
LEFT JOIN `contracted_guard`
ON (`contracted_guard`.`guard_id` = `guards`.`gid`)
LEFT JOIN `shifts`
ON (`shifts`.`guard_id` = `guards`.`gid`)
WHERE advised_sign_in >= DATE_SUB(CURDATE(), INTERVAL 2 MONTH))
GROUP BY `guards`.`gid`
HAVING sum(`shifts`. advised_sign_in = CURDATE() ) = 0
ORDER BY `guards`.`given_names` ASC;

Filling empty MySQL Result

I want to have a continuos date set with the sales.
SELECT *,
UNIX_TIMESTAMP(calendar.datefield) * 1000 AS time,
IFNULL(Sum(mos + mosnk), 0) AS mosfinal,
IFNULL(Sum(neukunden), 0) AS neukunden
FROM sms_stats
RIGHT JOIN calendar
ON ( DATE(sms_stats.date) = calendar.datefield )
WHERE calendar.datefield BETWEEN Curdate() - INTERVAL 90 day AND Now()
GROUP BY Date_format(calendar.datefield, '%Y%m%d')
this returns me a list of the last 90 days. Now I want to filter it, but if I do
WHERE owner = 2 AND calendar.datefield BETWEEN Curdate() - INTERVAL 90 day AND Now()
it just returns one result and not the list of dates.
The condition in the where clause "undoes" the right outer join. The solution is to move the condition to the where clause. I have a preference for left outer join over right outer join, so I'll swap the tables:
SELECT *,
UNIX_TIMESTAMP(c.datefield) * 1000 AS time,
IFNULL(Sum(mos + mosnk), 0) AS mosfinal,
IFNULL(Sum(neukunden), 0) AS neukunden
FROM calendar c LEFT JOIN
sms_stats ss
ON DATE(ss.date) = c.datefield and
ss.owner = 2
WHERE c.datefield BETWEEN Curdate() - INTERVAL 90 day AND Now()
GROUP BY Date_format(c.datefield, '%Y%m%d') ;
I added in table aliases to make the query a bit more readable.

Sum over defined period of time in months

Got a good one here...
I currently have the following bit of code that basically sums the total of active accounts by month.
That is simple, however what I'm wanting to do the same thing on a per category basis and over a defined period and not just one month Ie. over 12 months.... Any ideas / assistance please....My brain is flat :(
SELECT
DATE_FORMAT(s.`DateCreated`,'%Y-%M') AS `Date Created`
, DATE_FORMAT(s.`DateEnd`,'%Y-%M') AS `Date End`
,(#csum := #csum + COUNT(DISTINCT(acc.`AccountId`))) AS Active
FROM (SELECT #csum := 0) AS csums, xx_accountdetails acc
INNER JOIN xx_services s USING(accountid)
LEFT JOIN xx_category cat ON(CategoryId)
INNER JOIN xx_products prod USING(productid)
LEFT JOIN xx_subcategory sc ON(prod.Subcategoryid = sc.SubCategoryId)
LEFT JOIN xx_invoiceline il USING(serviceid)
LEFT JOIN xx_invoices i USING(invoiceid)
WHERE DATE_FORMAT(s.DateStart,'%Y-%m') <= DATE_SUB(NOW(), INTERVAL 1 MONTH)
AND
s.`ProductId` NOT IN (4001,4002)
AND cat.`CategoryId` = '1'
AND
(DATE_FORMAT(s.`DateEnd`,'%Y-%m') >= DATE_SUB(NOW(), INTERVAL 1 MONTH)
OR
(s.`DateEnd` IS NULL
AND s.`IsActive` = 1
AND (s.`SuspendReasonId` != 3 OR s.`SuspendReasonId` IS NULL)))
GROUP BY DATE_FORMAT(s.DateCreated,'%Y-%m')
For the date range, simply change the date intervals, e.g.:
date_sub(now(), interval 12 months)
For the per categories, you need to add an extra group by statement:
group by cat.CategoryId, ...
Remove the where clause on it, too, else you'll only have CategoryId = 1.

Trying to correct a mysql query

I currently have the following query;
SELECT a.schedID,
a.start AS eventDate, b.div_id AS divisionID, b.div_name AS divisionName
FROM schedules a
INNER JOIN divisions b ON b.div_id = a.div_id
WHERE date_format(a.start, '%Y-%m-%d') >= '2010-01-01'
AND DATE_ADD(a.start, INTERVAL 5 DAY) <= CURDATE()
AND NOT EXISTS (SELECT results_id FROM results e WHERE e.schedID = a.schedID)
ORDER BY eventDate ASC;
Im trying to basically find any schedules that do not have any results 5 days after the schedule date. My current query has major performance issues. It also times out inconsistently. Is there a different way to write the query? Im at a mental roadblock. Any help is appreciated.
Without antcipating much on the outcome I would suggest the following leads :
* try to remove the date_format as this generates one function call per record. I don't know the format of your column a.start but this should be possible.
* same for DATE_ADD, you could probably put it on the other member like :
a.start <= DATE_SUB(CURDATE(), INTERVAL 5 DAYS)
you get a chance the result is cached rather than being calculated for each line, you could even define it as a parameter upfront
* the NOT EXISTS is very expensive, it seems to mee you could replace this by a left join like :
schedules a LEFT JOIN results e ON a.schedId = e.schedId WHERE e.schedId is NULL
double-check that all join fields are well indexed.
Good luck
Maybe something like:
SELECT
a.schedID, a.start AS eventDate, b.div_id AS divisionID, b.div_name AS divisionName
FROM
schedules a
INNER JOIN divisions b ON b.div_id = a.div_id
WHERE
date_format(a.start, '%Y-%m-%d') >= '2010-01-01'
AND NOT EXISTS (
SELECT
*
FROM
results e
INNER JOIN schedules a2 ON e.schedID = a2.schedID
WHERE
DATE_ADD(a2.start, INTERVAL 5 DAY) <= CURDATE()
AND a2.id = a.id
)
ORDER BY eventDate ASC;
dont know if mysql is same as oracle but are you converting a date to a string here and then comparing it with a string '2010-01-01' ? Can you convvert 2010-01-01 to a date instead so that if there is an index on a.start, it can be used ?
Also does this query definitely return the right answer ?
You mention you want schedules without results 5 days after the schedule date but it looks like you are aksing for anything in the last 5 days ?
a.start >= 1-Jan-10 and start date + 5 days is before today
try this query
SELECT a.schedID,
a.start AS eventDate,
b.div_id AS divisionID,
b.div_name AS divisionName
FROM (SELECT * FROM schedules s WHERE DATE(s.start) >= '2010-01-01' AND DATE_ADD(s.start, INTERVAL 5 DAY) <= CURDATE()) a
INNER JOIN divisions b
ON b.div_id = a.div_id
LEFT JOIN (SELECT results_id FROM results) e
ON e.schedID = a.schedID
WHERE e.results_id = ''
ORDER BY eventDate ASC;