Let's assume I manage medical patient stays information system.
I want to get the patient count per day with the following minimal structure :
stay table has begin and end datetime columns
PHP gives me $first_day and $last_day limits
The following snippet is NOT what I want, since it only counts entries per day, and not present stays per day:
SELECT
DATE_FORMAT(`stay`.`begin`, '%Y-%m-%d') AS `date`,
COUNT(`stay`.`stay_id`) AS `total`
FROM `stay`
WHERE `stay`.`begin` <= '$first_day'
AND `stay`.`end` >= '$last_day'
GROUP BY `date`
ORDER BY `date`
Last but not least, I'm looking for a full SQL query.
It goes without saying that making one SQL query for each day would be totally trivial.
Use of temporary (dates ?) table is clearly an option.
As you mentioned using a temporary table of all dates in the range you want is one way to handle this. If you created a table of date called foo with all dates between $first_day and $last_day inclusive (see here).
Then you can write your query like:
SELECT f.date, count(s.stay_id)
FROM foo f
JOIN stay s ON s.begin <= f.date AND s.end >= date
GROUP BY f.date
ORDER BY f.date
A quick Google around leads me to this page: What is the most straightforward way to pad empty dates in sql results (on either mysql or perl end)?
What I would suggest is that you either follow the advice in that question, or construct your own loop in PHP.
Related
I have a PHP application that records the sessions of various devices connected to a server. The database has a table session, with the columns device_id, start_date, end_date. To know the number of devices connected on a given date, I can use the request :
SELECT COUNT(DISTINCT device_id)
FROM session
WHERE :date >= start_date AND (:date <= end_date OR end_date IS NULL)
where :date is passed as a parameter to the prepared statement.
This works fine, but if I want to know the number of devices for every days of the year, that makes 365 queries to run, and I'm afraid things could get very slow. It doesn't feel right to be iterating on the date in PHP, it seems to me that there should be a more optimal way to do this, with a single query to the database.
Is it possible do this with a single query?
Would it actually be faster than to iterate on the date in PHP an running multiple queries?
EDIT to answer the comments :
I do want the number for each separate day (to draw a graph for example), not just the sum
the datatype is DATE
If I understand correctly then you first need a table of dates, something like:
create table dates(dt date);
insert into dates(dt) values
('2001-01-01'),
('2001-01-02'),
...
('2100-12-31')
And use a query like so:
select dates.dt, count(session.device_id)
from dates
join session on start_date <= dates.dt and (dates.dt <= end_date or end_date is null)
-- change to left join to include zero counts
where dates.dt >= :date1 and dates.dt <= :date2
group by dates.dt
PS: since you mentioned charts I might add that it is possible to avoid the table of dates. However, the result will only contain dates on which the count of devices changed. Chart APIs usually accept this kind of data but still create data points for all dates in between.
I am working on a school project where I have to make a todo web app. now i have a little problem. I need to get the records that are running out of time (think 20% of the whole task left). now i'm looking for a solution in php or a sql statement with which i can retrieve only those records.
I tried many statements but i cant get one to work.
SELECT * FROM tasks
WHERE user_id='$user_id'
AND '$currentDate' BETWEEN start_date AND end_date
The above one is working with the date but not with time.
So now I need to have a statement or function that only retrieves the tasks that are almost finished. I've added a screenshot of the database and the application to clarify it a bit.
i hope someone could help me. (this is my first time using stackoverflow so sorry if i do something wrong)
First, you should not be munging your query with constants, date or otherwise. So, use now().
Second, combine the date/time into a single column
Third, you seem to want and:
WHERE user_id = ? AND
NOW() >= start_datetime AND
NOW() < end_datetime
If you want to store the date/time in separate columns, then you can combine them:
WHERE user_id = ? AND
NOW() >= ADDTIME(CAST(start_date as DATETIME), start_time) AND
NOW() < ADDTIME(CAST(end_date as DATETIME), end_time)
I have a PHP scirpt that is always querying all the data from a database table and it's getting pretty slow. I really just need the data of a specific month and year.
Is there a simple way to get only those entries? For example, everything from February 2013?
The column that stores the dates in my table is of type datetime, if that applies to the solution.
You can add that condition in the WHERE clause of your select statement. I would recommend using BETWEEN operand for two dates:
SELECT myColumns
FROM myTable
WHERE dateColumn BETWEEN '2013-02-01' AND '2013-02-28';
If you mean to say you want everything beginning with February 2013, you can do so using the greater than or equal to operator:
SELECT myColumns
FROM myTable
WHERE dateColumn >= '2013-02-01';
EDIT
While the above are my preferred methods, I would like to add for completeness that MySQL also offers functions for grabbing specific parts of a date. If you wanted to create a paramaterized query where you could pass in the month and year as integers (instead of a start and end date) you could adjust your query like this:
SELECT myColumns
FROM myTable
WHERE MONTH(dateColumn) = 2 AND YEAR(dateColumn) = 2013;
Here is a whole bunch of helpful date and time functions.
You should index the datetime field for added efficiency and then use Between syntax in your sql. This will allow the mysql engine to remove all records that you are not interested in from the returned data set.
I have a table called schedules which contains columns day, month, year, etc. What I need is to select records between the $datefrom and $dateto. Here is my code that does not work :(
SELECT * FROM schedules WHERE CONCAT(year, month, day) BETWEEN $datefrom AND $dateto
Im not sure if this is correct. Please help.
Like showdev already said in a comment, you have to cast the string that is returned from CONCAT() function to date. But consider, that no index can be used on this.
I'd suggest you create an additional column in your table with the full date. I don't know if you separated the date into 3 columns out of performance reasons, but have a try, if only one column is enough for you. Usually it's fast enough (when indexed).
If you don't want to do that and want to use indexes (if they exist at all on those 3 columns) you would have to write the query like this:
SELECT * FROM schedules WHERE
`year` BETWEEN YEAR($datefrom) AND YEAR($dateto)
AND `month` BETWEEN MONTH($datefrom) AND MONTH($dateto)
AND `day` BETWEEN DAY($datefrom) AND DAY($dateto)
I have a database that contains three different columns: domain, date, length (in that order). What I'm trying to do is count the occurrence of every unique date in the database without knowing what the end date is in the database. The start date is always todays date.
So far I've only been able to count the occurences of a specific date, which requires me to put in an exact date.
What I want the PHP script to do is to start with todays date and output the number of times the date is mentioned (or the number of rows with that date) and then continue until it reaches a date that doesn't have a value (you could call this the end date).
I'm surprised and frustrated that I haven't been able to find the solution yet. It seems like a very easy thing to do.
I'd be super happy for any hints, tips or solutions.
Use a combination of a GROUP and WHERE clause.
SELECT COUNT(*) AS `occurrences`, `date` FROM `table` WHERE `date` >= CURDATE() GROUP BY `date`
Use group by and order by
SELECT dateCol, Count(*) FROM myTable
WHERE dateCol >= date(now())
GROUP BY dateCol
ORDER BY dateCol ASC
Edit: SQLFiddle with your example: http://www.sqlfiddle.com/#!2/5e86b/2