How to get 7 days data from multiple table - mysql

Get 7 days data from multiple tables in mysql.
This is my select statement:
$sql="SELECT * FROM chain_management UNION
SELECT * FROM adagio_accounting_suite UNION
SELECT * FROM billquick UNION
SELECT * FROM budgetingdb UNION
SELECT * FROM chain_management UNION
SELECT * FROM accountpayable
WHERE DATE >= DATE_SUB(CURDATE(), INTERVAL 7 DAY) ORDER BY curtime DESC";

You can try to use this:
$sql="SELECT * FROM (SELECT * FROM chain_management UNION
SELECT * FROM adagio_accounting_suite UNION
SELECT * FROM billquick UNION
SELECT * FROM budgetingdb UNION
SELECT * FROM chain_management UNION
SELECT * FROM accountpayable) as XYZ
WHERE DATE >= DATE_SUB(CURDATE(), INTERVAL 7 DAY) ORDER BY curtime DESC";

Related

MySQL Select range date between two columns without using table columns

In My sql I want to get the date differences between two dates without using table columns
For example
SELECT BETWEEN '2012-01-10' AND '2012-01-15' as date1;
I have to get the following date as output
'2012-01-11'
'2012-01-12'
'2012-01-13'
'2012-01-14'
how to write a query to get the output as above
WITH RECURSIVE
cte AS ( SELECT #startdate + INTERVAL 1 DAY `date`
UNION ALL
SELECT `date`+ INTERVAL 1 DAY
FROM cte
WHERE `date` < #enddate - INTERVAL 1 DAY )
SELECT *
FROM cte
fiddle
MySQL 8+ needed.
my sql version used 5.6
maximum 1 year
SELECT #startdate + INTERVAL (n3.num * 7 * 7 + n2.num * 7 + n1.num + 1) DAY `date`
FROM ( SELECT 0 num union select 1 union select 2 union select 3
union select 4 union select 5 union select 6) n1
JOIN ( SELECT 0 num union select 1 union select 2 union select 3
union select 4 union select 5 union select 6) n2
JOIN ( SELECT 0 num union select 1 union select 2 union select 3
union select 4 union select 5 union select 6 union select 7) n3
HAVING `date` < #enddate;
fiddle
Max. period length is 7 * 7 * 8 = 392 days.
If you are running MySQL 8.0, you can do this with a recursive query:
with recursive cte as (
select '2012-01-10' + interval 1 day as dt
union all
select dt + interval 1 day from cte where dt + interval 1 day < '2012-01-15'
)
select * from cte
This generates one row per date in between the bounds given as input.

Get data by quantity and date using Laravel

I have in my mysql database a user table where I store the date the user was created.
I would like to get the number of registered users in the last 7 days.
Example:
[6,4,8,6,5,6,7]
Where each number is representing the number of registered users on each date within the 7 day period.
How could I do this using Laravel?
You can use the following solution where you can get the normal array and also another array where the key is the date and the value is the number of users registered on that day.
$usersPerDay = User::select(DB::raw('count(id) as `number_of_users`'),DB::raw("DATE_FORMAT(created_at, '%Y-%m-%d') new_date"))
->whereRaw('DATE(created_at) >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)')
->groupBy('new_date')->orderBy('new_date')->get();
print_r($usersPerDay->pluck('number_of_users')->toArray());
print_r($usersPerDay->pluck('number_of_users', 'new_date'));
As your requirement is to generate days from a date range(link) you will need to do the following.
first, update the strict value in config/database.php file
'mysql' => [
...
'strict' => false,
...
]
and then run the following query to get the desire result
$query = "select
t1.new_date,
coalesce(SUM(t1.number_of_users+t2.number_of_users), 0) AS number_of_users
from
(
select DATE_FORMAT(a.Date,'%Y-%m-%d') as new_date,
'0' as number_of_users
from (
select curdate() - INTERVAL (a.a + (10 * b.a) + (100 * c.a)) DAY as Date
from (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as a
cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as b
cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as c
) a
where a.Date BETWEEN NOW() - INTERVAL 7 DAY AND NOW()
)t1
left join
(
SELECT DATE_FORMAT(created_at,'%Y-%m-%d') AS created_at,
COUNT(*) AS number_of_users
FROM users
WHERE DATE_SUB(created_at, INTERVAL 1 DAY) > DATE_SUB(DATE(NOW()), INTERVAL 1 WEEK)
GROUP BY DAY(created_at) DESC
)t2
on t2.created_at = t1.new_date
group by DAY(t1.new_date)
order by t1.new_date asc";
$users = DB::select($query);
$usersPerDay = collect($users)->pluck('number_of_users')->toArray();
print_r($usersPerDay);
die;
with the following code you will get an array with the name and created at, and then do a count to get the number of users:
$previous_week = strtotime("-1 week +1 day");
$start_week = strtotime("last sunday midnight",$previous_week);
$end_week = strtotime("next saturday",$start_week);
$start_week = date("Y-m-d",$start_week);
$end_week = date("Y-m-d",$end_week);
$users = User::whereBetween('created_at', [$start_week, $end_week])->get(['name','created_at']);
echo count($users);
Insted of echo do whatever you want.
hope this works
Using Laravel CollectiongroupBy() function.
$users = Users::whereBetween(now(), now()->subWeek())
->groupBy(function ($user) {
return $user->created_at->toDateString();
})
->map(function ($group) {
return $group->count();
})
->values()
->toArray();

How to select Overdue Rows with Date Frequencies?

+------------------------+--------+
| Invoice_id | due_date | amount |
+-------------+----------+--------+
| 20 |2020-01-18| 1250 |
+-------------+----------+--------+
| 21 |2020-01-15| 1335 |
+-------------+----------+--------+
Get all Records with date passed n days and its multiple serires
like below...
for example n=5
SELECT * FROM `invoices`
WHERE `due_date = DATE_ADD(CURDATE() + INTERVAL 5 days)
OR due_date = DATE_ADD(CURDATE() + INTERVAL 10 days)
OR due_date = DATE_ADD(CURDATE() + INTERVAL 15 days)`
but i want to make it universal for any n value
1 Way to achieve this is to generate a date range with 5 days difference and then join that with your table -
SELECT *
FROM `invoices` I
JOIN (SELECT a.Date
FROM (SELECT CURDATE() + INTERVAL (a.a + (10 * b.a) + (100 * c.a) ) * 5 DAY as Date
FROM (SELECT 0 AS a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS a
CROSS JOIN (SELECT 0 AS a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) as b
CROSS JOIN (SELECT 0 AS a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) as c
)a
WHERE a.Date <= (SELECT MAX(due_date) FROM `invoices`)
) ON I.due_date = a.Date
I have generated only 1000 rows here. If your table is too large then you may generate 10000 rows using 1 more cross-join.
WHERE (DATEDIFF(due_date, CURDATE) % 5) = 0
It'll select all the multiple of 5 before and after today...
You can create a variable and pass it into a prepared statement like below.
SET #dateinterval = n;
SET #preparedStatement = CONCAT("
SELECT * FROM `invoices`
WHERE `due_date` IN (
(CURDATE() + INTERVAL ",#dateinterval," day),
(CURDATE() + INTERVAL ",#dateinterval*2," day),
(CURDATE() + INTERVAL ",#dateinterval*3," day)
);
");
PREPARE SQLStatement FROM #preparedStatement;
EXECUTE SQLStatement;
DEALLOCATE PREPARE SQLStatement;
Provided u pass in 5 for the #dateinterval, the above statement will resolved as:
SELECT * FROM `invoices`
WHERE `due_date` IN (
(CURDATE() + INTERVAL 5 day),
(CURDATE() + INTERVAL 10 day),
(CURDATE() + INTERVAL 15 day)
);
If you are using MySQL version 8.0 or higher, here is another alternative -
WITH CTE (RN, ID, DUE_DATE, AMT) AS(
SELECT *, ROW_NUMBER() OVER(ORDER BY due_date) RN FROM Invoices
WHERE due_date >=CURDATE()
)
SELECT * FROM CTE WHERE RN%5=0

Aggregating data by date in a date range without date gaps in result set

I have a table with sell orders and I want to list the COUNT of sell orders per day, between two dates, without leaving date gaps.
This is what I have currently:
SELECT COUNT(*) as Norders, DATE_FORMAT(date, "%M %e") as sdate
FROM ORDERS
WHERE date <= NOW()
AND date >= NOW() - INTERVAL 1 MONTH
GROUP BY DAY(date)
ORDER BY date ASC;
The result I'm getting is as follows:
6 May 1
14 May 4
1 May 5
8 Jun 2
5 Jun 15
But what I'd like to get is:
6 May 1
0 May 2
0 May 3
14 May 4
1 May 5
0 May 6
0 May 7
0 May 8
.....
0 Jun 1
8 Jun 2
.....
5 Jun 15
Is that possible?
Creating a range of dates on the fly and joining that against you orders table:-
SELECT sub1.sdate, COUNT(ORDERS.id) as Norders
FROM
(
SELECT DATE_FORMAT(DATE_SUB(NOW(), INTERVAL units.i + tens.i * 10 + hundreds.i * 100 DAY), "%M %e") as sdate
FROM (SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9)units
CROSS JOIN (SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9)tens
CROSS JOIN (SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9)hundreds
WHERE DATE_SUB(NOW(), INTERVAL units.i + tens.i * 10 + hundreds.i * 100 DAY) BETWEEN DATE_SUB(NOW(), INTERVAL 1 MONTH) AND NOW()
) sub1
LEFT OUTER JOIN ORDERS
ON sub1.sdate = DATE_FORMAT(ORDERS.date, "%M %e")
GROUP BY sub1.sdate
This copes with date ranges of up to 1000 days.
Note that it could be made more efficient easily depending on the type of field you are using for your dates.
EDIT - as requested, to get the count of orders per month:-
SELECT aMonth, COUNT(ORDERS.id) as Norders
FROM
(
SELECT DATE_FORMAT(DATE_SUB(NOW(), INTERVAL months.i MONTH), "%Y%m") as sdate, DATE_FORMAT(DATE_SUB(NOW(), INTERVAL months.i MONTH), "%M") as aMonth
FROM (SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10 UNION SELECT 11)months
WHERE DATE_SUB(NOW(), INTERVAL months.i MONTH) BETWEEN DATE_SUB(NOW(), INTERVAL 12 MONTH) AND NOW()
) sub1
LEFT OUTER JOIN ORDERS
ON sub1.sdate = DATE_FORMAT(ORDERS.date, "%Y%m")
GROUP BY aMonth
You are going to need to generate a virtual (or physical) table, containing every date in the range.
That can be done as follows, using a sequence table.
SELECT mintime + INTERVAL seq.seq DAY AS orderdate
FROM (
SELECT CURDATE() - INTERVAL 1 MONTH AS mintime,
CURDATE() AS maxtime
FROM obs
) AS minmax
JOIN seq_0_to_999999 AS seq ON seq.seq < TIMESTAMPDIFF(DAY,mintime,maxtime)
Then, you join this virtual table to your query, as follows.
SELECT IFNULL(orders.Norders,0) AS Norders, /* show zero instead of null*/
DATE_FORMAT(alldates.orderdate, "%M %e") as sdate
FROM (
SELECT mintime + INTERVAL seq.seq DAY AS orderdate
FROM (
SELECT CURDATE() - INTERVAL 1 MONTH AS mintime,
CURDATE() AS maxtime
FROM obs
) AS minmax
JOIN seq_0_to_999999 AS seq
ON seq.seq < TIMESTAMPDIFF(DAY,mintime,maxtime)
) AS alldates
LEFT JOIN (
SELECT COUNT(*) as Norders, DATE(date) AS orderdate
FROM ORDERS
WHERE date <= NOW()
AND date >= NOW() - INTERVAL 1 MONTH
GROUP BY DAY(date)
) AS orders ON alldates.orderdate = orders.orderdate
ORDER BY alldates.orderdate ASC
Notice that you need the LEFT JOIN so the rows in your output result set will be preserved even if there's no data in your ORDERS table.
Where do you get this sequence table seq_0_to_999999? You can make it like this.
DROP TABLE IF EXISTS seq_0_to_9;
CREATE TABLE seq_0_to_9 AS
SELECT 0 AS seq UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4
UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9;
DROP VIEW IF EXISTS seq_0_to_999;
CREATE VIEW seq_0_to_999 AS (
SELECT (a.seq + 10 * (b.seq + 10 * c.seq)) AS seq
FROM seq_0_to_9 a
JOIN seq_0_to_9 b
JOIN seq_0_to_9 c
);
DROP VIEW IF EXISTS seq_0_to_999999;
CREATE VIEW seq_0_to_999999 AS (
SELECT (a.seq + (1000 * b.seq)) AS seq
FROM seq_0_to_999 a
JOIN seq_0_to_999 b
);
You can find an explanation of all this in more detail at http://www.plumislandmedia.net/mysql/filling-missing-data-sequences-cardinal-integers/
If you're using MariaDB version 10+, these sequence tables are built in.
First create a Calendar Table
SELECT coalesce(COUNT(O.*),0) as Norders, DATE_FORMAT(C.date, "%M %e") as sdate
FROM Calendar C
LEFT JOIN ORDERS O ON C.date=O.date
WHERE O.date <= NOW() AND O.date >= NOW() - INTERVAL 1 MONTH
GROUP BY DAY(date)
ORDER BY date ASC;

How to select last 30 days dates in MySQL?

Can I list somehow the dates of last 30 days in MySQL? Not from a table!
For example I think about like this:
SELECT date WHERE date BETWEEN SUBDATE(NOW(), INTERVAL 30 DAY) AND NOW();
Is that possible?
I hacked this together from someone else's code, but it seems to work:
SELECT DATE_FORMAT(m1, '%d %b %Y')
FROM (
SELECT SUBDATE( NOW() , INTERVAL 30 DAY) + INTERVAL m DAY AS m1
FROM (
select #rownum:=#rownum+1 as m from
(select 1 union select 2 union select 3 union select 4) t1,
(select 1 union select 2 union select 3 union select 4) t2,
(select 1 union select 2 union select 3 union select 4) t3,
(select 1 union select 2 union select 3 union select 4) t4,
(select #rownum:=-1) t0
) d1
) d2
WHERE m1 <= now()
ORDER BY m1
The original code by valex is here:
How to get a list of months between two dates in mysql
You can do this the "explicit" way. That is, generate a series of numbers and calculate the date:
select date(date_sub(now(), interval n.n day) as thedate
from (select 1 as n union all
select 2 union all
. . .
select 30
) n