MySQL find first available weekend - php

I have a table which holds restaurant reservations. It just has an restaurant_id and a date column which specify the actual date (we are talking about whole day reservations).
I want to find out when is the next available weekend for a particular restaurant. A "weekend" is either Saturday or Sunday. If one of them is available, then we have an available weekend.
The query should, of course, consider the current time to calculate the next weekend.
Can anyone help?
Here's the table structure and data for the "dates" table which holds all reservations made so far:
id id_venue date
12 1 2011-04-22
13 1 2011-04-23
14 1 2011-04-24
15 1 2011-04-30
16 1 2011-05-07
17 1 2011-05-08
As you can see, the weekend of 23-24 is full, so the one of 7-8 May. What I need to find is the date of 2001-05-01 which is the first available Saturday OR Sunday after today's date.

I think the others are missing the question... They think your table may already be POPULATED with all weekends and some status as to open or not... My guess is that your table only HAS a record IF it is reserved... thus you need to find records that DO NOT EXIST AT ALL... based on some automated Look for dates...
This is a modification to another post I've done here
Although I didn't change the context of the query, I only put in the columns associated to YOUR table. I understand you are only going against a single venue table and so am I (actually). However, to understand the "JustDates" alias, this INNER PRE-QUERY is creating a dynamically populated table of ALL DATES by doing a Cartesian join against ANY other table.. in this case, your "Venue" table of reservations (I didn't see your actual table name reference explicitly, so you'll have to change that). So, this in essence creates a table of all dates starting from whatever "today" is and goes forward for 30 days (via limit), but could be 40, 50, 300 or as many as you need.. provided the "YourVenueTable" has at least as many records as days you want to test for. (same clarification in post this was derived from). This result set going out 30, 40 or however many days is pre-filtered for ONLY the given day of week of 1-Sunday or 7-Saturday... So it should return a result set of only Apr 23, Apr 24, Apr 30, May 1, May 7, May 8, May 14, May 15, May 21, May 28, etc.
So NOW you have a dynamically created result set of all possible days you are considering moving forward. Now, that gets joined to your actual Venue Reservations table and is filtered to ONLY return those DATES where it is NOT found for the id_venue you are concerned about. In your data example it WOULD find a match on Apr 23 and 24 and NOT return those records. Same with Apr 30... However, it WILL find that the record in the prequalifying list that includes May 1 will NOT find the date match in the venue table and thus include that as you are anticipating... It will then continue to skip May 7 and 8, then return May 14, 15, 21, 28, etc...
select JustDates.OpenDate
from
( select
#r:= date_add( #r, interval 1 day ) OpenDate
from
( select #r := current_date() ) vars,
Venue
LIMIT 30 ) JustDates
where
DAYOFWEEK( JustDates.OpenDate ) IN ( 1, 7 )
AND JustDates.OpenDate NOT IN
( select Venue.date
from Venue
where Venue.id_venue = IDYouAreInterestedIn
and Venue.Date = JustDates.OpenDate )
order by
JustDates.OpenDate
Note, and per the other reservations posting, the query for reservation date availability dates doing a limit of 30 above can be ANY table in the system as long as it has AT LEAST as many days out as you want to look forward for reservations... If you want all availability for an upcoming year, you would want 365 records in the table used for a Cartesian result to get the #r cycling through dynamically created "date" records.

SELECT ...... DAYOFWEEK(`date`) as `num` FROM .... WHERE num = 1 OR num = 7
I don't know how u wanna check "availability"

How about?:
SELECT * FROM table WHERE (DAYOFWEEK(date)=1 OR DAYOFWEEK(date)=7) AND restaurant_id =$RESTAURANTID AND date > CURDATE() ORDER BY date ASC LIMIT 1

Set the number of days from today until the next Saterday (if 0 then today is Saterday)
Assuming that if today is Sunday you only want reservations for the next full weekend.
select #OffsetSaterday:= mod((8-DayOfWeek(CurDate())+7,7);
You have not supplied enough info to know how the reservation database looks, so I'm going to guess here.
Every restaurant has seats:
Table seats
id: integer primary key
rest_id: integer #link to restaurant
desc: varchar(20) # description of the seat.
Table restaurant
id: integer primary key
other fields.....
Table Reservation
id: integer primary key
reservation_date: date
seat_id: integer
The select statement to get all available seats for next weekend is:
select #OffsetSaterday:= mod((8-DayOfWeek(CurDate())+7,7);
select s.*, rst.* from seats s
inner join restaurant rst on (rst.id = seats.rest_id)
left join r on (r.seat_id = s.id
and r.reservation_date between
date_add(curdate(),interval #OffsetSaterday day) and
date_add(curdate(),interval #OffsetSaterday+1 day)
where r.id is null
order by s.rest_id, s.desc;
You might be able to combine the two selects into one, but MySQL does not guarantee the order in which expressions get evaluated, so I would recommend against that.

Related

MSSQL datetime datetime in php

I have a problem where i think exist a couple solutions.
scenario
I have build this intranetpage where internal performance KPI's are visible for the office.
The data is extracted from a MSSQL database and shown on the webpage in combination with PHP, than the data and converted to an array so Google Chart API can create beautiful charts from there.
So far, so good!
Problem
I have a chart where the created tickets from the last 7 days are shown (in reverse order). The number of tickets are created by a MSSQL count, one number for each day (today - 7) in total.
But on some days, no tickets are created like a saterday or sunday. Thats where things go wrong.
Today is Thursday and it shows:
Day Amount
Thursday 25
Friday 10
Monday 30 (etc)
Tuesday 15 (day before)
Wednesday 20 (yesterday)
Thursday 50 (today)
instead of
Saturday 0
Sunday 0
Monday 30
Tuesday 15
Wednesday 20
Thursday 50
The problem is that there are no records (tickets) with a create-date on saturday or sunday, so MSSQL cant count them.
PHP calculates the dates (also today -7) that are shown beneath the axis in my chart, but PHP does include Saterday and Sunday, so the axis titles are not representive for the data that the axis shows.
Possible solution
One solution is that somehow MSSQL shows Saterday and Sunday in the result table. But i dont think this is possible, because the records simply dont exist.
Other solution
Retrieve the datetime used in the MSSQL query and parse them to my intranetpage so the google charts can display those dates instead of the PHP created dates. But than i get a "Convert datetime class to string" error.
Because the datetime in MSSQL is a datetime type and not a varchar type.
After trying a lot of things and searching even more on google and stackoverflow, i can succesfull convert a datetime to varchar. But than the part where i take todays date and go back 7 days, doesnt work anymore.
My PHP (and query) look as follow:
$sql = "
SELECT top 7
CAST(bb_casestartingtime AS DATE) AS DATE, COUNT(*) as TotalRows
FROM
CRM_MSCRM.dbo.FilteredIncident
WHERE
bb_casestartingtime > (CONVERT(date, GETDATE() - 7))
GROUP BY CAST(bb_casestartingtime AS DATE)
Order by date
";
$stmt = sqlsrv_query( $conn, $sql );
if( $stmt === false) {die( print_r( sqlsrv_errors(), true) );}
$x=5;
while( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_ASSOC) )
{ **$dateValue = date("Y-m-d", strtotime(" -$x day"));**
echo "[',".$row[**date**].$row['TotalRows'].",],";
$x--;
}
I broke the two pieces of code in half, but actually they are
The table looks like this (at least, the interesting part):
case id bb_casestartingtime
01 2016-11-10 15:30:45.000
02 2016-11-10 16:22:10.000
03 2016-11-09 15:02:15.000
I count the amount of occurrences by date (bb_casestartingtime) as a total.
So today i have
today 2 records
yesterday 1 record
Acutal Question
can somebody help me to extraced the date-time which is used in the query?
I only use one table called: FilteredIncident
Is there a way to convert the datetime bb_casestartingtime to a varchar (so PHP can extract it) but still count the amount of occurrences per day?
If any information is needed, please ask
Thanks in advance!
(I rewrote my entire question, because i wrote the initial post in a rush)
You could achieve what you're after by creating a date range table and the you can LEFT JOIN to it, so you get 0 for the days with no tickets. You can run this code in isolation to test and it should give you something you can adapt:
-- table for dummy data
CREATE TABLE #FilteredIncident (bb_casestartingtime DATETIME)
-- insert dummy data that has gaps and more than 7 days
INSERT INTO #FilteredIncident
( bb_casestartingtime )
VALUES ( '20161110 12:00'),
( '20161110 11:00'),
( '20161109 10:00'),
( '20161108 13:00'),
( '20161107 09:00'),
( '20161104 07:00'),
( '20161104 05:00'),
( '20161104 16:00'),
( '20161103 18:00'),
( '20161103 19:00')
-- create a date range table for last 7 days
CREATE TABLE #DateRange ( DateVal Date )
-- insert last 7 days
INSERT INTO #DateRange
( DateVal )
VALUES ( GETDATE() )
,( DATEADD(D,-1,GETDATE()))
,( DATEADD(D,-2,GETDATE()))
,( DATEADD(D,-3,GETDATE()))
,( DATEADD(D,-4,GETDATE()))
,( DATEADD(D,-5,GETDATE()))
,( DATEADD(D,-6,GETDATE()))
-- SELECT * FROM #FilteredIncident -- uncomment to see data
-- SELECT * FROM #DateRange -- uncomment to see date range data
SELECT COUNT(fi.bb_casestartingtime) TotalRows, dr.DateVal
FROM #DateRange dr
LEFT JOIN #FilteredIncident fi ON dr.DateVal = cast(fi.bb_casestartingtime AS DATE)
GROUP BY dr.DateVal
ORDER BY dr.DateVal
DROP TABLE #FilteredIncident
DROP TABLE #DateRange
Produces:
TotalRows DateVal
3 2016-11-04
0 2016-11-05
0 2016-11-06
1 2016-11-07
1 2016-11-08
1 2016-11-09
2 2016-11-10
Note:
I'd recommend moving this SQL code in to a stored procedure as opposed to building a string to execute like you are doing.
I solved the problem with a work arround, as i didnt need to see the days where there are 0 tickets, i didnt have to build an temporary table and do a left join.
The solution i came with is to use the datetime fields (bb_casestartingtime) and use those dates. Now the chart axis title matches the chart bar.
solution
Convert the $variable where the datetime field is put to, to a datetime field variable.
$rows[] = "['".$row[1]->format('D j-m')."',".$row[0]."],";
^ ^ ^
The datetime row | The format | The amount of tickets

mysql & php - How to calculate total year of experience from multiple date range?

I want to calculate total experience year and month of each particular user id. user_id can be multiple in the table like the following. Here for user_id 14, the total experience range will be from 2010-01-03 to 2013-11-30 and the expected result will be 3 year 11 month. How can I do it in either php or mysql?
Comments are relevant but incomplete for your case.
If exp_to is not nullable:
select user_id, sum( datediff(exp_to, exp_from) +1 )
from experience
group by user_id;
Notes:
don't forget +1 in the sum, because for user 25 it would return 0, whereas we can decently consider the user worked 1 day
for user 14, based on your screenshot, the total is 880 days: you'll have to calculate the number of months (with PHP, for example).
If exp_to is nullable (which makes sense if user is still working at the same position):
select user_id, sum( datediff( ifnull(exp_to, now()), exp_from) +1 )
from experience
group by user_id;

create mysql query for fetching data in 3 days slotwise

I want to create a query for fetch all the data from database. But condition is get from before current month and data will convert into 3 days slot wise with count.Like if i have 12 month data and in July 1 to 3 date data will insert into 50 rows and from 3 to 6 date data will insert into 5 rows.How i fetch this things.That is the mail problem. I have wondered but nothing found related my problem. Is this possible.
I assume you have a DATE or a DATETIME column, that marks the day of the insert, say the column created_at. Then you could get the desired result.
SELECT
COUNT(*)
FROM
your_table
WHERE
created_at BETWEEN '2014-07-01' AND '2014-07-31 23:59:59'
GROUP BY
(DAYOFMONTH(created_at) - 1) DIV 3
Explanation:
With the help of the DIV operator you get your 3-day-slots.
Note
If there's a slot without rows, it won't be in the result. To get these too, you could use a LEFT JOIN with the maximum 11 slots.
Demo
If you having timestamps as attribute type then might be this help you
SELECT count(*) as count
FROM table
AND
TIMESTAMPDIFF(DAY,date,2014-08-01)<=3";
The date is the attribute of your column, TIMESTAMPDIFF will find difference between given date if it's under 3 days from 2014-08-01 records will show up. This way by just sending one date into this position you can find 3 slots of date from your table.

how to count the number of dates in a table

I have a small custom blog type site and I keep track of my posts with a datetime field in the DB that hold a current_timestamp when entered.
I am working on a pagination setup and want to figure out how many unique days there are in my DB.
For example in the below screen shot there are 19 entries but only entered on 5 different days.
I want to be able to find the number of unique days in the DB. In the above shot 5.
This way I can paginate my posts by groups of days, say 7 but still show all the posts for all those days regardless of if one day has more posts or one day has none.
EX for page 1 showing the first 7 days of posts:
Jan 1st
+post
+post
+post
Jan 3
+post
Jan 4
+post
+post
Jan 5
+post
Jan 6
+post
+post
Jan 7
+post
Jan 8
+post
+post
How is the best way to get this data or paginate in this way?
Thanks
Try below:
select count(*),date from tablename group by left(date,10)
above query will give count of unique days.
This will give you the amount of posts per day:
select from_days(to_days(date)) day, count(*) from t
group by day
You can then apply a limit to the amount of records (days) to paginate them per 7 days:
select from_days(to_days(date)) day, count(*) from t
group by day
limit 7
Now, if you want to get the actual posts (I think that is what you want), you can do this:
select date, file from t t1 join (
select to_days(date) day from t
group by day
order by day desc
limit 7
) t2
on to_days(t1.date) = t2.day
This will give you all posts for the 7 most current days. Is that what you where looking for?
Edit:
I may be misinterpreting or did not ask my question well but I want the the count of all total unique days not posts. - ian
LOL: That's easier :)
select count(distinct to_days(date)) from t
I guess what you are looking for is
SELECT count(*) from table group by DATE(date)
the trick is to map datetime into date via DATE() function
UPDATE: sorry I missinterpreted your question. This will return the number of posts in each day.
To get number list of unique days you could do
SELECT DISTINCT DATE(datetime) from table
To get number of unique days you could either check the count of it in your back-end language or make a subquery, like:
select count(*) from (select distinct date(datetime) from table) as res

MySQL AVG(COUNT(*) - Orders By day of week query?

This query has baffled me... I've searched the web work over a day now and I have tried numerous things.
I want to get the avg number of orders for every day of the week from my db. I can pull the total # with COUNT just fine. But I just can't figure out how to get the AVG of COUNT on a GROUP BY. I've tried subqueries... functions... everything... nothing works... maybe someone can throw me a bone.
Here is the query I started with below. I know AVG(COUNT(*)) won't work but I'll leave it at that because it shows what I want to do.
SELECT
AVG(COUNT(*)) AS avgorders,
SUM(total) AS ordertotal,
DAYNAME(STR_TO_DATE(order_time,'%m/%d/%Y %H:%i')) AS day
FROM data
GROUP BY day
ORDER BY DAYOFWEEK(STR_TO_DATE(order_time,'%m/%d/%Y %H:%i')) ASC
To get the average you don't need the grand totals for each day, you need multiple daily totals for each day.
Day | Count
__________________
Monday 5
Tuesday 4
Monday 6
Tuesday 3
... ...
Then you can average those numbers. I.e (5+6)/2 for Monday.
Something like this should work:
SELECT day_of_week, AVG(order_count) average_order FROM
(
SELECT DAYNAME(order_date) day_of_week,
DAYOFWEEK(order_date) day_num,
TO_DAYS(order_date) date,
count(*) order_count
FROM data
GROUP BY date
) temp
GROUP BY day_of_week
ORDER BY day_num
UPDATE: I was originally wrong. Group the inner SELECT by the actual date to get the correct daily totals. For instance, you need to get how many orders happened Monday (2/1/10) and Monday (2/8/10) separately. Then average those totals by the day of the week.
This will do, assuming that order_time is date or datetime field ( everyone would be hapier this way ;) ). Of course there is some approximation, because oldest order can be in Friday and newest in Monday, so amount of every day of week isn't equal, but creating separate variable for every day of week will be pain in the ass. Anyway I hope it will be helpful for now.
SET #total_weeks = (
SELECT
TIMESTAMPDIFF(
WEEK,
MIN(order_time),
MAX(order_time)
)
FROM data
);
SELECT
DAYNAME(order_time) AS day_of_week,
( COUNT(*) / #total_weeks ) AS avgorders,
COUNT(*) AS total_orders
FROM
data
GROUP BY
DAYOFWEEK(order_time)
I know this is old, but i was searching for a similar solution hoping to find something someone else had used. In hopes of not doing a sub query, i came up with the below and would love any feed back!
SELECT dayofweek(`timestamp`) as 'Day',count(`OrderID`)/count(DISTINCT day(`timestamp`)) as 'Average' FROM `Data` GROUP BY dayofweek(`timestamp`)
The idea is to divide the total orders on a given day of the week, by the total number of "Mondays" or whatever day it is. What this does not account for would be any days that had zero orders would not lower the average. That may or may not be desired depending on the application.
What you are asking doesn't make sense to me... AVG is an aggregate function and so is COUNT. What's wrong with the query above but just use: COUNT(*) AS avgorders?
Lets say you had 3 rows for day1, 2 rows for day2, 5 rows for day3, and 9 rows for day4... do you want to get back a single row result that tells you:
avgorders = (3 + 2 + 2 + 5 + 9) / 5 = 21 / 5 = 4.2
ordertotal = (3 + 2 + 2 + 5 + 9) = 21
I don't think you can get that in a single query, and you'd be better off doing the second round of aggregation in a server side language like PHP operating on the results of the first aggregation.

Categories