Get data from first date on database till today - mysql

I want to group my data by date and view it on chart. here my data example:
count created_at
----- ----------
5 2020/04/20
4 2020/04/21
3 2020/04/25
9 2020/04/28
i want my data when i fetch be like
count created_at
----- ----------
5 2020/04/20
4 2020/04/21
0 2020/04/22
0 2020/04/23
0 2020/04/24
3 2020/04/25
0 2020/04/26
0 2020/04/27
9 2020/04/28
when there is no data in that date it will shown 0. can u guys help me how to get it on laravel controller?
thanks before.

#Alun here is an example of how you can do this:
SELECT `dateList`.`Date`,
CASE WHEN `yt`.`date` IS NULL THEN 0
ELSE COUNT(`yt`.`id`)
END AS `amt`
FROM
-- this is the part you can copy/paste
-- to be used to left join in a table of your choice
-- ---------------------------------------------------------------------------------------------------------------------------
(
SELECT DATE(`a`.`Date`) AS `Date`
FROM (
SELECT NOW() - 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`
) AS `a`
WHERE `a`.`Date` BETWEEN '2020-04-01' AND NOW()
) AS `dateList`
-- ---------------------------------------------------------------------------------------------------------------------------
LEFT JOIN `yourTable` AS `yt` ON `dateList`.`Date` = DATE(`yt`.`date`)
GROUP BY `dateList`.`Date`
ORDER BY `dateList`.`Date` ASC
Just sub your table name in place of yourTable in this query (modifying the date column name from your table replacing yt.date accordingly) and this will give you a list for every day of the month showing 0 for any day of the month that doesn't have any value.
As far as getting this to work using eloquent in a Laravel controller it might be possible but off the top of my head I don't know how you would do it. You could use this this raw SQL in the controller to accomplish what you want though.
Here's an example of how it works in sql fiddle.
Hope this helps!

Related

MySQL insert comma delimited variable into multiple rows

I'm trying to create a stored procedure to quickly insert some data into my DB and just having a little trouble figuring out the quickest way to do this.
Into table one I insert a bunch of data about a file and return the new ID of that file.
I then have a separate table that tracks which versions of the app that file is compatible with.
This table has two columns
FileID, Version
Let's say the returned FileID = 1 in this instance.
The Version String will look like this
"1.1, 1.2, 2.1, 2.2"
Essentially I want to split that string and loop it so it ends up as 4 rows like this
FileID
Version
1
1.1
1
1.2
1
2.1
1
2.2
You can accomplish this goal with a little bit of creative splitting:
SELECT zz.`file_id`, zz.`word`
FROM (SELECT DISTINCT `file_id`, LOWER(TRIM(SUBSTRING_INDEX(SUBSTRING_INDEX('1.1,1.2,1.3,2.0,2.1,2.1.5,2.2', ',', num.`id`), ',', -1))) as `word`
FROM (SELECT (h*1000+t*100+u*10+v+1) as `id`
FROM (SELECT 0 h 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) a,
(SELECT 0 t 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) b,
(SELECT 0 u 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) c,
(SELECT 0 v 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) d) num
WHERE num.`id` >= 0) zz
WHERE zz.`word` NOT IN ('')
ORDER BY zz.`word`;
This will give you up to 10,000 versions … if you need that many.

mysql select odd number values in a column that includes delimiter separated values

My next database table will be set up more optimally. Unfortunately this one was already set up where one column [data] contains checkbox array values that were saved the following way:
value 1|~|value 1 value 2|~|value 2 value 3|~|value 3
Not optimal, I know.
What I need is a mysql query that select only the values in [data] column in front of the |~|. Basically think I need to select the only odd values.
Any help pointing me in the right direction is greatly appreciated. I tried an if statement in a query and it did not work. Of course I deleted that by mistake.
What I need is a mysql query that select only the
values in [data] column in front of the |~|.
One thing to note the numbers before |~| must be unique.
It will not show the same number twice.
Query
SELECT
DISTINCT
SUBSTRING (
record_data.column
, LOCATE('|~|', record_data.`column` , number_generator.number) - 1
, 1
) AS number
FROM (
SELECT
#row := #row + 1 AS number
FROM (
SELECT 0 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
) record_1
CROSS JOIN (
SELECT 0 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
) record_2
CROSS JOIN (
SELECT 0 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
) record_4
CROSS JOIN (
SELECT 0 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
) record_5
CROSS JOIN (
SELECT #row := 0
) AS init_user_params
) AS number_generator
CROSS JOIN (
SELECT
*
FROM (
SELECT 'value 1|~|value 1 value 2|~|value 2 value 3|~|value 3' AS `column`
) AS record
) AS record_data
WHERE
LOCATE('|~|', record_data.`column` , number_generator.number) <> 0
Result
| number |
| ------ |
| 1 |
| 2 |
| 3 |
demo

MySQL count day of week between two dates over a table

I have a booking table with the following columns:
id, start_date, end_date
I want to know which days have had the most bookings over my dataset.
I can use dayofweek() on the start date and group by this also and use a count(*). But I also want to include the days between the start of booking and end.
An example output wouldbe
dayofweek count(*)
1 1
2 1
3 1
4 2
5 3
6 3
7 1
for the following set
id start_date end_date
1 2017-10-01 2017-10-07
2 2017-10-04 2017-10-07
3 2017-10-06 2017-10-08
I am assuming you wish to know something like how many rooms are filled for each date for the duration between the start and end. The"trick" here is that a long period between start/end will repeat the day or week and/or that the end day of week might be smaller than the start day of week. So, I have:
generated a list of 100,000 dates (1 per row)
joined those dates between the start/end of your table
converted each joined rows to a day of week number to be counted
left joined to a list of 1 to 7, and counted the rows of step 3
NOTE: if the end_date is a "check out date" then it may be necessary to deduct 1 day from each record to compensate (which is not done below).
This approach is available for review here at SQL Fiddle
MySQL 5.6 Schema Setup:
CREATE TABLE Table1
(`id` int, `start_date` datetime, `end_date` datetime)
;
INSERT INTO Table1
(`id`, `start_date`, `end_date`)
VALUES
(1, '2017-09-21 00:00:00', '2017-10-07 00:00:00'), ## added this row
(1, '2017-10-01 00:00:00', '2017-10-07 00:00:00'),
(2, '2017-10-04 00:00:00', '2017-10-07 00:00:00'),
(3, '2017-10-06 00:00:00', '2017-10-08 00:00:00')
;
Query:
set #commence := str_to_date('2000-01-01','%Y-%m-%d')
select
w.dy
, count(t.wdy)
from (
select 1 dy union all select 2 dy union all select 3 dy union all
select 4 dy union all select 5 dy union all select 6 dy union all select 7 dy
) w
left join (
select DAYOFWEEK(cal.dy) wdy
from (
select adddate( #commence ,t4.i*10000 + t3.i*1000 + t2.i*100 + t1.i*10 + t0.i) dy
from ( select 0 i 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) t0
cross join (select 0 i 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) t1
cross join (select 0 i 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) t2
cross join (select 0 i 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) t3
cross join (select 0 i 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) t4
) cal
INNER JOIN Table1 t on cal.dy between t.start_date and t.end_date
) t on w.dy = t.wdy
group by
w.dy
Results:
| dy | count(t.wdy) |
|----|--------------|
| 1 | 4 |
| 2 | 3 |
| 3 | 3 |
| 4 | 4 |
| 5 | 5 |
| 6 | 6 |
| 7 | 6 |
Also see: How to get list of dates between two dates in mysql select query where the accepted answer is the basis for the set of cross joins that produces 100,000 dates starting from a nominated date. I modified that however for syntax (explicit cross join syntax), a parameter as start point, and use of union all for efficiency.
You can accomplish this with a recursive table:
WITH cte AS
(
SELECT DATE_ADD(start_date INTERVAL 1 DAY) AS date, end_date, DAYOFWEEK(start_date) AS dw from bookings
UNION ALL
SELECT DATE_ADD(start_date INTERVAL 1 DAY), end_date, DAYOFWEEK(date)
FROM cte WHERE date <= end_date
)
SELECT COUNT(*), dw FROM cte GROUP BY dw

INSERT rows multiple times based on a column value from another table

Mainly, I would like to insert a row in table 1 multiple times, based on an integer value in a column of table 2.
My situation
Table 2 contains a column 'SKU' and 'stock', and I would like to insert the 'SKU' and a timestamp into table 1. I want this row duplicated for 'stock'-value times in table 1.
I currently have the following query:
DECLARE #Count int = 1
WHILE #Count <= ....
BEGIN
INSERT INTO table1 (table1.SKU, table1.timestamp_in)
SELECT table2.SKU, "some timestamp" FROM table2
SET ...
END
I am not sure if this is the correct approach. I would like to run this loop for 'table2.stock' times.
My question is: Is this possible with just a SQL query, or should it be a better practice to build some (in my case) java code for this?
You don't need a procedure or anything like that. All you need is a table containing just numbers. I'm creating this table on the fly with this in this example:
SELECT aa.a + 10*bb.b + 100*cc.c AS numbers FROM (
SELECT 0 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) aa
, (SELECT 0 b 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) bb
, (SELECT 0 c 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) cc;
This creates the numbers 0 till 999.
Now you join your table2 with this numbers table in the range of stock. Your final query looks like this:
INSERT INTO table1 (table1.SKU, table1.timestamp_in)
SELECT table2.SKU, "some timestamp" FROM table2
INNER JOIN (
SELECT aa.a + 10*bb.b + 100*cc.c AS n FROM (
SELECT 0 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) aa
, (SELECT 0 b 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) bb
, (SELECT 0 c 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) cc
) numbers ON numbers.n BETWEEN 0 AND table2.stock /*assuming you have no negative stock*/
Just make sure, that the numbers table contains more numbers than the highest value in the stock column.

Select the latest recored in each 2-minute interval in MySQL

I want to read about 8000 files, each containing the daily stock prices of a distinct stock, into a single table and select the latest price in each 2-minute interval and write a Null if no record available in an interval. My idea is add a column called bucketNumber to indicate which interval the record falls into, create another table containing one column of values 1, 2, ..., 195 repeating 8000 times and then joining the two tables. At last select the record with largest timestamps for records with the same bucketNumber.
Is this a good way to do the job? If it is, then how to efficiently generate a table with one column of values 1, 2, ..., 195 repeating 8000 times.
Here's a query that will return you a column of integer values from 1 to 8000
SELECT thousands.d*1000 + hundreds.d*100 + tens.d*10 + ones.d + 1 AS num
FROM ( SELECT 0 AS d 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
) ones
CROSS
JOIN ( SELECT 0 AS d 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
) tens
CROSS
JOIN ( SELECT 0 AS d 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
) hundreds
CROSS
JOIN ( SELECT 0 AS d 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
) thousands
HAVING num <= 8000
ORDER BY num
Seems like a stored procedure would be the easiest approach. Just loop through each 2 minute interval and select the price from the record having the maximum time in the interval. You could include arguments for the start and end time, which would provide a more general solution.