Previously I was doing following to get per day count from reports table.
SELECT COUNT(*) AS count_all, tracked_on
FROM `reports`
WHERE (domain_id = 939 AND tracked_on >= '2014-01-01' AND tracked_on <= '2014-12-31')
GROUP BY tracked_on
ORDER BY tracked_on ASC;
Obviously this wont give me 0 count for missing dates.
Then I finally found a optimum solution to generate date-series between given date range.
But the next challenge am facing is to join it with my reports table and get the count grouped by date.
select count(*), all_dates.Date as the_date, domain_id
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
) all_dates
inner JOIN reports r
on all_dates.Date >= '2014-01-01'
and all_dates.Date <= '2014-12-31'
where all_dates.Date between '2014-01-01' and '2014-12-31' AND domain_id = 939 GROUP BY the_date order by the_date ASC ;
The result am getting is
count(*) the_date domain_id
46 2014-01-01 939
46 2014-01-02 939
46 2014-01-03 939
46 2014-01-04 939
46 2014-01-05 939
46 2014-01-06 939
46 2014-01-07 939
46 2014-01-08 939
46 2014-01-09 939
46 2014-01-10 939
46 2014-01-11 939
46 2014-01-12 939
46 2014-01-13 939
46 2014-01-14 939
...
Whereas am looking to fill in the missing dates with 0
something like
count(*) the_date domain_id
12 2014-01-01 939
23 2014-01-02 939
46 2014-01-03 939
0 2014-01-04 939
0 2014-01-05 939
99 2014-01-06 939
1 2014-01-07 939
5 2014-01-08 939
...
Another try that I gave was:
select count(*), all_dates.Date as the_date, domain_id
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
) all_dates
inner JOIN reports r
on all_dates.Date = r.tracked_on
where all_dates.Date between '2014-01-01' and '2014-12-31' AND domain_id = 939 GROUP BY the_date order by the_date ASC ;
Results:
count(*) the_date domain_id
38 2014-09-03 939
8 2014-09-04 939
Minimal data with above queries: http://sqlfiddle.com/#!2/dee3e/6
You need an OUTER JOIN to arrive at every day between a start and an end because if you use an INNER JOIN it will restrict the output to just the dates that are joined (i.e. just those dates in the report table).
In addition, when you use an OUTER JOIN you must take care that conditions in the where clause don't cause an implicit inner join; for example AND domain_id = 1 if use in the where clause would suppress any row that did not have that condition met, but when used as a join condition it only restricts the rows of the report table.
SELECT
COUNT(r.domain_id)
, all_dates.Date AS the_date
, domain_id
FROM (
SELECT DATE_ADD(curdate(), INTERVAL 2 MONTH) - INTERVAL (a.a + (10 * b.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
) all_dates
LEFT OUTER JOIN reports r
ON all_dates.Date = r.tracked_on
AND domain_id = 1
WHERE all_dates.Date BETWEEN '2014-09-01' AND '2014-09-30'
GROUP BY
the_date
ORDER BY
the_date ASC;
I have also changed the all_dates derived table, by using DATE_ADD() to push the starting point into the future, and I have reduced the it's size. Both of these are options and can be tweaked as you see fit.
Demo at SQLfiddle
to arrive at a domain_id for every row (as shown in your question) you would need to use someting like the following; Note you could use IFNULL() which is MySQL specific but I have used COALESCE() which is more generic SQL. However use of an #parameter as shown here is MySQL specific anyway.
SET #domain := 1;
SELECT
COUNT(r.domain_id)
, all_dates.Date AS the_date
, coalesce(domain_id,#domain) AS domain_id
FROM (
SELECT DATE_ADD(curdate(), INTERVAL 2 month) - INTERVAL (a.a + (10 * b.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
) all_dates
LEFT JOIN reports r
ON all_dates.Date = r.tracked_on
AND domain_id = #domain
WHERE all_dates.Date BETWEEN '2014-09-01' AND '2014-09-30'
GROUP BY
the_date
ORDER BY
the_date ASC;
See this at SQLfiddle
The all_dates subquery is only looking back from the current day (curdate()). If you want to include future dates, change the first line of the subquery to something like:
select '2015-01-01' - INTERVAL (a.a + (10 * b.a) + (100 * c.a)) DAY as Date
Related
I'm trying to generate seven rows for each date in the last seven days, and join with a query from transactions table. The aim is to have a table with each date, and the cumulative total of the quantity column in transactions from the first entry up to the date:
| date | stockOnDate |
|---------------|---------------|
| 2021-10-15 | 10 |
| 2021-10-16 | 3 |
| 2021-10-17 | 0 |
| 2021-10-18 | 9 |
| 2021-10-19 | 15 |
| 2021-10-20 | 15 |
| 2021-10-21 | 15 |
I can get the list of dates, and can join, but can't filter the nested queries:
SELECT v.*, t.*
FROM ( SELECT DATE(ADDDATE(DATE_SUB(NOW(),INTERVAL 7 DAY), t3*1000 + t2*100 + t1*10 + t0)) AS `date`
FROM (SELECT 0 t0 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) t0,
(SELECT 0 t1 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) t1,
(SELECT 0 t2 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) t2,
(SELECT 0 t3 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) t3 ) AS v
LEFT JOIN (SELECT SUM(quantity) AS stockOnDate, DATE(timestamp) as tDate
FROM `transactions`
WHERE tDate <= v.`date`) AS t ON t.tDate = v.`date`
WHERE v.`date` >= DATE_SUB(NOW(),INTERVAL 7 DAY) AND v.`date` <= DATE(NOW())
But I'm receviing the following error:
#1054 - Unknown column 'tDate' in 'where clause'
If I replace WHERE tDate <= v.date with WHERE DATE(timestamp) <= v.date I get the same error for v.date - I can't seem to access the value of the parent tables.
I'm not great with MySQL but can't seem to find a solution, where am I going wrong?
Solution by ProGuru
Thanks to ProGuru's answer below, the below query works as expected (using <= instead of = in the JOIN was key)
SELECT b.date, SUM(a.quantity) AS stockOnDate
FROM (
SELECT DATE(ADDDATE(DATE_SUB(NOW(),INTERVAL 6 DAY), t3*1000 + t2*100 + t1*10 + t0)) AS `date`
FROM (SELECT 0 t0 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) t0,
(SELECT 0 t1 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) t1,
(SELECT 0 t2 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) t2,
(SELECT 0 t3 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) t3
) b
LEFT JOIN transactions a ON DATE(a.timestamp) <= b.date
WHERE b.date BETWEEN DATE(NOW()) - INTERVAL 6 DAY AND DATE(NOW())
AND a.organisationId = 1
GROUP BY b.date
ORDER BY b.date ASC
I can also change the GROUP BY to GROUP BY a.itemID, b.date to get the stock level on the given date for each itemId.
To get the cumulative sum of quantity, the date join needs to use <=
Revised SQL
SELECT b.date, SUM(COALESCE(a.quantity, 0))
FROM (
SELECT DATE(ADDDATE(DATE_SUB(NOW(),INTERVAL 7 DAY), t3*1000 + t2*100 + t1*10 + t0)) AS `date`
FROM (SELECT 0 t0 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) t0,
(SELECT 0 t1 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) t1,
(SELECT 0 t2 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) t2,
(SELECT 0 t3 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) t3
) b
LEFT JOIN transactions a ON DATE(a.timestamp) <= b.date
WHERE b.date BETWEEN DATE(NOW()) - INTERVAL 6 DAY AND DATE(NOW())
GROUP BY b.date
ORDER BY b.date ASC
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=34f78e3d7c9225727ac2e728588759e2
To use alias in where clause, you must encapsulate your query in another select.
Example :
SELECT * FROM
(SELECT SUM(quantity) AS stockOnDate, DATE(timestamp) as tDate FROM `transactions`) seb
WHERE seb.tDate <= v.`date`
Update try this:
SELECT v.*, t.*
FROM ( SELECT DATE(ADDDATE(DATE_SUB(NOW(),INTERVAL 7 DAY), t3*1000 + t2*100 + t1*10 + t0)) AS `date`
FROM (SELECT 0 t0 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) t0,
(SELECT 0 t1 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) t1,
(SELECT 0 t2 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) t2,
(SELECT 0 t3 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) t3 ) AS v
LEFT JOIN (SELECT SUM(quantity) AS stockOnDate, DATE(timestamp) as tDate FROM transactions) AS t ON t.tDate = v.`date`
WHERE t.tDate <= v.`date` and v.`date` >= DATE_SUB(NOW(),INTERVAL 7 DAY) AND v.`date` <= DATE(NOW())
here tDate can be used
Firstly you need to understand that in this subquery
(SELECT SUM(quantity) AS stockOnDate, DATE(timestamp) as tDate
FROM `transactions`
WHERE tDate <= v.`date`) AS t
there is nothing defined as date or even the alias v. You're basically telling the query to look for v.date when it doesn't exists in the subquery.
I think this is what you're looking for:
SELECT dt, IFNULL(SUM(quantity),0) AS stockOnDate
FROM (SELECT STR_TO_DATE(CONCAT(LEFT(NOW(),7),LPAD(seq,2,0)), '%Y-%m%d') dt
FROM seq_1_to_31) v
LEFT JOIN `transactions` t ON dt=DATE(timestamp)
WHERE dt >= (SELECT MIN(DATE(timestamp)) FROM `transactions`)
AND dt <= (SELECT MAX(DATE(timestamp)) FROM `transactions`)
GROUP BY dt;
Here I'm using MariaDB's built-in sequence engine to generate days; concatenated with current year-month combination then uses STR_TO_DATE to make it recognizable as proper date format. The query generating those is in subquery v.
Second option is using a recursive common table expression to generate the date range based on existing date data in the table. Here is the query:
WITH RECURSIVE cte AS (
SELECT MIN(DATE(timestamp)) mndt, MAX(DATE(timestamp)) mxdt FROM `transactions`
UNION ALL
SELECT mndt+INTERVAL 1 DAY, mxdt FROM cte WHERE mndt+INTERVAL 1 DAY <= mxdt)
SELECT mndt, IFNULL(SUM(quantity),0) AS stockOnDate
FROM cte
LEFT JOIN `transactions` t ON mndt=DATE(timestamp)
GROUP BY mndt;
Both the query above eliminates the need to include a long subquery that generates the date range. This is the benefit of newer MySQL & MariaDB versions.
Demo fiddle
I have a table Order:
id total_amount date_order
1 12.000 2018-09-01
2 10.000 2018-09-01
3 5.000 2018-09-03
4 2.000 2018-09-05
I have query SUM data group by date:
select SUM(total_amount) as 'total', DATE(date_order) as 'date'
from Order
where date_order >= '2018-09-01' and date_order <= '2018-09-06'
group by (date_order)
It shows:
total date
22.000 2018-09-01
5.000 2018-09-03
2.000 2018-09-05
Because data in 2018-09-02 and 2018-09-04 have no data so It's not show in result. But I want query to show table with expect result:
total date
22.000 2018-09-01
0 2018-09-02
5.000 2018-09-03
0 2018-09-04
2.000 2018-09-05
Every can help me write query to show like expect result ?
Create another table to join on.
It could be a table of dates, such as all date from 2000-01-01 until 2099-12-31...
SELECT
dt.`date`,
SUM(total_amount) as `total`
FROM
yourDatesTable AS dt
LEFT JOIN
Order AS o
ON o.`date_order` = dt.`date`
WHERE
dt.`date` >= '2018-09-01'
AND dt.`date` < '2018-09-08'
GROUP BY
dt.`date`
ORDER BY
dt.`date`
Or it could be a numbers table with values from -1023 to +1024 (or some other useful range)...
SELECT
n.id,
'2018-09-01' + INTERVAL n.id DAYS,
SUM(total_amount) as `total`
FROM
yourNumbersTable AS n
LEFT JOIN
Order AS o
ON o.`date_order` = '2018-09-01' + INTERVAL n.id DAYS
WHERE
n.id >= 0
AND n.id < 8
GROUP BY
n.id
ORDER BY
n.id
generate date and join with ordere table
select SUM(O.total_amount) as total, DATE(gen_date) as oreder_date
from
(
select * from
(select adddate('1970-01-01',t4*10000 + t3*1000 + t2*100 + t1*10 + t0) gen_date from
(select 0 t0 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) t0,
(select 0 t1 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) t1,
(select 0 t2 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) t2,
(select 0 t3 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) t3,
(select 0 t4 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) t4) v
where gen_date between '2018-09-01' and '2018-09-30'
) as t1 left join `Order` O on t1.gen_date= DATE(O.date_order)
where gen_date >= '2018-09-01' and gen_date <= '2018-09-06'
group by oreder_date
I'm using the code below in order to generate data from midnight till now.
SELECT CONCAT(Hour, ':00-', Hour+1, ':00') AS Hours, IFNULL(COUNT(product_id), 0) AS `total_count`
FROM clicks
RIGHT JOIN (
SELECT 0 AS Hour
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
UNION ALL SELECT 10 UNION ALL SELECT 11 UNION ALL SELECT 12
UNION ALL SELECT 13 UNION ALL SELECT 14 UNION ALL SELECT 15
UNION ALL SELECT 16 UNION ALL SELECT 17 UNION ALL SELECT 18
UNION ALL SELECT 19 UNION ALL SELECT 20 UNION ALL SELECT 21
UNION ALL SELECT 22 UNION ALL SELECT 23
) AS AllHours ON HOUR(clicked_at) = Hour
WHERE ( clicked_at BETWEEN CURRENT_DATE() AND NOW() OR clicked_at IS NULL ) AND clicks.site='awesome-site.com'
GROUP BY Hour
ORDER BY Hour
I need the code to return something like
Hours total_count
----------------------
0:00-1:00 19
1:00-2:00 2
2:00-3:00 0
3:00-4:00 0
4:00-5:00 0
5:00-6:00 1
6:00-7:00 0
7:00-8:00 0
8:00-9:00 0
9:00-10:00 4
10:00-11:00 2
11:00-12:00 0
12:00-13:00 17
13:00-14:00 1
The issue is that the query above is return is returning data with gap in the Hours column; something like:
Hours total_count
----------------------
0:00-1:00 19
1:00-2:00 2
5:00-6:00 1
9:00-10:00 4
10:00-11:00 2
12:00-13:00 17
13:00-14:00 1
Thanks for the help.
right join is the correct approach, but you are using columns from clicks table in the where statement. Instead put the filter in on:
SELECT CONCAT(Hour, ':00-', Hour+1, ':00') AS Hours, IFNULL(COUNT(product_id), 0) AS `total_count`
FROM clicks
RIGHT JOIN (
SELECT 0 AS Hour
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
UNION ALL SELECT 10 UNION ALL SELECT 11 UNION ALL SELECT 12
UNION ALL SELECT 13 UNION ALL SELECT 14 UNION ALL SELECT 15
UNION ALL SELECT 16 UNION ALL SELECT 17 UNION ALL SELECT 18
UNION ALL SELECT 19 UNION ALL SELECT 20 UNION ALL SELECT 21
UNION ALL SELECT 22 UNION ALL SELECT 23
) AS AllHours ON HOUR(clicked_at) = Hour
and ( clicked_at BETWEEN CURRENT_DATE() AND NOW() OR clicked_at IS NULL ) AND clicks.site='awesome-site.com'
GROUP BY Hour
ORDER BY Hour
An easy potential solution would be to just have a separate table with all the hours in a day (since the only problem seems to be having 0 entries that fall within certain hours):
Hours
-------------
0:00-1:00
1:00-2:00
2:00-3:00
...
22:00-23:00
23:00-24:00
Then JOIN that to the other table you have, I think basically all the other stuff you do should work with this such as the IFNULL and WHERE ( clicked_at BETWEEN CURRENT_DATE() AND NOW() ...
Table Pricing
What i want, is to provide a start_date & an end_date in order to get the price_per_day for each day between those 2 dates.
For example if i set as a start_date = 2015-05-30 & end_date = 2015-06-02, the desired output is
2015-05-30 | 24.00
2015-05-31 | 24.00
2015-06-01 | 27.00
2015-06-02 | 27.00
UPDATE:
Even if this output would be ok for me
24.00
24.00
27.00
27.00
You have to select dates greater than say 'From' date and lesser than 'To' date. I have posted the following without testing so please test and let me know in case of any errors.
SELECT Price FROM Pricing WHERE start_date >= '2015-05-30' AND end_date <= '2015-06-02'
Edit:
Please make sure the start_date and end_date have the same type as the dates provided. Just to be on the safe side, you could also convert them into datetime or convert(varchar, yourDatevariable, 103) but you have to apply it on both sides of the condition.
What you need to do is have a range of dates (ie, 1 row per date). This can be done a few ways. Probably the most efficient is having a calendar table, but if you cannot add new tables that is not possible.
You can have a table of numbers and add that to the starting date of each row, but again this requires a new table.
As such the option is to have a set of unioned queries to generate a range of numbers. For example the following will return 10 rows with the numbers 0 to 9:-
SELECT 0 a 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
You can cross join such sub queries against each other to generate a larger range of numbers, and add that to your start date where the results is less than of equal to the end date:-
SELECT id, start_date, end_date, price_per_day, DATE_ADD(start_date, INTERVAL (units.a + tens.a * 10 + hundreds.a * 100) DAY) AS aDay
FROM pricing
CROSS JOIN (SELECT 0 a 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) units
CROSS JOIN (SELECT 0 a 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) tens
CROSS JOIN (SELECT 0 a 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) hundreds
WHERE DATE_ADD(start_date, INTERVAL (units.a + tens.a * 10 + hundreds.a * 100) DAY) <= end_date
The above will cope with up to 1000 days between the dates. Easy to expand to cope with 10000 days or more, but will become slower.
You can then just use that as a sub query when checking the date range you are interested in:-
SELECT aDay, price_per_day
FROM
(
SELECT id, start_date, end_date, price_per_day, DATE_ADD(start_date, INTERVAL (units.a + tens.a * 10 + hundreds.a * 100) DAY) AS aDay
FROM pricing
CROSS JOIN (SELECT 0 a 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) units
CROSS JOIN (SELECT 0 a 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) tens
CROSS JOIN (SELECT 0 a 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) hundreds
WHERE DATE_ADD(start_date, INTERVAL (units.a + tens.a * 10 + hundreds.a * 100) DAY) <= end_date
) sub0
WHERE aDay BETWEEN '2015-05-30' AND '2015-06-02'
ORDER BY aDay
Your request should look something like this :
SELECT Price FROM Pricing WHERE start_date = 2015-05-30 AND end_date = 2015-06-02
But to print out everydate date between those two, i've no idea.
This might help you thought :
How to list all dates between two dates
I have a table for slots that have the following Schema
SlotId
FromDate
ToDate
I want to get the remaining days in that given month available for slot booking.
To be clear, I am trying to retrieve all the dates apart from the dates stored in the database(as those are already booked) for a given month.
For example, if a record have FromDate is equal to 2014-04-02 and ToDate is equal to 2014-04-06 I am expecting the following result:
2014-04-01
2014-04-07
...
2014-04-30
Although i am scripting in PHP, I am little curious about the query to accomplish this.
So it is not an easy thing to do in mysql but here is something that should work. this gets the dates in any given month that are not booked... see fiddle for working example
SELECT *, union_month.day_date
FROM (
SELECT 1 AS day_date 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 UNION ALL
SELECT 10 UNION ALL
SELECT 11 UNION ALL
SELECT 12 UNION ALL
SELECT 13 UNION ALL
SELECT 14 UNION ALL
SELECT 15 UNION ALL
SELECT 16 UNION ALL
SELECT 17 UNION ALL
SELECT 18 UNION ALL
SELECT 19 UNION ALL
SELECT 20 UNION ALL
SELECT 21 UNION ALL
SELECT 22 UNION ALL
SELECT 23 UNION ALL
SELECT 24 UNION ALL
SELECT 25 UNION ALL
SELECT 26 UNION ALL
SELECT 27 UNION ALL
SELECT 28 UNION ALL
SELECT 29 UNION ALL
SELECT 30 UNION ALL
SELECT 31
) AS union_month
LEFT JOIN myTable AS t ON union_month.day_date <> DAY(t.to_date) OR union_month.day_date <> DAY(t.from_date)
WHERE union_month.day_date <= DAY(LAST_DAY(t.to_date))
AND union_month.day_date NOT BETWEEN DAY(t.from_date) AND DAY(t.to_date)
GROUP BY union_month.day_date
for multiple dates in a month change the WHERE clause to this
WHERE
union_month.day_date <= DAY(LAST_DAY(t.to_date))
AND union_month.day_date not BETWEEN (select DAY(from_date) from myTable limit 0,1) AND (select DAY(to_date) from myTable limit 0,1)
AND union_month.day_date not BETWEEN (select DAY(from_date) from myTable limit 1,1) AND (select DAY(to_date) from myTable limit 1,1)
AND union_month.day_date not BETWEEN (select DAY(from_date) from myTable limit 2,1) AND (select DAY(to_date) from myTable limit 2,1)
GROUP BY union_month.day_date
working fiddle for multiple dates
You need remaining days count or dates which are free?
I have tried this. May it will help you.
You need to use this query in loop. with some variables.
In example I have consider April month only. You can do it for all months.
SELECT distinct * FROM (SELECT DATE_ADD('2014-04-01', INTERVAL t4+t16+t64+t256+t1024 DAY) freedays FROM
(SELECT 0 t4 UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 ) t4,
(SELECT 0 t16 UNION ALL SELECT 4 UNION ALL SELECT 8 UNION ALL SELECT 12 ) t16,
(SELECT 0 t64 UNION ALL SELECT 16 UNION ALL SELECT 32 UNION ALL SELECT 48 ) t64,
(SELECT 0 t256 UNION ALL SELECT 64 UNION ALL SELECT 128 UNION ALL SELECT 192) t256,
(SELECT 0 t1024 UNION ALL SELECT 256 UNION ALL SELECT 512 UNION ALL SELECT 768) t1024
) b
WHERE freedays not between (select FrmDate from slotbooking limit 1) and (select ToDate from
slotbooking limit 1) and freedays < '2014-04-30';