Need to find duplicates with multiple criteria and then comparing dates between duplicates - mysql

I am writing annual membership registrations to a single db table. I need to keep track of when renewals have occurred in less than 11 months from their last renewal.
I look for the duplicate rows based on multiple criteria. I currently have this working with out the 11 month criteria, although it's slow. Here's what I currently use.
SELECT y_reg.* FROM y_reg WHERE (((y_reg.season) In (SELECT season FROM y_reg As Tmp
GROUP BY season, Father_Last_Name, Father_First_Name
HAVING Count(*)>1
AND Father_Last_Name = y_reg.Father_Last_Name
AND Father_First_Name = y_reg.Father_First_Name)))
ORDER BY y_reg.season, y_reg.Father_Last_Name, y_reg.Father_First_Name
I have a field Date which is the date of the renewal that I need to evaluate. I'd like to add something like "AND Date - Date < 335"
335 is the number of days and is about 1 month short of a year. But I just keep getting syntax error because I clearly don't know what I'm doing.

Date arithmetic works quite well in MySQL; you just need the knack.
You can say things like
AND later.Date >= earlier.Date
AND later.Date < earlier.Date + INTERVAL 11 MONTH
That particular pair of comparisons comes up true if the later date occurs in the time range between the earlier date and 11 months later.
In general you can say stuff like this to do date arithmetic.
datestamp + INTERVAL 1 HOUR
datestamp - INTERVAL 5 MINUTE
datestamp + 1 MONTH - 3 WEEK
datestamp - INTERVAL 3 QUARTER (calendar quarters)
LAST_DAY(datestamp) + INTERVAL 1 DAY - INTERVAL 1 MONTH
The last item is the first day of the month containing the datestamp. This whole date thing works quite well.
I think you should consider a so-called self-join query to get your duplicate-except-for-date results. Try something like this.
SELECT a.*
FROM y_reg a
JOIN y_reg b ON a.Father_Last_Name = b.Father_Last_Name
AND a.Father_First_Name = b.Father_First_Name
AND b.Date < a.Date - 11 MONTH
AND b.Date >= a.Date - 12 MONTH

Related

Dynamic due date finder in a single query

id start_date interval period
1 2018-01-22 2 month
2 2018-02-25 3 week
3 2017-11-24 3 day
4 2017-07-22 1 year
5 2018-02-25 2 week
the above is my table data sample. start_dates will be expired based on interval and period(i.e id-1 will have due date after 2 months from the start_date, id-2 will have due after 3 weeks vice versa). period is enum of (day,week,month,year). requirement is, Client can give any period of dates. let's say 25-06-2026 to 13-07-2026 like that.. I have to return the ids whose due dates falls under that period.I hope i made my question clear.
I am using mysql 5.7. I found a way to achieve this with recursive CTE's.(not available in mysql 5.7). and there is a way to achieve this by populating virtual records by using inline sub queries along with unions but its a performance killer and we can't do populate virtual records every time a client request comes.(like given in the link Generating a series of dates) I have reached a point to get results for a single date which is very easy. Below is my query.
SELECT b.*
FROM (SELECT a.*,
CASE
WHEN period = 'week' THEN MOD(Datediff('2018-07-22', start_date), 7 * intervals)
WHEN period = 'month'
AND Day('2018-07-22') = Day(start_date)
AND MOD(Period_diff(201807, Extract(YEAR_MONTH FROM start_date)), intervals) = 0 THEN 0
WHEN period = 'year'
AND Day('2018-07-22') = Day(start_date)
AND MOD(Period_diff(201807, Extract(
YEAR_MONTH FROM start_date)) / 12,
intervals) = 0 THEN 0
WHEN period = 'day' THEN MOD(Datediff('2018-07-22', start_date) , intervals)
end filters
FROM kml_subs a)b
WHERE b.filters = 0;
But I need to do this for a period of dates not a single date. Any suggestions or solutions will be much appreciated.
My desired result shoud be like..
if i give two dates.say 2030-05-21 & 2030-05-27. due dates falls under those 6 dates between(2030-05-21 & 2030-05-27) will be shown in the result.
id
1
4
My question is different from Using DATE_ADD with a Column Name as the Interval Value . I am expecting a dynamic way to check due dates based on start_date
Thanks, Kannan
In MySQL, it would seem that a query along these lines would suffice. (Almost) everything else could and should be handled in application level code...
SELECT *
, CASE my_period WHEN 'day' THEN start_date + INTERVAL my_interval DAY
WHEN 'week' THEN start_date + INTERVAL my_interval WEEK
WHEN 'month' THEN start_date + INTERVAL my_interval MONTH
WHEN 'year' THEN start_date + INTERVAL my_interval YEAR
END due_date
FROM my_table;

Extract only month and day from date field mysql

I've a table in a db with some date field with format yyyy-mm-dd
I'm trying to perform a query that take just records with a interval of 3 month from today.
I've done like this
WHERE DATE_SUB(myTable.myField, INTERVAL 3 MONTH) = CURDATE()
and it works, but my second step is ignore years of my date field and from curdate().
I've tried EXTRACT or DATEFORMAT, but query doesn't work with those function.
How can I modify my query?
Thanks
The condition is wrong.
Try this instead:
...WHERE myTable.myField >= CURDATE() - INTERVAL 3 MONTH...
EDIT:
Based on your comment:
with my query i've got all record that have in dateField this date
'2016-12-07' (curdate() is today '2016-09-07') and it's fine. but i
want that query gives me also date that have 12 on month and 07 on
day, ignoring year. Eg. if i have '2016-12-07' and '2014-12-07', my
query must give me both records. it's a query that will run every day
...WHERE DATE_FORMAT(myTable.myField,'%m-%d') =
DATE_FORMAT((CURDATE() + INTERVAL 3 MONTH),'%m-%d')...
Use below condition which will find records with a interval of 3 month from today.
WHERE myTable.myField = DATE_SUB(CURDATE(), INTERVAL 3 MONTH)

SQL group by relative date range

I have a user table which has standard columns id and registered_date
For each week in the year (e.g. DATE_FORMAT '%x-%v' ), I want a count of users who signed up within the PAST 4 weeks of that week (including that week itself).
So for example, for week 2014-50, I want a count of users who registered in week 50, as well as week 49, 48 and 47.
Normally, to get a count of users registered in each week, I would use:
SELECT DATE_FORMAT(registered_date, '%x-%v'), count(*)
FROM user
GROUP BY DATE_FORMAT(registered_date, '%x-%v')
But of course, this doesn't include users who signed up in the previous 3 weeks as well.
Any idea how to modify the query accordingly?
We're going to have to create a structured query to get this stuff.
First, we need a subquery that will yield a list of the starting days of each week in which a user registered. We need dates of the Mondays, because you're using %x-%v to get your week numbers.
To get the date of the Monday immediately preceding any DATETIME value, this expression does it.
DATE(registered_date) - INTERVAL WEEKDAY(registered_date) DAY
So this little subquery gets us the list of Mondays.
SELECT DISTINCT DATE(registered_date) -
INTERVAL WEEKDAY(registered_date) DAY as monday
FROM user
Next we need to nest this inside another query to get a row for each (overlapping) four week period for which we hope to summarize. Each row will have three columns in it: the first date of the period, the last+1 date of the period, and the period's identifier, for example '2013-52'.
SELECT monday - INTERVAL 3 WEEK AS start,
monday + INTERVAL 1 WEEK AS finish,
DATE_FORMAT(monday, '%x-%v') AS week
FROM (
SELECT DISTINCT DATE(registered_date) -
INTERVAL WEEKDAY(registered_date) DAY as monday
FROM user
) AS wks
Cool. Now we have a table that we can join with the user table to extract which users signed up in which period. We can do that like so
SELECT user.id, periods.week
FROM user
JOIN ( /* the subquery */
) AS periods ON user.registered_date >= periods.start
AND user.registered_date < periods.finish
But we don't want that detail, instead we want the count, so we rewrite this as an aggregate query.
SELECT periods.week, COUNT(*)
FROM user
JOIN ( /* the subquery */
) AS periods ON user.registered_date >= periods.start
AND user.registered_date < periods.finish
GROUP BY periods.week
ORDER BY periods.week
Putting it all together, here's the query.
SELECT periods.week, COUNT(*)
FROM user
JOIN (
SELECT monday - INTERVAL 3 WEEK AS start,
monday + INTERVAL 1 WEEK AS finish,
DATE_FORMAT(monday, '%x-%v') AS week
FROM (
SELECT DISTINCT DATE(registered_date) -
INTERVAL WEEKDAY(registered_date) DAY as monday
FROM user
) AS wks
) AS periods ON user.registered_date >= periods.start
AND user.registered_date < periods.finish
GROUP BY periods.week
ORDER BY periods.week
This looks like a hairball, but notice that we've built it up like a sandwich, of fairly simple parts.
The trick to assigning users to the appropriate four-week periods is embedded in this ON condition for the join.
ON user.registered_date >= periods.start
AND user.registered_date < periods.finish
Because the start and finish dates overlap, each user gets assigned to multiple four-week periods.
The other trick here is to use actual dates rather than week ids '2014-45' for the computations, because it's not possible, especially at year ends, to convert back from week id to date, and we want to use computations like date - INTERVAL 3 WEEK to compute start and end dates.

Retrieve data whose Date between start and end date is between today and after ten day in rails or sql

I want to retrieve data whose Date between start and end date is between today and after ten day.I'm doing it in rails but even if i get the query in MySQL i can convert it to rails active record.
Something like this one :
select * from users where( between users.from and users.to = between '2012-11-25 11:52:33' and '2012-12-05 11:52:33')
The interval (a, b) overlaps with (c, d) iff a < d and b > c. Also, the curdate() function returns the current date ("today"). To calculate the date ten days into the future you can use + interval 10 day.
Combining these bits of information you get:
select ... where users.to > curdate()
and users.from < curdate() + interval 10 day
Follwing is the logic snippet not the exact code though. Please try.
select * from users
where users.fromDate between '2012-11-25 11:52:33' and '2012-12-05 11:52:33'
and users.toDate between '2012-11-25 11:52:33' and '2012-12-05 11:52:33';
Check the following sample code in * SQLFIDDLE as well
EDITING AS PER YOUR QUESTION'S REPHRASING..
Guess you are better off with,
where users.from between users.from and users.from + interval 10day
and users.to <= user.from + interval 10 day
That means, your from date can be anything (today, yesterday, one month back, two years to future...). Hence your to-date will be validated against any date that is 10 days interval from the above from-date
Hope it makes sense... but again, Joni's answers fills for your today's consition. :)

How do I select two weeks ago in MYSQL?

I have a report that is driven by a sql query that looks like this:
SELECT batch_log.userid,
batches.operation_id,
SUM(TIME_TO_SEC(ramses.batch_log.time_elapsed)),
SUM(ramses.tasks.estimated_nonrecurring + ramses.tasks.estimated_recurring),
DATE(start_time)
FROM batch_log
JOIN batches ON batch_log.batch_id=batches.id
JOIN ramses.tasks ON ramses.batch_log.batch_id=ramses.tasks.batch_id
JOIN protocase.tblusers on ramses.batch_log.userid = protocase.tblusers.userid
WHERE DATE(ramses.batch_log.start_time) > "2011-02-01"
AND ramses.batch_log.time_elapsed > "00:03:00"
AND DATE(ramses.batch_log.start_time) < now()
AND protocase.tblusers.active = 1
AND protocase.tblusers.userid NOT in ("ksnow","smanning", "dstapleton")
GROUP BY userid, batches.operation_id, date(start_time)
ORDER BY start_time, userid ASC
Since this is to be compared with the time from the current payperiod it causes an error.
Our pay periods start on a Sunday, the first pay period was 2011-02-01 and our last pay period started the 4th of this month. How do I put that into my where statement to strip the most recent pay period out of the query?
EDIT: So now I'm using date_sub(now(), INTERVAL 2 WEEK) but I really need a particular day of the week(SUNDAY) since it is wednesday it's chopping it off at wednesday.
You want to use DATE_SUB, and as an example.
Specifically:
select DATE_SUB(curdate(), INTERVAL 2 WEEK)
gets you two weeks ago. Insert the DATE_SUB ... part into your sql and you're good to go.
Edit per your comment:
Check out DAYOFWEEK:
and you can do something along the lines of:
DATE_SUB(DATE_SUB(curdate(), INTERVAL 2 WEEK), INTERVAL 2 + DAYOFWEEK(curdate()) DAY)
(I don't have a MySql instance to test it on .. but essentially subtract the number of days after Monday.)
Question isn't quite clear, especially after the edit - it isn't clear now is the "pay period" two weeks long or do you want just last two weeks back from last sunday? I assume that the period is two weeks... then you first need to know how many days the latest period (which you want to ignore, as it isn't over yet) has been going on. To get that number of days you can use expression like
DATEDIFF(today, FirstPeriod) % 14
where FirstPeriod is 2011-02-01. And now you strip that number of days from the current date in the query using date_sub(). The exact expression depends on how the period is defined but you should get the idea...