I want to calculate via MariaDB query a date of recurring subscription based on this information:
For Example:
start_date:01.01.2019
period_of_validity: 4 (Months)
regular_finish_date:01.05.2019, 01.09.2019, 01.01.2020, "01.05.2020"
finished_by_user_at:
membership_will_finished_at:
Case1:
When finished_by_user_at is NULL (It means, the user doesnt cancel his subscription) the regular_finish_date should be update automatically after the interval was reached. As we can see in the example above, the date it should show now is 01.05.2020.
Wo can help me with this Task? No php, java or something else is possible. Only MYSQL query. Thanks
SELECT
subscription.SubscriptionID,
subscription.tb_usersID,
subscription.subscription_planID,
subscription.payment_typeID,
subscription.start_date,
DATE_ADD(subscription.start_date, INTERVAL subscription_plan.period_of_validity MONTH) AS date_joker,
DATE_ADD(CURDATE(), INTERVAL subscription_plan.period_of_validity MONTH) AS regular_finish_date,
subscription.finished_by_user_at,
(CASE
WHEN subscription.finished_by_user_at IS NOT NULL THEN
(CASE
WHEN subscription.regular_finish_date >= NOW() - INTERVAL subscription_plan.period_of_validity MONTH THEN
DATE_ADD(subscription.regular_finish_date, INTERVAL subscription_plan.period_of_validity MONTH)
END)
END) AS membership_will_finished_at,
subscription.is_active,
subscription.status,
subscription.notizen,
subscription.file1,
subscription.file2,
subscription.file3
FROM subscription
JOIN subscription_plan ON subscription.subscription_planID = subscription_plan.subscription_planID
Do not store dates in this format: 01.01.2019. Instead, use 2019-01-01. And store them with datatype DATE, not VARCHAR. Then you can use date expressions.
Suggested indexes:
subscription_plan: (subscription_planID, period_of_validity)
subscription: (subscription_planID)
Related
I have a table which has a column called created DATETIME, When adding entries It works fine, but when It gets to Date Interval, It keeps on duplicating new entries. I'm trying to get Today's and Yesterday's entries. Today's works fine, but for Yesterday's, It also puts on Today's contents in query results which Is not what I want.
SELECT * FROM tab WHERE created > DATE_SUB(NOW(), INTERVAL $num DAY) ORDER BY created DESC LIMIT 9;
$num Is 1 for Today's entries, and It's 2 for Yesterday's. So basically an entry which Is created today, Is getting duplicated on Yesterday's query results.
You are getting the results you requested from the database. Namely any record that is greater than today minus however many days you put in.
The reason you get 0 records when you try #KenWhite's suggested of changing your > to = is because your field is DATETIME, so subtracting exactly 24 hours from NOW() yields the same exact time yesterday and you probably don't have a record that was written precisely at this time yesterday. Right?
What you'll have to do is test for records between two dates to get you want. Instead of NOW(), switch to CURDATE(), this way you can be assured you'll get every record for the datetime range you are looking for.
SELECT *
FROM tab
WHERE
created BETWEEN DATE_SUB(CURDATE(), INTERVAL $num DAY) AND DATE_SUB(CURDATE(), INTERVAL $num - 1 DAY)
ORDER BY created DESC LIMIT 9;
You can check out a SQLFiddle of this here: http://sqlfiddle.com/#!2/19d9b/12
With datetime/timestamp values, similar to floats, always use ranges with closed beginnings and open endings. So use '>=' and '<'.
For example to use the data of a single day:
SELECT ... FROM tab
WHERE created >= CURDATE() - INTERVAL #num:=? DAY
AND created < CURDATE() - INTERVAL #num DAY + INTERVAL 1 DAY
ORDER BY created DESC
LIMIT 9
;
With MySQL, generally prefer the timestamp type over the datetime type, as datetime doesn't carry timezone information.
Alternatives:
created_at timestamp NULL DEFAULT NULL COMMENT 'set by application',
created_at timestamp NOT NULL DEFAULT '1970-01-01 23:00:00' COMMENT 'set by application',
dbms_row_created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'set by DBMS',
I am facing an odd issue. The global timezone setting in the mySQL is in UTC. There are multiple tables (sub databases) within a single instance of mySQL (I am using database.NET as the manager); so I can't change the global timezone.
The following is my query. All I need is to display the times in EST. I have seen a few solutions with ##sessionTimeZone but they didn't work. Furthermore, I am running into the issue of data being collected till 9PM EST, but in UTC that's 1AM on the next day.
My main confusion is that the data is already stored in the table in UTC; however, I would like to see those datetime fields displayed in EST.
cartId is a numerical field
createDate is a datetime field
I am just using http://fishcodelib.com/database.htm and connecting to the mySQL database.
SELECT DATE(createDate)
,DATE_FORMAT(createDate, '%l%p') as HourOfDay
,count(cartId) as numCarts_ALL
FROM carts
WHERE createDate >= '2014-09-24'
AND createDate < '2014-10-01'
AND HOUR(createDate) >= 10 AND HOUR(createDate) <21
GROUP by DATE(createDate),HOUR(createDate)
;
I will really appreciate any help.
Thanks again
DATETIME data types are not affected by either the global or connection-local timezone setting. That only works for TIMESTAMP data types. That explains why your attempts to muck around with ##session.TimeZone don't have any effect. NOW() and CURDATE() are affected, though.
You say your DATETIME data is stored in UTC. That's excellent. Life is much easier when you store your data that way.
Before you use the advice I'm about to give you, please make sure your MySQL server has its timezone tables loaded correctly. Do this command and make sure you don't get a NULL result.
SELECT CONVERT_TZ(NOW(), 'America/New_York', 'UTC')
If this doesn't work -- if you get a NULL or an error -- you need to get your server people to load the time zone tables. They should do this. They know how. (If they don't, you should get a new service provider.)
We need to use the timezone named 'America/New_York' because presumably you want to switch automatically between EDT and EST on the appropriate dates each year.
Now, to retrieve a correctly converted UTC DATETIME value from a table, you do this:
SELECT CONVERT_TZ(createDate, 'UTC', 'America/New_York') AS createDate
FROM yourTable
This is cool because you can make the timezone setting a user preference if you have users in various time zones.
To store a local time value as UTC just do it in reverse. For example.
INSERT INTO yourTable (createDate) VALUES (CONVERT_TZ(?, 'America/New_York', 'UTC'))
Now do
SELECT NOW()
and look to see whether NOW() is in local time or in UTC. If it is in UTC, then you should start your session by doing SET TIME_ZONE='America/New_York' . This will get your timezone set right so NOW() and CURDATE() do what you want.
Then, to fetch yesterday's (local time) rows from your table do this:
WHERE createDate >= CONVERT_TZ(CURDATE(),'America/New_York','UTC') - INTERVAL 1 DAY
AND createDate < CONVERT_TZ(CURDATE(),'America/New_York','UTC')
This will convert midnight local time to UTC and fetch the range of items.
To get all the data from 4pm today until 2am tomorrow, you could do this:
4pm today (localtime) is CURDATE() + INTERVAL 16 HOUR . 2am tomorrow is CURDATE() + INTERVAL 26 HOUR or you could write it CURDATE() + INTERVAL 1 DAY + INTERVAL 2 HOUR
So fetching that range would need this:
WHERE createDate >= CONVERT_TZ(CURDATE() + INTERVAL 16 HOUR,'America/New_York','UTC')
AND createDate < CONVERT_TZ(CURDATE() + INTERVAL 26 HOUR,'America/New_York','UTC')
You could also use ADDTIME(CURDATE(),'16:00') to obtain a DATETIME value for 4pm today, if you'd rather combine ordinary date objects and ordinary time objects. Similarly, you could get 2am tomorrow like this:
ADDTIME(CURDATE(),'02:00') + INTERVAL 1 DAY
Notice that this form of WHERE clause allows a range scan on an index on the createDate column. This is very good for performance.
To convert datetime from a timezone to another timezone:
SELECT DATE(CONVERT_TZ(createDate, '+00:00', '-04:00')) createdDate,
HOUR(CONVERT_TZ(createDate, '+00:00', '-04:00')) hourOfDay
FROM carts
WHERE
createDate BETWEEN CURRENT_DATE + INTERVAL 16 HOUR AND CURRENT_DATE + INTERVAL 26 HOUR
GROUP BY createdDate, hourOfDay
For different dates
SELECT DATE(CONVERT_TZ(createDate, '+00:00', '-04:00')) createdDate,
HOUR(CONVERT_TZ(createDate, '+00:00', '-04:00')) hourOfDay
FROM carts
WHERE
createDate BETWEEN '2014-09-24' AND '2014-10-01'
GROUP BY createdDate, hourOfDay
HAVING hourOfDay <= 2 OR hourOfDay >= 20
You might think "why not in WHERE clause?"
If functions are used in the where clause, indexes can't be used (which results in a full table scan). So just filter out the records within the daterange, and the hours in the HAVING clause
FYI
CURRENT_DATE + INTERVAL 16 HOUR
Is short for
DATE_ADD(CURRENT_DATE, INTERVAL 16 HOUR)
I am trying to get the number of times a user has logged in since the beginning of each day.
SELECT user_id
FROM users
WHERE TIMESTAMPDIFF(HOUR, user_login, NOW()) < 12
AND user_id = 1
This sql checks the difference between the login and the current time which is wrong.
What should go instead of NOW() to indicate midnight+1min of that day and check the logins throughout that day?
As far as I understand your code, the question is rather about mySQL and not PHP. Use
CURDATE()
instead of NOW() since TIMESTAMPDIFF will use this as 'Current Day, 00:00:00'
To get the end of the current day use
CURDATE() + INTERVAL 1 DAY
so your where-clause should be
WHERE user_login BETWEEN CURDATE() AND CURDATE() + INTERVAL 1 DAY
provided you have the user_login field in the DATE format, otherwise you would have to cast that accordingly.
I need help with mysql and date_sub(). I have a table call Activity
Activity(id,deadline,alert)
Activity(1,'2011-04-18','1 DAY');
Activity(2,'2011-04-13','1 MONTH');
Every row in A have an 'alert', this field indicate how time before the deadline an activity have to reported.
For example
On 2011-04-17 I have to report the activity with 'id' 1
On 2011-03-14 I have to report the activity with 'id' 2
I trying to use date_sub() functions, but I can't use a field as params of this function. Any idea how to fix this?
SELECT *
FROM `activities`
WHERE date_sub(`deadline`, INTERVAL alert) >= CURDATE();
Split the alert into 2 fields
Alert_count: integer
Alert_period: enum('hour','day','month','week')
And change the query like so:
SELECT *
FROM `activities`
WHERE CASE alert_period
WHEN 'hour' THEN date_sub(`deadline`, INTERVAL alert_count HOUR) >= CURDATE();
WHEN 'day' THEN date_sub(`deadline`, INTERVAL alert_count DAY) >= CURDATE();
...
END CASE
If the number of alerts is small, you could write out a case:
WHERE case
when alert = '1 DAY' then date_sub(`deadline`, INTERVAL 1 DAY)
when alert = '1 MONTH' then date_sub(`deadline`, INTERVAL 1 MONTH)
... etc ...
end >= CURDATE();
Although this solution will work it's not the most efficient way of storing this data because each time you query for this data MySQL must look at the interval value in every row, compute it against deadline date and then return you the answer.
If you were to compute this information just before you insert the data and store alert_date as a DATE column then (assuming you index it too) it'd be very fast for MySQL to find the rows with a query like:
SELECT id FROM activity WHERE alert=CURRENT_DATE();
even more efficient (it'd allow it to be query cached):
SELECT id FROM activity WHERE alert="2011-04-23";
Strings are not allowed after INTERVAL, you can convert your all alert limit to day on one column.
Activity(id,deadline,alert)
Activity(1,'2011-04-18','1');
Activity(2,'2011-04-13','30');
and use as:
SELECT *
FROM `activities`
WHERE date_sub(`deadline`, INTERVAL alert DAY) >= CURDATE();
How to select data from mysql table past date to current date? For example, Select data from 1 january 2009 until current date ??
My column "datetime" is in datetime date type. Please help, thanks
Edit:
If let say i want to get day per day data from 1 january 2009, how to write the query? Use count and between function?
select * from *table_name* where *datetime_column* between '01/01/2009' and curdate()
or using >= and <= :
select * from *table_name* where *datetime_column* >= '01/01/2009' and *datetime_column* <= curdate()
All the above works, and here is another way if you just want to number of days/time back rather a entering date
select * from *table_name* where *datetime_column* BETWEEN DATE_SUB(NOW(), INTERVAL 30 DAY) AND NOW()
You can use now() like:
Select data from tablename where datetime >= "01-01-2009 00:00:00" and datetime <= now();
Late answer, but the accepted answer didn't work for me.
If you set both start and end dates manually (not using curdate()), make sure to specify the hours, minutes and seconds (2019-12-02 23:59:59) on the end date or you won't get any results from that day, i.e.:
This WILL include records from 2019-12-02:
SELECT *SOMEFIELDS* FROM *YOURTABLE* where *YOURDATEFIELD* between '2019-12-01' and '2019-12-02 23:59:59'
This WON'T include records from 2019-12-02:
SELECT *SOMEFIELDS* FROM *YOURTABLE* where *YOURDATEFIELD* between '2019-12-01' and '2019-12-02'