WHERE Statement to find all records in a month? - mysql

Suppose I want to find all of the records involved in June!
-----------------------------------------------------------
CaseID StartDate EndDate
1 2016-05-31 2016-06-01
2 2016-02-29 2016-06-20
3 2016-03-21 2016-06-01
4 2016-05-05 2016-06-01
5 2016-05-20 2016-07-01
6 2016-05-12 2016-12-31
SELECT CaseID, StartDate, EndDate
FROM ServiceCase
WHERE((StartDate > '2016-05-31' and StartDate < '2016-07-01') or (EndDate >
'2016-05-31' and EndDate < '2016-07-01'))
But I cannot search CaseID 6's Record, Am I Logic wrong?

It seems like you want to select all cases that were in progress during the month of June. If so, then these are the 4 possible scenarios:
Or, in other words, the cases would have to both
start before July; and
end after May
So, the query would essentially look like this:
SELECT CaseID, StartDate, EndDate
FROM ServiceCase
WHERE
StartDate < '2016-07-01' AND EndDate > '2016-05-31'
Output: SQL fiddle

Try as mentioned below:
SELECT CaseID, StartDate, EndDate
FROM ServiceCase
WHERE(StartDate < '2016-07-01' and EndDate > '2016-05-31')

You could try MySQL MONTH() Function; sample code as bellow for the month June
SELECT CaseID, StartDate, EndDate
FROM ServiceCase
WHERE MONTH(StartDate) = 6
OR MONTH(EndDate) = 6
OR (MONTH(StartDate) < 6 AND MONTH(EndDate) > 6)
Note: this is just an option to compare month part without considering performance.

Related

MySQL Select data from table with dates between in reverse of interval 7 days

I have a MySQL requirement to select data from a table based on a start date and end date and group it by weekly also selecting the data in reverse order by date. Assume that, I have chosen the start date as 1st November and the end date as 04 December. Now, I would like to fetch the data as 04 December to 28 November, 27 November to 20 November, 19 November to 12 November and so on and sum the value count for that week.
Given an example table,
id
value
created_at
1
10
2021-10-11
2
13
2021-10-17
3
11
2021-10-25
4
8
2021-11-01
5
1
2021-11-10
6
4
2021-11-18
7
34
2021-11-25
8
17
2021-12-04
Now the result should be like 2021-12-04 to 2021-11-28 as one week, following the same in reverse order and summing the column value data for that week. I have tried in the query to add the interval of 7 days after the end date but it didn't work.
SELECT count(value) AS total, MIN(R.created_at)
FROM data_table AS D
WHERE D.created_at BETWEEN '2021-11-01' AND '2021-12-04' - INTERVAL 7 DAY ORDER BY D.created_at;
And it's also possible to have the last week may have lesser than 7 days.
Expected output:
end_interval
start_interval
total
2021-12-04
2021-11-27
17
2021-11-27
2021-11-20
34
2021-11-20
2021-11-13
4
2021-11-13
2021-11-06
1
2021-11-06
2021-10-30
8
2021-10-30
2021-10-25
11
Note that the last week is only 5 days depending upon the selected from and end dates.
One option to address this problem is to
generate a calendar of all your intervals, beginning from last date till first date, with a split of your choice, using a recursive query
joining back the calendar with the original table
capping start_interval at your start_date value
aggregating values for each interval
You can have three variables to be set, to customize your date intervals and position:
SET #start_date = DATE('2021-10-25');
SET #end_date = DATE('2021-12-04');
SET #interval_days = 7;
Then use the following query, as already described:
WITH RECURSIVE cte AS (
SELECT #end_date AS end_interval,
DATE_SUB(#end_date, INTERVAL #interval_days DAY) AS start_interval
UNION ALL
SELECT start_interval AS end_interval,
GREATEST(DATE(#start_date), DATE_SUB(start_interval, INTERVAL #interval_days DAY)) AS start_interval
FROM cte
WHERE start_interval > #start_date
)
SELECT end_interval, start_interval, SUM(_value) AS total
FROM cte
LEFT JOIN tab
ON tab.created_at BETWEEN start_interval AND end_interval
GROUP BY end_interval, start_interval
Check the demo here.

How to SELECT the last 30 days records from SQL, including days with zero?

I want to SELECT from my table the last 30 day records. My queries looks like this:
SELECT DATE(o_date) as date, count(id) AS sum FROM customers WHERE o_date BETWEEN DATE_SUB(CURDATE(), INTERVAL 30 DAY) AND NOW() GROUP BY o_date
Or this:
SELECT DATE(o_date) AS date, COUNT(id) AS sum FROM customers WHERE o_date >= DATE(NOW()) + INTERVAL -30 DAY GROUP BY DATE(o_date)
I want to create a list with dates and count of id-s.
But where I dont have any records in exact day, the query just skip that date. But I want to insert there a zero.
Example:
id
o_date
1
2021-11-23
2
2021-11-22
3
2021-11-20
4
2021-11-20
5
2021-11-19
6
2021-11-18
7
2021-11-18
The result will be this:
date
sum
2021-11-23
1
2021-11-22
1
2021-11-20
2
2021-11-19
1
2021-11-18
2
But where I dont have records like in this example in 2021-11-21 how can I insert to the sum 0?
Thank you!
UPDATE:
I need this query for MariaDB.
For MariaDB,
SELECT DATE(o_date) AS date, COUNT(id) AS sum FROM customers WHERE o_date BETWEEN DATE_SUB(NOW(), INTERVAL 30 DAY)
AND NOW();
For SQL,
SELECT DATE(o_date) AS date, COUNT(id) AS sum FROM customers WHERE DATEDIFF(day,o_date,GETDATE()) < 31
or
SELECT DATE(o_date) AS date, COUNT(id) AS sum FROM customers WHERE DATEDIFF(day,o_date,GETDATE()) between 0 and 30
From what I could gather, it should be :
SELECT * FROM customers WHERE o_date BETWEEN DATE_SUB(NOW(), INTERVAL 30 DAY) AND NOW();
Link to almost 10 year old post:
MySQL Query - Records between Today and Last 30 Days
Try this query:
SELECT DATE(o_date) AS date, COUNT(id) AS sum FROM customers WHERE o_date >= DATE_ADD(NOW(), INTERVAL -30 DAY)
Your real question seems to be about how to show all 30 days, even days with a zero value.
Since you are using MariaDB 10.0 or newer, there is a nifty trick to give all the days in a range:
MariaDB [test]> SELECT '2019-01-01' + INTERVAL seq-1 DAY AS dates FROM seq_1_to_31;
+-----------------------------------+
| dates |
+-----------------------------------+
| 2019-01-01 |
| 2019-01-02 |
| 2019-01-03 |
| 2019-01-04 |
| 2019-01-05 |
| 2019-01-06 | etc.
So, what you do is
SELECT ...
FROM ( select using seq table ) AS dates
JOIN ( your table ) AS yours ON dates.dy = yours.o_date
WHERE ...
Your secondary question about how to ask for a date range -- both of your attempts give the same result with the same performance.

Given a table with time periods, query for a list of sum per day

Let's say I have a table that says how many items of something are valid between two dates.
Additionally, there may be multiple such periods.
For example, given a table:
itemtype | count | start | end
A | 10 | 2014-01-01 | 2014-01-10
A | 10 | 2014-01-05 | 2014-01-08
This means that there are 10 items of type A valid 2014-01-01 - 2014-01-10 and additionally, there are 10 valid 2014-01-05 - 2014-01-08.
So for example, the sum of valid items at 2014-01-06 are 20.
How can I query the table to get the sum per day? I would like a result such as
2014-01-01 10
2014-01-02 10
2014-01-03 10
2014-01-04 10
2014-01-05 20
2014-01-06 20
2014-01-07 20
2014-01-08 20
2014-01-09 10
2014-01-10 10
Can this be done with SQL? Either Oracle or MySQL would be fine
The basic syntax you are looking for is as follows:
For my example below I've defined a new table called DateTimePeriods which has a column for StartDate and EndDate both of which are DATE columns.
SELECT
SUM(NumericColumnName)
, DateTimePeriods.StartDate
, DateTimePeriods.EndDate
FROM
TableName
INNER JOIN DateTimePeriods ON TableName.dateColumnName BETWEEN DateTimePeriods.StartDate and DateTimePeriods.EndDate
GROUP BY
DateTimePeriods.StartDate
, DateTimePeriods.EndDate
Obviously the above code won't work on your database but should give you a reasonable place to start. You should look into GROUP BY and Aggregate Functions. I'm also not certain of how universal BETWEEN is for each database type, but you could do it using other comparisons such as <= and >=.
There are several ways to go about this. First, you need a list of dense dates to query. Using a row generator statement can provide that:
select date '2014-01-01' + level -1 d
from dual
connect by level <= 15;
Then for each date, select the sum of inventory:
with
sample_data as
(select 'A' itemtype, 10 item_count, date '2014-01-01' start_date, date '2014-01-10' end_date from dual union all
select 'A', 10, date '2014-01-05', date '2014-01-08' from dual),
periods as (select date '2014-01-01' + level -1 d from dual connect by level <= 15)
select
periods.d,
(select sum(item_count) from sample_data where periods.d between start_date and end_date) available
from periods
where periods.d = date '2014-01-06';
You would need to dynamically set the number of date rows to generate.
If you only needed a single row, then a query like this would work:
with
sample_data as
(select 'A' itemtype, 10 item_count, date '2014-01-01' start_date, date '2014-01-10' end_date from dual union all
select 'A', 10, date '2014-01-05', date '2014-01-08' from dual)
select sum(item_count)
from sample_data
where date '2014-01-06' between start_date and end_date;

Iterating thought dates in SQL

I have a table 1 of data that looks a bit like that:
Record# Date Person
1 12/12/2012 Tom
2 01/02/2013 Tom
3 10/02/2013 Tom
4 02/01/2013 John
5 04/01/2014 John
6 30/06/2010 Mary
7 30/06/2011 Mary
8 30/06/2012 Mary
9 30/07/2012 Mary
and another table 2 where we have the registration date of each Person
Person RegisterDate MaxRecord
Tom 15/12/2011 100
John 01/01/2013 10
Mary 16/06/2010 50
Before adding a record in the table1, I need to check whether the annual count of record (table1) by Person is lower than the MaxRecord number (table2) for that Person. By Annual, I mean startDate = registration date and endDate = registration date + 1 year and not from Januray 1st till December 31st.
If I want to add a record for Mary, I want to write SQL that will give me the following output:
StartDate EndDate CountRecord
16/06/2010 15/06/2011 1
16/06/2011 15/06/2012 1
16/06/2012 15/06/2013 2
Once this output is build, I could test whether thedate of a new record (for a Person) is allowed or not.
Could someone give me a clue, a link to a tutorial or some help please?
For the following I am assuming you already have a numbers table, If you don't have a numbers table, then I'd recommend you make one then, but if you don't want to then you can create a number list on the fly
You can get a list of all boundaries by cross joining your table of Register dates (RegDate) with your numbers table:
SELECT r.Person,
DATE_ADD(r.RegisterDate, INTERVAL n.Number YEAR) PeriodStart,
DATE_ADD(r.RegisterDate, INTERVAL n.Number + 1 YEAR) PeriodEnd,
n.Number
FROM RegDate r
CROSS JOIN Numbers n;
This gives a table like (Just for Tom and adding WHERE n.Number <= 3; as an example):
Person PERIODSTART PERIODEND NUMBER
Tom 15/12/2011 15/12/2012 0
Tom 15/12/2012 15/12/2013 1
Tom 15/12/2013 15/12/2014 2
Tom 15/12/2014 15/12/2015 3
Example on SQL Fiddle
You then need to join this to your table of other dates (T) to do the count:
SELECT r.Person,
DATE_ADD(r.RegisterDate, INTERVAL n.Number YEAR) StartDate,
DATE_ADD(DATE_ADD(r.RegisterDate, INTERVAL n.Number + 1 YEAR), INTERVAL -1 DAY) EndDate,
COUNT(T.Record) AS `CountRecord`
FROM RegDate r
CROSS JOIN Numbers n
LEFT JOIN T
ON T.Person = r.Person
AND T.Date >= DATE_ADD(r.RegisterDate, INTERVAL n.Number YEAR)
AND T.Date < DATE_ADD(r.RegisterDate, INTERVAL n.Number + 1 YEAR)
WHERE DATE_ADD(r.RegisterDate, INTERVAL n.Number YEAR) <= CURRENT_TIMESTAMP
AND r.Person = 'Mary'
GROUP BY r.Person, R.RegisterDate, n.Number;
Giving a final result of:
PERSON STARTDATE ENDDATE COUNTRECORD
Mary 2010-06-16 2011-06-15 1
Mary 2011-06-16 2012-06-15 2
Mary 2012-06-16 2013-06-15 1
Mary 2013-06-16 2014-06-15 0
Full Example on SQL-Fiddle
I have limited the results to where the StartDate is less than today using this line
WHERE DATE_ADD(r.RegisterDate, INTERVAL n.Number YEAR) <= CURRENT_TIMESTAMP
you can obviously change this as you need

SQL to return record counts in X intervals

I have a table like this:
id | created_on
1 2013-09-03 20:05:09
2 2013-09-05 17:03:13
...
How do I write a query to return a result of record counts that was created from Date X to Date Y in 7-day intervals?
So the result would look like this:
count | created_on
4 2013-09-17 00:00:00
2 2013-09-24 00:00:00
1 2013-09-31 00:00:00
10 2013-10-07 00:00:00
...
You can go to the beginning of the week by subtracting the day of the week. Here is one way to do that:
select date(created_on - interval dayofweek(created_on) day), count(*)
from t
group by date(created_on - interval dayofweek(created_on) day);
If this is not the day you want the week to start, then you can add an offset day.
Group by the date field, floored to the week:
SELECT
count(*),
YEARWEEK(created_on) as week
FROM
yourtable
GROUP BY week
This assumes that created_on is a type that can be interpreted as a date:
http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_yearweek
This will get you weekly groupings, but you may want to then convert that field (which will look like YYYYWW) back to something more readable.
You can try this
SELECT created_on, count( id ) AS count
FROM `test_table`
WHERE created_on
BETWEEN '2013-09-01'
AND '2013-10-10'
GROUP BY WEEK( created_on )