MySQL inner join three tables to use in calendar - php

Following up my question where I used the answer to generate data on my calendar called maintenance calendar showing the aircraft's maintenance schedule. This is the MySQL query for it:
SELECT DISTINCT s.reg AS 'reg',
a.date AS 'date'
FROM (SELECT Curdate()
+ INTERVAL (a.a + (10 * b.a) + (100 * c.a)) day AS Date
FROM (SELECT 0 AS a
UNION ALL SELECT 1
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
UNION ALL SELECT 6
UNION ALL SELECT 7
UNION ALL SELECT 8
UNION ALL SELECT 9) AS a
CROSS JOIN (SELECT 0 AS a
UNION ALL SELECT 1
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
UNION ALL SELECT 6
UNION ALL SELECT 7
UNION ALL SELECT 8
UNION ALL SELECT 9) AS b
CROSS JOIN (SELECT 0 AS a
UNION ALL SELECT 1
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
UNION ALL SELECT 6
UNION ALL SELECT 7
UNION ALL SELECT 8
UNION ALL SELECT 9) AS c) a
INNER JOIN maintenance_sched s
ON a.date >= s.date_from
AND a.date <= s.date_to
WHERE Month(date) = '".$month."'
AND Dayofmonth(date) = '".$dayArray["mday"]."'
AND Year(date) = '".$year."'
Here is the maintenance_sched database:
And the calendar looks like this (based on the data from maintenance_sched):
Then, I have another calendar called reservation calendar with the same code as the maintenance calendar though with different query. This is the reservation calendar query: SELECT acode FROM reservation WHERE month(etd) = '".$month."' AND dayofmonth(etd) = '".$dayArray["mday"]."' AND year(etd) = '".$year."' ORDER BY etd".
The reservation table is this:
And the reservation calendar looks like this:
EDIT:
What I want to do is: have these two calendar in one calendar with the result of maintenance_sched query outputted as string with strikethrough. But I can't seem to make the two queries work out together as one.

I do think the answer to this question is to simply join the two queries. An example of this might be like below where you just null out any columns that aren't in your second table.
SELECT id, date, field3, description
FROM table1
UNION
SELECT id, date, field3, null
FROM table2

As there is no relationship among both the table we cannot go for joins, it would be better to go for UNION to combine the result.
This query uses group_concat so will generate common results in following form
2013-03-15 | RP-C1728, RP-C1086
2013-03-08 | RP-C1728, RP-C1086, RP-C143
If you dont want record in this format then just remove group_concat, group by clause from the query.
Query
SELECT a.date, group_concat(a.reg)
FROM
(SELECT DISTINCT s.reg AS 'reg',
a.date AS 'date'
FROM (SELECT Curdate()
+ INTERVAL (a.a + (10 * b.a) + (100 * c.a)) day AS Date
FROM (SELECT 0 AS a
UNION ALL SELECT 1
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
UNION ALL SELECT 6
UNION ALL SELECT 7
UNION ALL SELECT 8
UNION ALL SELECT 9) AS a
CROSS JOIN (SELECT 0 AS a
UNION ALL SELECT 1
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
UNION ALL SELECT 6
UNION ALL SELECT 7
UNION ALL SELECT 8
UNION ALL SELECT 9) AS b
CROSS JOIN (SELECT 0 AS a
UNION ALL SELECT 1
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
UNION ALL SELECT 6
UNION ALL SELECT 7
UNION ALL SELECT 8
UNION ALL SELECT 9) AS c) a
INNER JOIN maintenance_sched s
ON a.date >= s.date_from
AND a.date <= s.date_to
WHERE Month(date) = '".$month."'
AND Dayofmonth(date) = '".$dayArray["mday"]."'
AND Year(date) = '".$year."'
UNION ALL
SELECT acode as 'reg', date as 'date' //Add the date logic here as per your need
FROM reservation
WHERE month(etd) = '".$month."' AND
dayofmonth(etd) = '".$dayArray["mday"]."' AND
year(etd) = '".$year."' ORDER BY etd) a
GROUP BY a.date;
NOTE For the second query add the according date logic

Related

How to separate the row value one by one with count function option in mysql

Mysql Table:
In My facility table is this
facility_name mbid date
yoga,aerobics,table tennis,tai chi, OM1111 2016-06-12
aerobics,tai chi, OM1111 2016-06-12
How to split row value one by one with mbid in mysql:
Facility_name mbid Number of count
yoga OM1111 1
aerobics OM1111 2
table tennis OM1111 1
tai chi OM1111 2
CREATE TABLE facility
(facility_name varchar(35), mbid varchar(6), date varchar(10))
;
INSERT INTO facility
(facility_name, mbid, date)
VALUES
('yoga,aerobics,table tennis,tai chi,', 'OM1111', '2016-06-12'),
('aerobics,tai chi,', 'OM1111', '2016-06-12')
;
Script :
Select T.VALUE,T.mbid,COUNT(T.VALUE)Cnt FROM (
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(t.facility_name, ',', n.n), ',', -1) value,mbid
FROM facility t CROSS JOIN
(
SELECT a.N + b.N * 10 + 1 n
FROM
(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) a
,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) b
ORDER BY n
) n
WHERE n.n <= 1 + (LENGTH(t.facility_name) - LENGTH(REPLACE(t.facility_name, ',', ''))))T
WHERE T.VALUE <> ''
GROUP BY T.VALUE,T.mbid
ORDER BY T.value
How to pass the date function in where condition to get count of activity :
Select facility.mbid,membership.name,membership.organization,
membership.designation,membership.division, facility.VALUE `Facility Name`,
COUNT(facility.VALUE)`Number of Activite` FROM ( SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(facility.facility_name, ',', n.n), ',', -1) value,mbid FROM facility CROSS JOIN
(
SELECT a.N + b.N * 10 + 1 n
FROM
(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) a
,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) b
ORDER BY n
) n
WHERE n.n <= 1 + (LENGTH(facility.facility_name) -LENGTH(REPLACE(facility.facility_name, ',', ''))))T
facility Inner Join membership ON facility.mbid=membership.mbid
where facility.date Between '2016-06-04' and '2016-06-07' &&
facility.VALUE <> ''
GROUP BY facility.VALUE,facility.mbid ORDER BY facility.value
You have a very poor database structure. You should have one row per mbid and facility_name. In fact, I have no idea why mbid and date are the same in the two rows.
If I assume that you have facility names in another table, then you can use:
select fn.facility_name, f.mbid, count(*)
from facility f join
facility_names fn
on find_in_set(fn.facility_name, f.facility) > 0
group by fn.facility_name, f.mbid;
I should emphasize, though, that although you can do a query like this, you really need to fix your data structure. Storing lists of values in a string is the wrong way to store data in a SQL database.

0 When no row exist

I have following sql query
SELECT DATE_FORMAT(date,'%d.%m. %y') as date, COUNT(idStat) as number
FROM stat
WHERE IdGame = ? AND date >= ? AND date <= ?
GROUP BY date
It returns date and how much people visited game this day, but how to return 0, when no rows exist this day?
For example day 15.12.1993 does not exist in db, but user pick date between 15.10.1950 and 12.15.2020.
I want to return this non existing date 15.12.1993 but with count 0.
Is this even possible?
Thanks for help,
Filip.
The best way is to have a Calendar table handy with relevant dates. You can then use a left join to get the dates. Something like this:
SELECT DATE_FORMAT(c.date,'%d.%m. %y') as date, COUNT(s.idStat) as number
FROM Calendar c LEFT JOIN
stat s
ON c.date = s.date AND s.IdGame = ?
WHERE c.date >= ? AND c.date <= ?
GROUP BY c.date;
If you have games on every date but the problem is that the particular game is not one the day, you can use this short-cut:
SELECT DATE_FORMAT(date,'%d.%m. %y') as date, SUM(IdGame = ?) as number
FROM stat
WHERE date >= ? AND date <= ?
GROUP BY date;
This doesn't work in all cases, but it can be a useful short-cut.
I used RedFilter Answer to solve my problem, from this link: generate days from date range
My query now looks like this:
select DATE_FORMAT(a.Date,'%d.%m. %Y'), COUNT(stat.IdStat)
from (
select curdate() - INTERVAL (a.a + (10 * b.a) + (100 * c.a)) DAY as Date
from (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as a
cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as b
cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as c
) as a LEFT JOIN stat ON a.Date = stat.date
where a.Date between ? and ? AND (stat.IdGame = ? OR stat.IdGame IS NULL) GROUP BY a.Date
But I need remove future dates form my datapicker, because when i use futue date in this sql, no data will be return... I need set min and max of my datapicker.

Get 0 if record doesn't exists of same day

What I'm trying to do is getting data for analytics which is working fine except one thing only, I am getting total records of date, previous total records of same days and total record of particular day, which is working absolutely fine.
But the only issue is I want data of those days also which have no rows
For example :
I have data for 1 sept, 2 sept, 3 sept and 6 sept but I want result for 4 & 5 sept also with 0 total.
SELECT (SELECT COUNT(ActivityID) FROM Activity WHERE DATE(CreatedDate) BETWEEN '2015-08-31' AND '2015-09-07'
) as total_post, (SELECT COUNT(ActivityID) FROM Activity WHERE DATE(CreatedDate) BETWEEN '2015-08-23'
AND '2015-08-30') as previous_total_post, DATE_FORMAT(DATE(CreatedDate), '%d %b, %y') as date, COUNT
(ActivityID) as total
FROM (`Activity`)
WHERE DATE(CreatedDate) BETWEEN '2015-08-31' AND '2015-09-07'
GROUP BY `date`
ORDER BY `CreatedDate` ASC
You can try it-
SELECT DATE_FORMAT(a.date_field, '%d %b, %y') AS 'DATE',
COUNT(IF(b.CreatedDate>='2015-08-31 00:00:00' AND b.CreatedDate<='2015-09-07 23:59:59',b.ActivityID,NULL)) AS total_post,
COUNT(IF(b.CreatedDate>='2015-08-23 00:00:00' AND b.CreatedDate<='2015-08-30 23:59:59',b.ActivityID,NULL)) AS previous_total_post,
COUNT(b.ActivityID) total
from
(
SELECT date_format(date_field, '%Y-%m-%d') as date_field FROM
(
SELECT
MAKEDATE(YEAR(NOW()),1) +
INTERVAL (MONTH(NOW())-2) MONTH +
INTERVAL daynum DAY date_field
FROM
(
SELECT t*10+u daynum
FROM
(SELECT 0 t UNION SELECT 1 UNION SELECT 2 UNION SELECT 3) A,
(SELECT 0 u UNION SELECT 1 UNION SELECT 2 UNION SELECT 3
UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7
UNION SELECT 8 UNION SELECT 9) B
ORDER BY daynum
) AA
) AAA
WHERE date_field >= '2015-08-23' and date_field < '2015-09-08') a
LEFT JOIN `Activity` AS b ON a.date_field=DATE(b.CreatedDate)
GROUP BY a.date_field
ORDER BY a.date_field ASC
Please updated query for multiple years-
SELECT DATE_FORMAT(a.date_field, '%d %b, %y') AS 'DATE',
COUNT(IF(b.CreatedDate>='2015-08-31 00:00:00' AND b.CreatedDate<='2015-09-07 23:59:59',b.ActivityID,NULL)) AS total_post,
COUNT(IF(b.CreatedDate>='2015-08-23 00:00:00' AND b.CreatedDate<='2015-08-30 23:59:59',b.ActivityID,NULL)) AS previous_total_post,
COUNT(b.ActivityID) total
from
(
SELECT date_format(date_field, '%Y-%m-%d') as date_field FROM
(
SELECT
MAKEDATE(YEAR(SUBDATE(NOW(),INTERVAL 5 YEAR)),1) +
INTERVAL (MONTH(NOW())-9) MONTH +
INTERVAL daynum DAY date_field
FROM (
SELECT m*1000+h*100+t*10+u daynum
FROM
(SELECT 0 m UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) D,
(SELECT 0 h UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) C,
(SELECT 0 t UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) A,
(SELECT 0 u UNION SELECT 1 UNION SELECT 2 UNION SELECT 3
UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7
UNION SELECT 8 UNION SELECT 9) B
ORDER BY daynum
) AA
) AAA
WHERE date_field >= '2010-01-01' and date_field < '2015-09-08') a
LEFT JOIN `Activity` AS b ON a.date_field=DATE(b.CreatedDate)
GROUP BY a.date_field
ORDER BY a.date_field ASC

PHP Calendar use union or multiple query

I have two separate calendars: reservation_schedule and maintenance_schedule calendars. Reservation_schedule fetch data from reservation table and maintenance_schedule fetch data from maintenance table. My goal is to put both fetched data from the two calendars into one calendar.
Here is the query I used for the reservation_schedule:
SELECT acode
FROM reservation
WHERE month(etd) = '".$month."'
AND dayofmonth(etd) = '".$dayArray["mday"]."'
AND year(etd) = '".$year."'
ORDER BY etd
And for the maintenance_schedule:
SELECT DISTINCT s.reg AS 'reg',
a.date AS 'date'
FROM (SELECT Curdate()
+ INTERVAL (a.a + (10 * b.a) + (100 * c.a)) day AS Date
FROM (SELECT 0 AS a
UNION ALL SELECT 1
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
UNION ALL SELECT 6
UNION ALL SELECT 7
UNION ALL SELECT 8
UNION ALL SELECT 9) AS a
CROSS JOIN (SELECT 0 AS a
UNION ALL SELECT 1
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
UNION ALL SELECT 6
UNION ALL SELECT 7
UNION ALL SELECT 8
UNION ALL SELECT 9) AS b
CROSS JOIN (SELECT 0 AS a
UNION ALL SELECT 1
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
UNION ALL SELECT 6
UNION ALL SELECT 7
UNION ALL SELECT 8
UNION ALL SELECT 9) AS c) a
INNER JOIN maintenance_sched s
ON a.date >= s.date_from
AND a.date <= s.date_to
WHERE Month(date) = '".$month."'
AND Dayofmonth(date) = '".$dayArray["mday"]."'
AND Year(date) = '".$year."'
I can show data from both of them by using UNION but I want the data from the maintenance table to be outputted as string with strikethrough. I'm outputting the query result in this code:
$chkEvent_res = mysql_query($chkEvent_sql) or die(mysql_error());
if (mysql_num_rows($chkEvent_res) > 0) {
$event_title = "<br/>";
while ($ev = mysql_fetch_array($chkEvent_res)) {
$event_title .= stripslashes($ev["reg"])."<br/>";
//$event_title .= "<del>".stripslashes($ev["acode"])."</del><br/>";
}
mysql_free_result($chkEvent_res);
} else {
$event_title = "";
}
If I use the query with UNION, I can't set the output string from maintenance to have strikethrough since it runs the query once. How can I achieve having the fetched data from maintenance table to output with strikethrough? Should I go for the one query with UNION? If I do, how can I separate the data coming from maintenance table and reservation table? If I go with separating the query, how can I run it? Should it be something like $chkEvent_res = mysql_query($chkEvent_sql1) and mysql_query($chkEvent_sql2) or die(mysql_error());? Please help, thanks.
The only way you can UNION these 2 queries is if you have the same number of columns in each query, and each column have the same data type. Not sure about the data types involved -- you have "acode" being returned from the first query and "reg" and "date" from the second query.
Assuming you could actually UNION your results and get what you need, you could consider adding an additional column to your results, returning the source of the query:
SELECT Field1, Field2, Field3, 'Table1' Source
FROM TABLE1
...
UNION
SELECT Field1, Field2, Field3, 'Table2' Source
FROM Table2
...
The you could use that Source column to format your results accordingly.
Here's some additional information about using UNION:
http://dev.mysql.com/doc/refman/5.0/en/union.html

MySQL query get 0 if no result for day

I am creating a line graph in flot, I have it all working except for the days which do not have a result I need them to come back with a result 0 + date. Is this possible in mysql? Here is my current query:
$chartQuery = "SELECT count(date) as counted_leads, UNIX_TIMESTAMP(date) as time FROM enquiries WHERE visibility != 'deleted' group by date";
Or would I need to do it in my php? Here is my code:
<?php
$last_key = end(array_keys($chartResults));
foreach ($chartResults as $item => $value)
{
$timestamp = round($value['time'] * 1000);
if ($item == $last_key)
{
// last element
echo '['.$timestamp.', '.htmlentities($value['counted_leads']).']';
}
else
{
// not last element
echo '['.$timestamp.', '.htmlentities($value['counted_leads']).'],';
}
}
unset($value);
?>
SELECT
ifnull(count(date),0) as counted_leads,
UNIX_TIMESTAMP(date) as time
FROM enquiries WHERE visibility != 'deleted'
group by date
Use if null for defult value
I think this is what you are looking for:
SELECT time, SUM(counted_leads) AS counted_leads
FROM(
SELECT UNIX_TIMESTAMP(date) AS time, count(1) AS counted_leads
FROM enquiries
WHERE visibility != 'deleted'
GROUP BY time
UNION ALL
SELECT a.Date AS time, 0 AS counted_leads
FROM (
SELECT CURDATE() - INTERVAL (a.a + (10 * b.a) + (100 * c.a)) DAY AS Date
FROM (SELECT 0 AS a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS a
CROSS JOIN (SELECT 0 AS a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS b
CROSS JOIN (SELECT 0 AS a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS c
) a
WHERE a.Date BETWEEN (SELECT MIN(date) FROM enquiries) AND (SELECT MAX(date) FROM enquiries)
) a
GROUP BY time;

Categories