Running into a bit of a problem here. We have a system where we track our website hostings and I'm developing a frontend portal on this already pre-existing system.
In the database, the table looks something like:
id | company_id | renewal | domain_name
and an example couple entries in a MySQL database:
1 | 5 | June 2014 | www.example.com
2 | 5 | June 2015 | www.example.com
3 | 5 | June 2016 | www.example.com
4 | 5 | June 2017 | www.example.com
5 | 5 | June 2018 | www.example.com
6 | 5 | June 2014 | www.stackoverflow.com
7 | 5 | June 2015 | www.stackoverflow.com
8 | 5 | June 2016 | www.stackoverflow.com
9 | 5 | June 2017 | www.stackoverflow.com
10 | 5 | June 2018 | www.stackoverflow.com
I am wanting to SELECT * where the company_id = 5 - that's no problem. I then want to show all domains where the renewal is the highest - basically I want to return:
5 | 5 | June 2018 | www.example.com
10 | 5 | June 2018 | www.stackoverflow.com
Getting unique domains is simple, I've achieved that by GROUP BY(domain_name), but am clueless on sorting by renewal, especially because it isn't a simple int, rather a combination.
I would definitely recommend to convert this table to something with a real date in it, so you can sort it. For the time being, you could use MySQL's STR_TO_DATE function, which tries to parse the date according to a given format.
Here that would be:
SELECT domain_name, MAX(STR_TO_DATE(renewal_date, '%M %Y')) AS max_renewal_date
FROM table
WHERE company_id = 5
GROUP BY domain_name
Related
I am trying to select data, when inserting the data it has an auto insert of the date when submitting. So when data is inserted it inserts the current date.
However, in my table I have week beginnings, so I am trying to select the data inside of that week:
mysql> select * from week;
+---------+------+------------+
| week_id | week | date |
+---------+------+------------+
| 1 | 1 | 2014-12-29 |
| 2 | 2 | 2015-01-05 |
| 3 | 3 | 2015-01-12 |
| 4 | 4 | 2015-01-19 |
| 5 | 5 | 2015-01-26 |
| 6 | 6 | 2015-02-02 |
| 7 | 7 | 2015-02-09 |
| 8 | 8 | 2015-02-16 |
| 9 | 9 | 2015-02-23 |
| 10 | 10 | 2015-03-02 |
| 11 | 11 | 2015-03-09 |
| 12 | 12 | 2015-03-16 |
| 13 | 13 | 2015-03-23 |
| 14 | 14 | 2015-03-30 |
| 15 | 15 | 2015-04-06 |
| 16 | 16 | 2015-04-13 |
| 17 | 17 | 2015-04-20 |
e.g.
select * from table where date='2015-04-06';
However the data will not be selected and presented because the inserted date was 2015-04-10. The only way to retrieve that data is by doing this:
select * from table where date='2015-04-10'; < when the data was inserted
So my question is, is it possible to select that data from that week beginning?
So if I select data from 2015-04-06 it should show data from the range of 2015-04-06 to 2015-04-12, is that possible?
Hopefully I have explained correctly, been a bit tricky to explain let alone try to implement. I can add any more info if needed.
NOTE: I am trying to use this inside of PHP so where the date is I would just use a variable, just thought I would say.
As the week will always end 6 days from the beginning you can use the between operator and the date_add function like this:
(for your specific example):
select *
from table
where date between '2015-04-06' and date_add('2015-04-06', interval 6 day)
And using a php variable:
select *
from table
where date between '$name_of_dt_var' and date_add('$name_of_dt_var', interval 6 day)
You could also compare the week of the date the data was entered with the weeks in the week table using WEEK() function.
Assuming that week is the same value as week(), the:
select t.*
from table t
where week = week('2015-04-10');
Even if the numbers do not match, then presumably you have some base date (such as 2015-01-01 and simple arithmetic would accomplish something very similar).
I have found that the most robust way to do this sort of week processing is to truncate each date in the table (in your example 2015-04-10) to the preceding Monday at midnight. That way you can compute the week of each item by assigning it to the first day of that week.
This little formula returns the preceding Monday given any DATE or DATETIME value.
FROM_DAYS(TO_DAYS(datestamp) -MOD(TO_DAYS(datestamp) -2, 7))
For example,
set #datestamp := '2015-04-10'
SELECT FROM_DAYS(TO_DAYS(#datestamp) -MOD(TO_DAYS(#datestamp) -2, 7))
yields the value 2015-04-06.
So, if you have a table called sale you can add up sales by week like this:
SELECT SUM(amount) weekly_amount,
FROM_DAYS(TO_DAYS(datestamp) -MOD(TO_DAYS(datestamp) -2, 7)) week_beginning
FROM sale
GROUP BY FROM_DAYS(TO_DAYS(datestamp) -MOD(TO_DAYS(datestamp) -2, 7))
This is a very convenient way to handle things, because it's robust over end-of-year transitions. The WEEK() function doesn't work quite as well.
If your business rules say that your weeks begin on Sunday rather than Monday, use -1 rather than -2, as follows.
FROM_DAYS(TO_DAYS(datestamp) -MOD(TO_DAYS(datestamp) -1, 7))
We are trying to sort through people that have purchased items to filter out people that have averaged purchasing over a certain amount of items per year.
Person 1 has bought 1.6 items/year. We want to exclude everyone below a certain amount. How can we do this?
id | item | year
1 | 1 | 2002
1 | 1 | 2003
1 | 3 | 2004
1 | 2 | 2004
2 | 2 | 2004
2 | 2 | 2003
1 | 4 | 2004
We got it. We used the query below and did the math in PHP.
$query = "SELECT id, COUNT(DISTINCT year), COUNT(item) from purchases GROUP BY id"
I have a table called jobs with fields: id, status. And another table called jobs_history with fields: id, jobid, status, added_time.
Every time a job is edited through php, I insert the updated data into jobs_history table with jobid, user selected status, and added_time.
A job maybe edited many times so there could be many rows in jobs_history table for one job. And the status field may contains different status like, 1st status would be "Under review", 2nd could be "In progress", 3rd could be "E-mail sent", 4th "Completed".
Now, I need to count the total number of jobs at a specific datetime that had status "In progress" on that date. Here is some example data in jobs_history table:
id | jobid | status | added_time
--------------------------------------
1 | 10 | Under review | 2014-05-20 01:00:00
2 | 10 | In progress | 2014-05-21 02:30:00
3 | 10 | E-mail sent | 2014-05-23 10:00:00
4 | 10 | Completed | 2014-05-23 04:00:00
5 | 11 | Under review | 2014-05-19 05:00:00
6 | 11 | In progress | 2014-05-20 06:00:00
7 | 11 | E-mail sent | 2014-05-20 07:00:00
8 | 11 | Completed | 2014-05-22 08:00:00
9 | 12 | Under review | 2014-05-23 09:00:00
10 | 12 | In progress | 2014-05-24 02:00:00
11 | 13 | Under review | 2014-05-20 10:00:00
12 | 13 | In progress | 2014-05-20 12:00:00
I want to count total number of jobs that had status "In progress" on the 2014-05-21 06:00:00. The query should produce result 2, that is jobid 10 and 13, because those are the only jobs that had last status "In progress" on 2014-05-21 06:00:00.
I have about 400,000 data in the jobs_history table so the query should be written in the fastest way possible.
Thanks and I very much appreciate your help on this.
If your date format is different you can use date_format function. Check this link
http://sqlfiddle.com/#!2/4a6e8b/17
The system is as such. Tutors provide their availability (Monday - Sunday) and the time frame they are available on that day (0700 - 1400) (ie: 7am - 2pm).
I am trying to figure out the best way to store and search through this information to find available tutors. Searching only needs to be done on a daily system (ie: day of the week - mon, tues, wed, etc).
My planned infrastructure:
//Tutor Availability
---------------------------------------------------------------------------
tutorID | monday | tuesday | wednesday | thursday | friday |
---------------------------------------------------------------------------
27 | 0700-1200 | NULL | 1400-1800 | NULL | NULL |
---------------------------------------------------------------------------
35 | NULL | 1400-1600 | NULL | NULL | 1100-1900 |
//Scheduled tutor sessions
------------------------------------
tutorID | day | time |
------------------------------------
27 | monday | 0700-0900 |
------------------------------------
35 | friday | 1300-1500 |
Query: SELECT tutorid FROM tutoravailability WHERE 'monday'=... is available between 0900-1100 and is not in scheduled tutor session.
I have been searching forever about how I can search through (and store) these time intervals in MySQL. Is this the best way to store the time intervals of a 24 hours day? Will it even be possible to search between these intervals? Am I approaching this from the wrong way? Any insight is appreciated.
Updated Infrastructure
//Tutor Availability
-----------------------------------------------------
tutorID | day | start_time | end_time | PK |
-----------------------------------------------------
27 | mon | 0700 | 1200 | 1 |
-----------------------------------------------------
27 | fri | 1400 | 1800 | 2 |
-----------------------------------------------------
35 | tue | 1100 | 1600 | 3 |
//Scheduled tutor sessions
--------------------------------------------------------
tutorID | day | start_time | end_time | PK |
--------------------------------------------------------
27 | mon | 0800 | 1000 | 1 |
--------------------------------------------------------
27 | fri | 1600 | 1800 | 2 |
So with this system it will be much simpler to search for available times. However I am still at a loss as to how to compare the availability against the scheduled lessons to ensure no overlap.
SELECT tutorID
FROM tutoravailability WHERE day = 'fri'
AND start_time <= '1400'
AND end_time >= '1530'
Now I don't understand how I would compare this query against the Scheduled tutor sessions table to avoid duplicate bookings.
Final Update
To ensure their are no overlapping of the Scheduled Tutors sessions I will use the MySQL BETWEEN clause to search for the start and end time.
If you store the time interval using two columns it will be much easier for you to perform a search using sql query.
i.e. tutorID, day, startTime, endTime
You can use a bit flag to indicate the availability (24 bit) and scheduled time (24 bit). Then you can use 24 bit to represent the available hours and scheduled hours for each day.
In the Tutor Availability table, let's say '1' stands for Available in and '0' stands for unavailable. In the Scheduled table, '0' stands for Scheduled, '1' stands for Unscheduled.
So the available interval 0900-1100 can be stored as POW(2,9) | POW(2,10) | POW(2,11); the scheduled 1000-1200 can be stored as ^(POW(2,10) | POW(2,12))
Then the following query can give your the availability of on tutor - available on Monday between 09 am to 11 am:
SELECT ta.tutorid FROM tutoravailability ta, tutorscheduled ts
WHERE ta.tutorid = ts.tutorid AND ts.day = 'monday'
AND (ta.monday & ts.time & (POW(2,9) | POW(2,10) | POW(2,11))) = (POW(2,9) | POW(2,10) | POW(2,11))
Project: I am working on a project which is about some rooms and equipments using in the rooms. The software is about scheduling the equipments in the rooms. In other words, it is a reservation software that reserves selected equipments in separate rooms for needed dates and times ranges. I have many tables in MYsSQL database working with Php but I will mention the tables my question is about. The tables I will relate my questions are equipment table (Table A), schedule table (Table B) and equipments using in the related schedule (Table C).
Table A: equipment list table
eqid | eqName | available|
1 | book | 90 |
2 | pen | 82 |
3 | computer | 25 |
In table A; eqid represents unique id of an equipment, eqName represents name of an equipment, available represents total available equipments existing.
Table B: schedule table
scheduleid | startDate | endDate | startTime | endTime | office |
1 | 2012-08-27 | 2012-08-27 | 08:30:00 | 10:00:00 | room1 |
2 | 2012-08-27 | 2012-08-27 | 09:30:00 | 11:00:00 | room3 |
3 | 2012-08-28 | 2012-08-30 | 08:30:00 | 12:00:00 | room2 |
4 | 2012-08-29 | 2012-08-31 | 11:30:00 | 14:00:00 | room1 |
5 | 2012-08-28 | 2012-08-28 | 10:30:00 | 14:00:00 | room3 |
6 | 2012-08-27 | 2012-08-30 | 08:30:00 | 10:00:00 | room4 |
7 | 2012-08-27 | 2012-08-27 | 10:30:00 | 12:00:00 | room4 |
8 | 2012-08-27 | 2012-08-30 | 08:30:00 | 11:00:00 | room6 |
9 | 2012-08-27 | 2012-08-27 | 10:30:00 | 12:00:00 | room5 |
In table B; scheduleid represents unique id for a schedule, startDate and endDate are date range for a schedule, startTime and endTime time range for a schedule, office means that where the schedule will take place. Let me give an example here. Scheduleid 1 means there is a reservation on 27th of august 2012, Monday and it is from 08.30 to 10:00. As it start and end on same day this is just one day reservation in room1. However, Scheduleid 3 means there is a reservation starts on 28th of august 2012, Tuesday and goes on until 30th of august 2012, Thursday at 08:30-12:00... in other words, it lasts for 3 days and everyday from 08:30 to 12:00... So there is a reservation from Tuesday to Thursday at 08:30 to 12:00 in room2... I hope this is clear.
Table C: equipments using in the related schedule
Autoid | scheduleid | eqid | amountInSch|
1 | 1 | 1 | 2 |
2 | 1 | 2 | 3 |
3 | 1 | 3 | 1 |
4 | 2 | 1 | 1 |
5 | 2 | 2 | 1 |
6 | 2 | 3 | 2 |
7 | 3 | 2 | 1 |
8 | 3 | 3 | 3 |
9 | 4 | 2 | 1 |
10 | 4 | 3 | 1 |
11 | 5 | 1 | 1 |
12 | 6 | 1 | 1 |
13 | 6 | 3 | 2 |
14 | 6 | 2 | 4 |
15 | 7 | 1 | 5 |
16 | 7 | 2 | 6 |
17 | 8 | 2 | 1 |
18 | 9 | 1 | 8 |
19 | 9 | 2 | 5 |
20 | 9 | 3 | 6 |
In table C: Autoid represents unique automatic id generated by auto-increment, scheduleid comes from Table B, eqid comes from Table A, amountInSch represents how many (amount) equipment will use in the related schedule. I want to give an example here. Scheduleid 1 in Table C, there are 3 rows. This means that scheduleid 1 related in TAble B will use 2 books (eqid 1), 3 pens (eqid 2) and 1 computer (eqid 3) in room1 specified dates and times in table B . Another example is that scheduleid 3 in Table C is related 2 rows. It means that 1 pen (eqId 2) and 3 computers (eqId 3) will be using in room2 from 27th to 30th of august 2012 everyday from 08:30 to 12:00.
The above is the explanation and give some information about the project. The table rows are not permanent. When you make a reservation, there will be a new row in Table B and if it is selected an equipment, there will be new rows in table C...
The Question:
I want to calculate left amount of a specific equipment when I supply eqId, startDate, endDate, startTime and endTime...
An example:
eqId: 1 (book)
startDate: 2012-08-27
endDate: 2012-08-27
startTime: 08:30:00
endTime: 12:00:00
Result should be: 14 books used in schedule and 76 left available books
Because: if you look scheduleIds and related eqIds, you will only see 1, 2, 6, 7, 9 scheduleIds related to my query(dates and eqId). If you sum the all amount of related in Table C, you will get the wrong result. In other words, related amounts for eqId(1-book) and for 1, 2, 6, 7, 9 scheduleIds are 2, 1, 1, 5, 8 respectively. So if you sum them you will get 17 which is wrong. Because, 1 and 9 schedule don't intersect each other in terms of start and end Times, and 6 and 7 don't intersect each other either. as a result of them 2 stays lonely and can be count separately. We must consider 1 and 9 as summed 8 because 8 is bigger than 2. it is same for 6 and 7, considered as 5 because of 5 is bigger than 1...
So folks! I am not sure how I can sum/ this in programming algorithm. Is there a way to do in SQL or do I have to use PHP and Mysql together? and How?
Cheers!
SQLFiddle Records
I started with the following SQL to gather all date ranges that intersect with the given range:
SELECT MAX(available) - IFNULL(SUM(amountInSch), 0)
FROM Table1
LEFT JOIN Table3 USING (eqid)
LEFT JOIN Table2 USING (scheduleid)
WHERE DATE(startDate) <= '2012-08-27' AND DATE(endDate) >= '2012-08-27'
AND endTime > '08:30' AND startTime < '12:00'
AND eqid = 1
Fiddle
This is only the first part. Next up you have to work out the possible overlaps; this wouldn't be practical to do with SQL, so I would suggest to do this in PHP.
The generic algorithm I would pick is unfortunately O(n**2), it goes like this:
create a timeline (demarcated by each day) with time as the horizontal axis
iterate over every date/time range and mark the time of its left and right edge to create time segments of every possible permutation.
using the segments, you sum vertically for overlaps and you take the daily maximum across.
Hope that helps.