I am sure this is a common task although all of the examples I have looked at dont help me solve this issue.
I have 2 tables:
events
schedules with foreign key to events. With schedule_datetime_from and schedule_datetime_until
Q. When selecting all of the events, how would I also fetch/join the first closest schedule based on todays date? E.g only return the most relevant schedule.
NOTE: There maybe more than one schedule for each event. The schedule may also be in the past.
E.g e.schedule_datetime_from >= NOW() OR schedule_datetime_until > NOW() would return only the future schedules, but how do I also return schedules in the past. Or do I need to use a ORDER BY + LIMIT 1 to achieve this?
select e.*, s.*
from
events e
inner join
schedules s on e.id = s.event_id
order by
abs(unix_timestamp(schedule_datetime_from) - unix_timestamp(now())))
limit 1
This has worked for me:
SELECT * FROM table
WHERE DATE(date_column)
BETWEEN DATE(CURDATE()) AND DATE(CURDATE()+7);
This will give you a weeks heads up!
Well if you want to select a group of events between dates you can use
SELECT * FROM events WHERE date BETWEEN 'mm-dd-yyyy' AND 'mm-dd-yyyy'
If you want to select the most recent date you can add
ORDER BY date DESC LIMIT 1
Related
In short: MySQL - I need to bring company that have been inactive for a while (or 365 days for the fiddle example).
How I check this? each company have at least a contact, who is related to an event, and each event have (many) subevents, in this last table I have the last date of activity, the days that considers that one company is on inactivity is decided for the user, I don't have problem to do this calculation
sql.Append("where DATEDIFF(CURDATE(),DATE(lastdate)) > " +days.ToString()+ "
The problem is, that this check ALL the subevents, so this not only check the last date, but every date... and this means, bad output.
I was thinking on subqueries to get or the max date on the subevent of a contact, or the max date of the subevent of a event.
Then with a friend we get close with sort of this, but the query is infinite.
select * from subevent se
where DATEDIFF(CURDATE(),DATE(
(select se2.dates from subevent se2
where se2.dates in
(select max(se3.dates)
from subevent se3
where se.idev = se3.idev)
group by se2.dates)));
I'm stuck and I would appreciate the help...
Tried group by, subquery and MAX (obviously max is necessary, but don't how where to apply...)
https://www.db-fiddle.com/f/wgSQGn7Z26tHnwm6nAaNSA/8
(On the Fiddle link, should only bring the companyname2 and companyname4)
You can use aggregation to get the last subevent date for each company. Then filter using a having clause:
select c.idcomp
from contact c join
events e
on e.idcont = c.idcont join
subevent se
on se.idev = e.idev
group by c.idcomp
having max(se.date) < current_date - interval 365 day;
Here is a db-fiddle.
I have 2 tables, one with hostels (effectively a single-room hotel with lots of beds), and the other with bookings.
Hostel table: unique ID, total_spaces
Bookings table: start_date, end_date, num_guests, hostel_ID
I need a (My)SQL query to generate a list of all hostels that have at least num_guests free spaces between start_date and end_date.
Logical breakdown of what I'm trying to achieve:
For each hostel:
Get all bookings that overlap start_date and end_date
For each day between start_date and end_date, sum the total bookings for that day (taking into account num_guests for each booking) and compare with total_spaces, ensuring that there are at least num_guests spaces free on that day (if there aren't on any day then that hostel can be discounted from the results list)
Any suggestions on a query that would do this please? (I can modify the tables if necessary)
I built an example for you here, with more comments, which you can test out:
http://sqlfiddle.com/#!9/10219/9
What's probably tricky for you is to join ranges of overlapping dates. The way I would approach this problem is with a DATES table. It's kind of like a tally table, but for dates. If you join to the DATES table, you basically break down all the booking ranges into bookings for individual dates, and then you can filter and sum them all back up to the particular date range you care about. Helpful code for populating a DATES table can be found here: Get a list of dates between two dates and that's what I used in my example.
Other than that, the query basically follows the logical steps you've already outlined.
Ok, if you are using mysql 8.0.2 and above, then you can use window functions. In such case you can use the solution bellow. This solution does not need to compute the number of quests for each day in the query interval, but only focuses on days when there is some change in the number of hostel guests. Therefore, there is no helping table with dates.
with query as
(
select * from bookings where end_date > '2017-01-02' and start_date < '2017-01-05'
)
select hostel.*, bookingsSum.intervalMax
from hostel
join
(
select tmax.id, max(tmax.intervalCount) intervalMax
from
(
select hostel.id, t.dat, sum(coalesce(sum(t.gn),0)) over (partition by t.id order by t.dat) intervalCount
from hostel
left join
(
select id, start_date dat, guest_num as gn from query
union all
select id, end_date dat, -1 * guest_num as gn from query
) t on hostel.id = t.id
group by hostel.id, t.dat
) tmax
group by tmax.id
) bookingsSum on hostel.id = bookingsSum.id and hostel.total_spaces >= bookingsSum.intervalMax + <num_of_people_you_want_accomodate>
demo
It uses a simple trick, where each start_date represents +guest_num to the overall number of quests and each 'end_date' represents -guest_num to the overall number of quests. We than do the necessary sumarizations in order to find peak number of quests (intervalMax) in the query interval.
You change '2017-01-05' in my query to '2017-01-06' (then only two hostels are in the result) and if you use '2017-01-07' then just hostel id 3 is in the result, since it does not have any bookings yet.
I'm trying to find the cumulative sum of sessions of a link for its first 3 days. I tried this but it doesn't seem to take the date clause into account:
select
date,
link,
sum(sessions) as sessions
from ga
where date <= date+interval 3 day
group by link
But if I manually enter a date, it seems to work. Why is it not seeing date+interval 3 day as a proper date...?
Any help would be greatly appreciated! :)
Date is a column, not a value, you need to provide a specific date entry. Also "between" is a better keyword to use in this situation.
You need to also add date column in GROUP BY clause. Also, avoid using column name as date. It will create confusion.
Try below query :
select date_column,
link,
sum(sessions) as sessions
from ga
where date_column BETWEEN CURDATE()-3 AND CURDATE()
group by link, date_column
I have a table called 'events'.
It contains eventID (INT), eventDateTime(DATETIME), and eventMessage(VARCHAR).
I want to be able group the rows by eventDateTime where there is another row with eventDateTime within 1 hour each side. This should propogate forever (for example a group should be able go on for years, as long as there is never a gap longer than an hour between a linking chain of eventDateTime values within that time period. Ideally I want to end up selecting MIN(eventID) for each group, and both the MIN and MAX of eventDateTime which will give me the time span in which the group runs.
I assume I need some kind of iterating loop to do this? Where would I start?
Let's start from subqueries we need
SET #row_number1 = 0;
SET #row_number2 = 0;
The query returns us the events table ordered with row numbers (rn)
SELECT
(#row_number1:=#row_number1 + 1) AS rn, eventID, eventDateTime
FROM
events
ORDER BY eventDateTime
Let's mar them as SUB1 and SUB2
Then let's join them
select *
from SUB1 join SUB2 on sub1.rn=sub2.rn+1
So we have in one row 2 eventDateTime of current and next row and can calculate time difference
TIMESTAMPDIFF(HOUR, SUB1.eventDateTime, SUB2.eventDateTime) as hoursDiff
Then we can add HAVING hourDiff>1 to have rule breaking intervals. For such records SUB1.eventDateTime is the end of previous group but SUB2.eventDateTime is the beginning of next group.
So our query will return us
SUB1.eventID as previousGroupEndEventId,
SUB1.eventDateTime as previousGroupEndeventDateTime,
SUB2.eventID as currentGroupStartEventId,
SUB2.eventDateTime as currentGroupStarteventDateTime,
TIMESTAMPDIFF(HOUR, SUB1.eventDateTime, SUB2.eventDateTime) as breakInterval
And you can use the query results to get all your info
For complex problems requiring some form of looping, some databases allow recursive queries, but apparently not mysql.
Fortunately, in your case I don't think it is necessary. You can instead look for any rows which don't have another row in the preceeding hour thus:
select *
from events as A
where not exists (
select 1
from events as B
where B.eventDateTime < A.eventDateTime
and B.eventDateTime > DATE_ADD(A.eventDateTime, INTERVAL -1 HOUR)
)
Example kept simple. Fix up the details to meet your requirements.
Working example is here: http://sqlfiddle.com/#!9/c3b73c/1
I know there have been a few posts related to this, but my case is a little bit different and I wanted to get some help on this.
I need to pull some data out of the database that is a cumulative count of interactions by day. currently this is what i have
SELECT
e.Date AS e_date,
count(e.ID) AS num_interactions
FROM example AS e
JOIN example e1 ON e1.Date <= e.Date
GROUP BY e.Date;
The output of this is close to what I want but not exactly what I need.
The problem I'm having is the dates are stored with the hour minute and second that the interaction happened, so the group by is not grouping days together.
This is what the output looks like.
On 12-23 theres 5 interactions but its not grouped because the time stamp is different. So I need to find a way to ignore the timestamp and just look at the day.
If I try GROUP BY DAY(e.Date) it groups the data by the day only (i.e everything that happened on the 1st of any month is grouped into one row) and the output is not what I want at all.
GROUP BY DAY(e.Date), MONTH(e.Date) is splitting it up by month and the day of the month, but again the count is off.
I'm not a MySQL expert at all so I'm puzzled on what i'm missing
New Answer
At first, I didn't understand you were trying to do a running total. Here is how that would look:
SET #runningTotal = 0;
SELECT
e_date,
num_interactions,
#runningTotal := #runningTotal + totals.num_interactions AS runningTotal
FROM
(SELECT
DATE(eDate) AS e_date,
COUNT(*) AS num_interactions
FROM example AS e
GROUP BY DATE(e.Date)) totals
ORDER BY e_date;
Original Answer
You could be getting duplicates because of your join. Maybe e1 has more than one match for some rows which is inflating your count. Either that or the comparison in your join is also comparing the seconds, which is not what you expect.
Anyhow, instead of chopping the datetime field into days and months, just strip the time from it. Here is how you do that.
SELECT
DATE(e.Date) AS e_date,
count(e.ID) AS num_interactions
FROM example AS e
JOIN example e1 ON DATE(e1.Date) <= DATE(e.Date)
GROUP BY DATE(e.Date);
I figured out what I needed to do last night... but since I'm new to this I couldn't post it then... what I did that worked was this:
SELECT
DATE(e.Date) AS e_date,
count(e.ID) AS num_daily_interactions,
(
SELECT
COUNT(id)
FROM example
WHERE DATE(Date) <= e_date
) as total_interactions_per_day
FROM example AS e
GROUP BY e_date;
Would that be less efficient than your query? I may just do the calculation in python after pulling out the count per day if its more efficient, because this will be on the scale of thousands to hundred of thousands of rows returned.