using <= or >= in timestamp field in mysql - mysql

I would like to select all records before 2014-03-22 date:
where date < 2014-03-22 // what I need
but below code doesn't see 2013 year's records :
SELECT * FROM `tractions` WHERE YEAR(date) <= 2014 AND MONTH(date) <= 3 and DAY(date) <= 22 and succ = 1

Is there anything wrong with:
SELECT * FROM tractions
WHERE date < '2014-03-22' -- place the date, correctly formatted, in quotes
Since this comparison doesn't use any functions, it will also allow you to use any indices setup on the date column.

Related

Aggregating table data in MySQL, is there an easier way to do this?

I'm trying to write a query that aggregates data from a table.
Essentially I have a long list of devices that have been inventoried and eventually installed over the last couple of years.
I want to find the average amount of time between when the device was received and when it was installed, and then have that data sorted by the month the device was installed. BUT in each month's row, I also want to include the data from the previous months.
So essentially what I want to see is: (sorry for terrible formatting)
MonthInstalled | TimeToInstall | Total#Devices
-----------------+---------------+----------------------------
Jan | 10 Days | 5
Feb(=Jan+Feb) | 15 Days | 18 (5 in Jan + 13 in Feb)
Mar(=Jan+Feb+Mar)| 13 Days | 25 (5 + 13 + 7)
...
The query I currently have written looks like this:
INSERT INTO DevicesInstall
SELECT ROUND(AVG(DATEDIFF(dvc.dt_install , dvc.dt_receive)), 1) AS 'Install',
COUNT(dvc.dvc_model) AS 'Total Devices',
MAX(dvc.dt_install) AS 'Date',
loc.loc_campus AS 'Campus'
FROM dvc_info dvc, location loc
WHERE dvc.dvc_loc_bin = loc.loc_bin
AND dvc.dt_install < '20160201'
;
Although this is functional, I have to iterate this for each month manually, so it is not scale-able. Is there a way to condense this at all?
We can return the dates using an inline view (derived table), and then join to the dvc_info table, so we can get the "cumulative" results.
To get the results for:
Jan
Jan+Feb
Jan+Feb+Mar
We need to return three copies of the rows for Jan, and two copies of the rows for Feb, and then collapse the those rows into an appropriate group.
The loc_campus is being included in the SELECT list... not clear why that is needed. If we want results "by campus", then we need to include that expression in the GROUP BY clause. Otherwise, the value returned for that non-aggregate is indeterminate... we will get a value for some row "in the group", but it could be any row.
Something like this:
SELECT d.dt AS `before_date`
, loc.loc_campus AS `Campus`
, ROUND(AVG(DATEDIFF(dvc.dt_install,dvc.dt_receive)),1) AS `Install`
, COUNT(dvc.dvc_model) AS `Total Devices`
, MAX(dvc.dt_install) AS `latest_dt_install`
FROM ( SELECT '2016-01-01' + INTERVAL 1 MONTH AS dt
UNION ALL SELECT '2016-01-01' + INTERVAL 2 MONTH
UNION ALL SELECT '2016-01-01' + INTERVAL 3 MONTH
UNION ALL SELECT '2016-01-01' + INTERVAL 4 MONTH
UNION ALL SELECT '2016-01-01' + INTERVAL 5 MONTH
UNION ALL SELECT '2016-01-01' + INTERVAL 6 MONTH
UNION ALL SELECT '2016-01-01' + INTERVAL 7 MONTH
UNION ALL SELECT '2016-01-01' + INTERVAL 8 MONTH
UNION ALL SELECT '2016-01-01' + INTERVAL 9 MONTH
UNION ALL SELECT '2016-01-01' + INTERVAL 10 MONTH
UNION ALL SELECT '2016-01-01' + INTERVAL 11 MONTH
UNION ALL SELECT '2016-01-01' + INTERVAL 12 MONTH
) d
CROSS
JOIN location loc
LEFT
JOIN dvc_info dvc
ON dvc.dvc_loc_bin = loc.loc_bin
AND dvc.dt_install < d.dt
GROUP
BY d.dt
, loc.loc_campus
ORDER
BY d.dt
, loc.loc_campus
Note that the value returned for d.dt will be the "up until" date. We're going to get '2016-02-01' returned for the January results. If we want to return a value of January date, we can use an expression in the SELECT list...
SELECT DATE_FORMAT(d.dt + INTERVAL -1 MONTH,'%Y-%m') AS `month`
Lots of options on query alternatives.
But it looks like the "big hump" is that to get cumulative results, we need to return multiple copies of the dvc_info rows, so the rows can be collapsed into each "grouping".
I recommend working on just the SELECT first. And get that tested working, before monkeying around to turn it into an INSERT ... SELECT.
FOLLOWUP
We can use any query as an inline view (derived table d) that returns a set of dates we want.
e.g.
FROM ( SELECT DATE_FORMAT(m.install_dt,'%Y-%m-01') + INTERVAL 1 MONTH AS dt
FROM dvc_install m
WHERE m.install_dt >= '2016-01-01'
GROUP BY DATE_FORMAT(m.install_dt,'%Y-%m-01') + INTERVAL 1 MONTH
) d
Note that with this approach, if there are no install_dt in February, we won't get back a row for February. Using the static UNION ALL SELECT approach allows us to get back "zero" counts, i.e. to return rows for months where there isn't an install_dt in that month. (But that's the answer to a different question... how do I get back a "zero" count for February when there aren't any rows for Februrary?)
Alternatively, if we have a calendar table e.g. cal that contains a list of the dates we want, we could just reference the table in place of the inline view, or the inline view query could get rows from that.
FROM ( SELECT cal.dt
FROM cal cal
WHERE cal.dt >= '2016-01-01'
AND cal.dt <= NOW()
AND DATE_FORMAT(cal.dt,'%d') = '01'
) d

MySql Select record before x days every month

I have a table tbl_subscriptions and columns like this "id, user_name, join_date(date)", I want to select the users before 7 days every month based on join_date so that I can send them notifications to continue their subscription for the next month. I have records like this
1, user1, 2014-05-02
2, user2, 2014-05-04
3, user3, 2014-06-12
4, user4, 2014-06-20
4, user5, 2014-07-24
If today is 2014-07-28, then I want to get records 1 and 2. I tried below query
SELECT *,
datediff( date_format(date, '2014-07-%d'), now() ) as daysLeft
FROM tbl_subscriptions
HAVING daysLeft >= 0
AND daysLeft < 7
the problem with above sql is that it is selecting the record of the current month only, plz suggest any better query.
Does this do what you want?
SELECT s.*, datediff(date, curdate()) as daysLeft
FROM tbl_subscriptions s
WHERE date >= curdate() and date < curdate() + interval 7 day;
EDIT:
I see. These are recurrent subscriptions and you want to find the next ones. The following logic should work:
select s.*,
(case when day(date) >= day('2014-07-28')
then day(date) - day('2014-07-28')
else day(date) + day(last_day('2014-07-28')) - day('2014-07-28')
end) as diff
from tbl_subscriptions s
having diff <= 7;
Here is the SQL Fiddle.
Ok, first of all I dont know what is subscription renewal period. And idea of only checking date (and not the whole period) doesnt make sense to me.
But this will get you your required output.
SELECT *,
day(date) days,
day(last_day('2014-07-28')) as lastday,
day('2014-07-28') today, day(last_day('2014-07-28'))-day('2014-07-28') as diff
FROM tbl_subscriptions
having days <= (7-diff) or (days > today and days <= today+7)
And here goes the demo (schema thanks to one of the deleted answer) ->
http://sqlfiddle.com/#!2/3cc4f

using 'AND' with COUNT(*)

I would like to get the total number of entries, upon 2 or more conditions.
Yet is seems as if mysql is ignoring the 'AND' clause in the query.
edit:
I want to get number of calls made by user with id=97, while the date is between starttime and stoptime, and prefix is like *us*
Example:
select count(*)
from calls
where id = 97
and starttime >= '2012-06-11'
and stoptime >= '2012-06-12'
and prefix like '%us%'
This gives me total amount of calls from id=97, while ignoring the rest of the conditions
I'm guessing that you want the second condition on the date should be <=:
select count(*)
from calls
where id = 97
and starttime >= '2012-06-11'
and stoptime <= '2012-06-12'
and prefix like '%us%';
You should also know that if you are storing times in the date time field along with the date, the you might really want:
select count(*)
from calls
where id = 97
and date(starttime) >= '2012-06-11'
and date(stoptime) <= '2012-06-12'
and prefix like '%us%';
or better yet:
select count(*)
from calls
where id = 97
and starttime >= '2012-06-11'
and stoptime <= '2012-06-13'
and prefix like '%us%';
I think you meant to do something like
select count(*)
from calls
where id = 97
and (starttime >= '2012-06-11' and stoptime <= '2012-06-12')
and prefix like '%us%'

SQL SERVER 2008 Date difference

I have a column name logdate which has dates in following format
2011-01-04 23:35:44.000
I want to select other columns in between 1st June 2011 till 30th June 2011 so the query should be
select * from abc where logdate = ?
You can use >= and <:
SELECT *
FROM abc
WHERE logdate >= '20110601' AND logdate < '20110701'
There are many ways to manipulate SQL datetimes and strings that represent SQL datetimes:
http://msdn.microsoft.com/en-us/library/ms186724(v=sql.105).aspx
A very straightforward way to do this would be to use >= < operators.
SELECT *
FROM abc
WHERE logdate >= '20110601'
AND logdate < '20110701'
The reason you want to use < July 1 as opposed to <= June 30 is that the string parsing on a date assumes it is midnight on that date, and it will exclude any values later than June 30 at 12 AM.
Assuming that LogDate is a DateTime column, you can use the following query to get the full range of the month:
WHERE logdate >= '2011-06-01' AND logdate < '2011-07-01'

MySQL: group by date RANGE?

OK I have this query that groups 2 columns together quite nicely:
SELECT search_query_keyword, search_query_date, COUNT(1) as count
FROM search_queries
WHERE search_query_date >= '.$from.' AND search_query_date <= '.$to.'
GROUP BY search_query_keyword, search_query_date
ORDER BY count DESC
LIMIT 10
But what if I want to group by a date RANGE instead of just a date? Is there a way to do that?
Thanks!
EDIT: OK these answers are pretty complicated and I think what I want can be acheived a lot easier so let me re-explain. I want to select keywords over a time period ">= 20090601 AND <= 20090604" for example. But instead of getting repeated keywords I would rather just get the keyword ounce and how many times it occured. So for example instead of this:
keyword: foo
keyword: foo
keyword: foo
keyword: bar
keyword: bar
I would get:
keyword: foo, count: 3
keyword: bar, count: 2
I'm not exactly sure about the date range grouping -- you'd have to define the date ranging that you would want and then maybe you could UNION those queries:
SELECT
'Range 1' AS 'date_range',
search_query_keyword
FROM search_queries
WHERE search_query_date >= '.$fromRange1.' AND search_query_date <= '.$toRange1.'
UNION
SELECT
'Range 2' AS 'date_range',
search_query_keyword
FROM search_queries
WHERE search_query_date >= '.$fromRange2.' AND search_query_date <= '.$toRange2.'
GROUP BY 1,2
Or if you wanted to put them within a grouping of how many days old like "30 days, 60 days, etc" you could do this:
SELECT
(DATEDIFF(search_query_date, NOW()) / 30) AS date_group,
search_query_keyword
FROM search_queries
GROUP BY date_group, search_query_keyword
EDIT: Based on the further information you provided, this query should produce what you want:
SELECT
search_query_keyword,
COUNT(search_query_keyword) AS keyword_count
FROM search_queries
WHERE search_query_date >= '.$from.' AND search_query_date <= '.$to.'
GROUP BY search_query_keyword
You could group on a CASE statement or on the result of a function. For instance:
SELECT search_query_keyword, QUARTER(search_query_date), COUNT(1) as count
FROM search_queries
WHERE search_query_date >= '.$from.' AND search_query_date <= '.$to.'
GROUP BY search_query_keyword, QUARTER(search_query_date)
ORDER BY count DESC
look into the different DATE-based functions and build based on that, such as
select YEAR( of your date ) + MONTH( of your date ) as ByYrMonth
but the result in above case would need to be converted to character to prevent a year of 2009 + January ( month 1) = 2010 also getting falsely grouped with 2008 + February (month 2 ) = 2010, etc... Your string should end up as something like:
...
200811
200812
200901
200902
200903
...
If you wanted by calendar Quarters, you would have to do a INTEGER of the (month -1) divided by 4 so...
Jan (-1) = 0 / 4 = 0
Feb (-1) = 1 / 4 = 0
Mar (-1) = 2 / 4 = 0
Apr (-1) = 3 / 4 = 0
May (-1) = 4 / 4 = 1
June (-1)= 5 / 4 = 1 ... etc...
Yes, a previous example explicitly reference the QUARTER() function that handles more nicely, but if also doing based on aging, such as 30, 60, 90 days, you could apply the similar math above but divide by 30 for your groups.