MySQL - Using a date range vs functions - mysql

I needed to know how many users registered during June and July, this is the first query I wrote:
select count(*) from users where created_at>="2013-06-01" and created_at<="2013-07-31"
Result: 15,982
select count(*) from users where year(created_at)=2013 and month(created_at) in (6,7)
Result: 16,278
Why do they return a different result? Could someone explain? Or am I missing something?
Thanks.

Both query should be equivalent, except that the first one is able to make use of an index and it should be faster, and except the case in which created_at is not a DATE but is a TIMESTAMP.
If created_at is a timestamp, you should write your first query this way:
select count(*) from users
where created_at>='2013-06-01' and created_at<'2013-08-01'
otherwise your first query will exclude all records created on 31th of July, after midnight, eg. 2013-07-31 00:00:00 will be included while 2013-07-31 09:15:43 will be not.

The reason is that your date values do not include the last day: The date constants are converted to a timestamp at midnight. You are querying between these values:
2013-06-01 00:00:00
2013-07-31 00:00:00
So only the first second of the last day is included.
Try this:
select count(*)
from users
where created_at>="2013-06-01"
and created_at<="2013-07-31 23:59:59"
Or more simply make less than the next day:
select count(*)
from users
where created_at>="2013-06-01"
and created_at<"2013-08-01" -- < 1st day of next month

Related

MYSQL How to get list of records with time period included in specified year and month?

I have a table that links an employee to a project, the columns are:
BIGINT ID;
BIGINT FK_PROJECT;
BIGINT FK_EMPLOYEE;
DATE FROM;
DATE TO;
from and to are the first and last day during which the employee will be assigned to the project,
now what I would like to do is getting records by using the id of the employee, the year and month, currently I have a whole date to give to the query but I can extract month and year if necessary. I need a query that by using these infos it fetches the records in which the year and month provided are included in the time period from-to, like if I have employee 3 and march 2022 I get all the projects said employee was assigned to in march 2022.
A project can last more than a year.
An employee could be assigned from 23/05/2022 to 29/08/2022.
I already tried select where fk_employee = 3 and 2022-03-01 between from and to but it clearly wouldn't work if from and to were in random days of the month like 13 and 23
Can you guys help me? I'm not good at all in sql
You can use EXTRACT function
Try:
SELECT ID,
FK_PROJECT,
FK_Employee
FROM tablename
WHERE EXTRACT(YEAR_MONTH FROM 'your_date') BETWEEN EXTRACT(YEAR_MONTH FROM `from`) and EXTRACT(YEAR_MONTH FROM `to`)
Fiddle
SELECT ID,
FK_PROJECT,
FK_Employee
FROM tablename
WHERE DATE > '2020-01-01'
AND DATE < '2022-01-01';
Not that if this does not give you the results you are expecting, the most likely reason is that the DATE field is not defined as a DATE OR DATETIME column in MySql. If this is the case, you can change the column type, or if that is not an option, you can use str_to_date to treat that column as a date column for this query.

How can I handle NULL values while doing datetime comparisons?

My goal is to work out how many accounts there have been on my website at specific times. I allow accounts to be cancelled at anytime, but if they were cancelled after the month I'm looking at then I would still like them to appear as they were active at that snapshot in time.
My accounts table which looks like:
--------------------------------------------------
id | int
signUpDate | varchar
cancellationTriggeredDate | datetime (NULLABLE)
--------------------------------------------------
I wrote a select statement to accomplish this goal which looks like:
SELECT
COUNT(*) AS January_2020
FROM
Accounts
WHERE
STR_TO_DATE(signUpDate, '%d/%m/%Y') <= STR_TO_DATE('31/01/2020', '%d/%m/%Y')
AND cancellationTriggeredDate <= '2020-01-31 00:00:00'
The expected results would be 3, this is how many accounts I had in January and have not been cancelled after January. The actual results is 0. I believe this is because not all of my accounts have a cancellation date set, but I'm not sure how to handle this.
To make it easier to get help, I have created a SQL Fiddle including sample data and schema.
http://sqlfiddle.com/#!9/64f3e3
Your date comparison needs to be correct for the cancellation date.
Then you can use OR to handle NULL:
SELECT COUNT(*) AS January_2020
FROM Accounts
WHERE STR_TO_DATE(signUpDate, '%d/%m/%Y') <= '2020-01-31' and
(cancellationTriggeredDate > '2020-01-31' OR
cancellationTriggeredDate IS NULL
)
Here is the db<>fiddle. Note that the above gives the users who are active at eactly 2020-01-31 00:00:00 -- that is, at the beginning of the day. There are different things that you might mean:
Customers active at exactly 2020-01-31 00:00:00
Customers active at exactly 2020-02-01 00:00:00
Customers active for the entire day of 2020-01-31
Customers active for the entire month of 2020-01
Customers active at any time during the month of 2020-01
All of these use basically the same logic, just by tweaking the specific comparisons.
Alternate solution - you can use CASE WHEN and initialize cancellationTriggeredDate with a hypothetically higher date (i.e. end of this century) before taking this field for comparison in WHERE predicate.
SELECT
COUNT(*) AS January_2020
FROM
Accounts
WHERE
STR_TO_DATE(signUpDate, '%d/%m/%Y') <= STR_TO_DATE('31/01/2020', '%d/%m/%Y')
AND CASE WHEN cancellationTriggeredDate IS NULL THEN '2099-12-31' ELSE cancellationTriggeredDate END > '2020-01-31 00:00:00'

Empty result when using mySQL WEEK() to find dates in current week

We are using the following statement to select dates of birth which occur in the current week:
SELECT * FROM tbl_user WHERE WEEK(dob,1) = WEEK(CURDATE(),1) ORDER BY id DESC
Our 'dob' column has the type DATE and contains 1 record where dob is 1972-07-09. However, when we run our query (today is 2014-07-07) we get an empty result.
Any ideas why?? Does WEEK() only work on columns with type DATETIME?
Thanks in advance for an help!
SELECT WEEK('1972-07-09',1); //result= 27
SELECT WEEK('2014-07-07',1); //result=28
For Example :
SELECT WEEK('2014-01-18',1); //result=3
Your where condition does not satisfy that why It's return false and Empty Result.
Check Manual here
2014-07-07 is week 28 and 1972-07-09 is week 27. 27 is not equals 28 so you get no result.
You can check this with that query:
select week('2014-07-07',1),week('1972-07-09',1) from tbl_user ;
SELECT WEEK('1972-07-09',1);
result: 27
SELECT WEEK('2014-07-07',1);
result: 28
In this case your condition WHERE WEEK(dob,1) = WEEK(CURDATE(),1) is False. That's why you get an empty result.
Your definition of week is not the same as MySQLs. For a better and more efficient result you should instead decide on the min and max range you wish to find and select that which allows you to define when your week starts and ends.
SELECT *
FROM tbl_user
-- min range == 00:00:00 on the first day of week
WHERE dob >= ADDDATE(CURRENT_DATE, INTERVAL 1-DAYOFWEEK(CURRENT_DATE) DAY)
-- max range == 00:00:00 on the first day of next week
AND dob < ADDDATE(CURRENT_DATE, INTERVAL 8-DAYOFWEEK(CURRENT_DATE) DAY)
ORDER BY id DESC
The start and end date can be adjusted as needed, but because you aren't applying a function to the dob field you will avoid a table scan.

Query Time range between Dates using DATETIME mysql

I have a database table that has fields as such :
TIME(Datetime) Update_ID
2013-11-25 05:00:14 XC3
2013-11-25 06:00:13 XC4
2013-11-25 06:00:19 XC5
2013-12-25 23:00:14 XC6
2013-12-25 24:00:00 XC7
So assuming i want to find a trend on the updates to know which period of the day has the a particular number of updates, what i initially think of is doing something like this :
SELECT COUNT(TIME) FROM table WHERE TIME between '06:00:00' and '12:00:00'
But this doesn't work because i think since the date is not added with the time, a default value for date is added(some date around 1970). If, i add the beginning and enddate in my query, i am afraid it won't give me the results i need.
Use
WHERE HOUR(TIME)...GROUP BY DAY(TIME)
in case you have more than 1 day
You are correct, the problem is that when you do not specify the date, a default one is added.
You can use the EXTRACT function to extract the time from a date, like this:
SELECT COUNT(*)
FROM mytable
WHERE EXTRACT(HOUR_SECOND from TIME) between 60000 and 120000
Note that the time portion in the condition is specified in a different format - i.e. as numbers, without colons and quotes.
Demo on SqlFiddle.

datetime searching using sub-sections of the YYYY-MM-DD HH:MM string

[MySQL/PHP] My table has a date column of datetime format. All records are of the YYYY-MM-DD HH:MM:SS variety.
MySQL queries like SELECT record FROM table WHERE date > '1941' AND date < '1945' work nicely.
MySQL queries like SELECT record FROM table WHERE date > '1941-03-01' AND date < '1945-01-30' also work nicely.
But what about if I wanted all records that were filed in March, regardless of year? Or all records filed on the 17th, regardless of month/year?
``SELECT record FROM table WHERE date = '03'` clearly doesn't work.
I know I could snag it with a LIKE '%-03-%' parameter, but that doesn't leave room for me to search for range, like all records from March to May.
Help? :-)
Try WHERE MONTH(DATE(`date`)) BETWEEN '03' AND '05'
The DATE() part is to extract the date from the timestamp to be used with MONTH().
You can use MySQL date functions:
SELECT record FROM table WHERE MONTH(date) = 3
SELECT record FROM table WHERE DAY(date) = 17
http://dev.mysql.com/doc/refman/5.1/en/date-and-time-functions.html
If you look at http://dev.mysql.com/doc/refman/5.1/en/date-and-time-functions.html, you will find many useful functions for your purpose.
... WHERE MONTH(date) = 3, e.g. =)