I am looking for a SQL statement that outputs missing calendar weeks based on a table. Here is a short example. We are using MySQL. I dropped all the irrelevant columns.
+------+--------------+
| Year | CalendarWeek |
+------+--------------+
| 2012 | 1 |
| 2012 | 5 |
| 2012 | 8 |
| 2012 | 9 |
| 2012 | 51 |
| 2013 | 2 |
+------+--------------+
What I am trying to get:
+------+--------------+
| Year | CalendarWeek |
+------+--------------+
| 2012 | 2 |
| 2012 | 3 |
| 2012 | 4 |
| 2012 | 6 |
| 2012 | 7 |
| 2012 | 10 |
| ... | ... |
| 2012 | 50 |
| 2012 | 52 |
| 2013 | 1 |
+------+--------------+
I added the dots to shorten the output.
Further background: The columns in each row are computed via some logic in Java. If we create a new row, lets say for the current calendar week, we have to check if we need to fill gaps. Its a simple routine. Is there a row for the previous week? Yes? Fine we are done. Otherwise compute the value for the previous week, insert it and check the week before that. The one and only do-while-loop in the whole program.
This apparently fails if we start with a table that has more than one gap. In this case we have to run through all the calendar weeks for every year and check for missing rows. Takes some time.
tl;dr I am trying to reduce roundtrips to the database with a shortcut.
Related
I am getting the following table,
+-------------+-----------+------------+--------------------+
| quantity | year | month | category |
+-------------+-----------+------------+--------------------+
| 122 | 2012 | 7 | 15 |
| 100 | 2012 | 7 | 25 |
| 1029| 2012 | 7 | 10 |
| 212 | 2012 | 7 | 0 |
+-------------+-----------+------------+--------------------+
But I want to get it as how we can merge cells in excel
+-------------+-----------+------------+--------------------+
| quantity | year | month | category |
+-------------+-----------+------------+--------------------+
| 122 | | | 15 |
| 100 | 2012 | 7 | 25 |
| 1029| | | 10 |
| 212 | | | 0 |
+-------------+-----------+------------+--------------------+
checking if this is possible in MySQL?
You might find that aggregation is what you really want:
select year, month, group_concat(quantity), group_concat(category)
from t
group by year, month;
This produces one row for each year/month combination with a list of the quantities and categories. You can get fancy and use a newline to separate the values. They would appear on multiple "lines" but still be one "row".
Note that the ordering is not specified in the question. And without an order by in the group_concat() the values for the two columns might not be in the same order as the original data.
Hi I’m trying to make a small CRM where I storing some master data for Clients and I have made a CRUD that saves to a MySQL table called clients – so far so good.
Now I would like to register worked time within each Client, so I need arrays within arrays, but as I can see that is not possible with MySQL tables.
My idea is that when I have finished working on a task, then I (frontend) select a the Client, and then I select “Register time” within that client then I select the Year I have done the task, and then I select the Month I have done the task and then I add a new line with in that table (Time sheet) where I set the date, the name of the task and the time used or the fixed priced and save.
I have the table Clients which contains the basic master data:
Clients (simplified) – where I want to add the new column with register_time.
+-----------+-------------+---------------+---------------+---------------+
| client_id | client_name | clients_phone | clients_email | register_time |
+-----------+-------------+---------------+---------------+---------------+
| 1 | Ford | 111-222-333 | info#ford.com | [years] |
| 2 | BMW | 444-555-666 | info#bmw.com | [years] |
| 3 | KIA | 777-888-999 | info#kia.com | [years] |
+-----------+-------------+---------------+---------------+---------------+
Years
+---------+
| year |
+---------+
| 2017 |
| 2018 |
| 2019 |
| 2020 |
+---------+
Months (for 2020)
+-------------+
| month |
+-------------+
| january |
| february |
| march |
| april |
| may |
| june |
| july |
| august |
| september |
| october |
| november |
| december |
+-------------+
Time sheet (for January)
+------------+-------------+---------------+---------------+
| date | task | time_worked | fixed_price |
+------------+-------------+---------------+---------------+
| 01-01-2020 | Webdesign | 2 | - |
| 02-01-2020 | Logo | - | 500 |
+------------+-------------+---------------+---------------+
I hardly know any MySQL (or backend in general) and I made the node CRUD connection with a tutorial - so I’m really having trouble getting my head around how to join the table and use the client_id as the main key/identifier. And also how to make it so that I can have a CRUD insdie my current CRUD so that I can create new years and new lines in the time sheets.
Maybe I’m going about it all wrong – I hope you can help.
Let me know if you need more info from me.
// Rue
I have a table which saves monthly values, but also a value for the complete year. Is is possible to add to the yearly value whenever I insert a value for a month?
I want to avoid loading the value first, adding to it in the server-code and writing it again.
You can write a trigger and insert value in the years table when any value is inserted in the Month table like
CREATE TRIGGER tr_month ON monthly_table
AFTER INSERT
AS
BEGIN
UPDATE year_table
SET // insert your values here
FROM inserted
WHERE monthly.id = inserted.id; // something like that, I am not sure about your structure thats why cannot add exact syntax
END
GO
Your best approach to this is avoiding redundant data in your table. When you need year totals, SELECT them.
You didn't tell us your table definition, so I will guess. The table months contains
year int (for example, 2019)
month int (1-12)
value number
You can get the details of this the obvious way: `
SELECT year, month, value FROM months;
You can get the details and the yearly sums this way
SELECT year, month, SUM(value) value
FROM months
GROUP BY year, month WITH ROLLUP;
The result set for this query looks like the other result set, but also contains sums. It looks like this:
| year | month | value |
| ---- | ----- | ----- |
| 2018 | 1 | 100 | detail month values...
| 2018 | 2 | 140 |
| 2018 | 3 | 130 |
| 2018 | 4 | 190 |
| 2018 | 5 | 120 |
| 2018 | 6 | 180 |
| 2018 | 7 | 130 |
| 2018 | 8 | 140 |
| 2018 | 9 | 150 |
| 2018 | 10 | 200 |
| 2018 | 11 | 230 |
| 2018 | 12 | 300 |
| 2018 | | 2010 | yearly sum for 2018 (month is NULL)
| 2019 | 1 | 100 |
| 2019 | 2 | 130 |
| 2019 | 3 | 160 |
| 2019 | 4 | 140 |
| 2019 | 5 | 190 |
| 2019 | 6 | 240 |
| 2019 | | 960 | yearly sum for 2019 (month is NULL)
| | | 2970 | total sum (both month and year are NULL)
View on DB Fiddle
Why is this a good process?
you need to store no extra data.
it works correctly even if you update or delete rows in your table.
it's fast: SQL is made to do this kind of thing.
Just solved it by adding the values client side, this also saves computing time on the server.
Thank you in advance for all of your help!
I am trying to determine how to get a count of the number of values in the first column of a report where I have it grouped on a number. So for example if I had the table below I would want to have an output of 5 at the bottom of the first column. I have tried multiple things but my attempts either fail or I get the number of rows within each group or the total number of rows in the table.
+----------+---------+-------+------+
| Number | Order | Month | Year |
+----------+---------+-------+------+
| 142010 | 1800053 | 1 | 2018 |
+ +---------+-------+------+
| | 1800045 | 4 | 2018 |
+----------+---------+-------+------+
| 1622220 | 1700021 | 10 | 2017 |
+----------+---------+-------+------+
| 20101040 | 1600065 | 4 | 2016 |
+ +---------+-------+------+
| | 1400056 | 8 | 2014 |
+----------+---------+-------+------+
| 21968145 | 1800004 | 4 | 2018 |
+----------+---------+-------+------+
| 4893154 | 1400021 | 4 | 2014 |
+ +---------+-------+------+
| | 1200047 | 6 | 2012 |
+ +---------+-------+------+
| | 1200056 | 1 | 2012 |
+----------+---------+-------+------+
| Total: 5 | | | |
+----------+---------+-------+------+
I apologize if this has been asked before, I tried searching but could not find a similar question. Any advice would be appreciated!
Thank you in advance!
I have a table that looks like this:
+--------+----------+------+-----------+
| make | model | year | avg_price |
+--------+----------+------+-----------+
| Subaru | Forester | 2013 | 18533 |
| Ford | F-150 | 2014 | 27284 |
| Ford | F-150 | 2010 | 18296 |
| Subaru | Forester | 2012 | 16589 |
| Ford | F-150 | 2013 | 25330 |
| Ford | F-150 | 2011 | 20366 |
| Subaru | Forester | 2008 | 7256 |
| Ford | F-150 | 2015 | 33519 |
| Ford | F-150 | 2012 | 23033 |
| Subaru | Forester | 2011 | 15789 |
+--------+----------+------+-----------+
Using MySQL, I want to add a new column with a three year average price centered on the record year. It should look like this when done:
+--------+----------+------+-----------+---------------------+
| make | model | year | avg_price | 3_yr_center_average |
+--------+----------+------+-----------+---------------------+
| Subaru | Forester | 2013 | 18533 | 17561 |
| Ford | F-150 | 2014 | 27284 | 28711 |
| Ford | F-150 | 2010 | 18296 | 19331 |
| Subaru | Forester | 2012 | 16589 | 16970 |
| Ford | F-150 | 2013 | 25330 | 25216 |
| Ford | F-150 | 2011 | 20366 | 20565 |
| Subaru | Forester | 2008 | 7256 | 7256 |
| Ford | F-150 | 2015 | 33519 | 30401 |
| Ford | F-150 | 2012 | 23033 | 22910 |
| Subaru | Forester | 2011 | 15789 | 16189 |
+--------+----------+------+-----------+---------------------+
It seems that this should be straight forward if the data was ordered and everything was the same make and model. The reality is the working table has over 4000 unique make model year combinations and they are all un-ordered by year.
Therefore, the query cannot rely on ordered records or that adjacent records are in any way relevant to the next record. The query needs to filter on the distinct make model and year then center avg over the three year interval without hiccuping when it is averaging the first or last year of a spread where it will be missing one or two of the three years.
Any MySQL tips would be greatly appreciated! Thanks.
We can try joining twice to bring the previous and proceeding years into a single line with the current year, for each make and model. Then, subquery and take the average of prices from the three years:
SELECT make, model, year, avg_price,
(avg_price + last_price + next_price) / (1.0 + last_cnt + next_cnt) AS 3_yr_center_average
FROM
(
SELECT t1.make, t1.model, t1.year, t1.avg_price,
COALESCE(t2.avg_price, 0) AS last_price,
COALESCE(t3.avg_price, 0) AS next_price,
CASE WHEN t2.avg_price IS NOT NULL THEN 1 ELSE 0 END AS last_cnt,
CASE WHEN t3.avg_price IS NOT NULL THEN 1 ELSE 0 END AS next_cnt
FROM yourTable t1
LEFT JOIN yourTable t2
ON t1.make = t2.make AND t1.model = t2.model AND t1.year = t2.year + 1
LEFT JOIN yourTable t3
ON t1.make = t3.make AND t1.model = t3.model AND t1.year = t3.year - 1
) t
ORDER BY
make, model, year;
Demo
Note that there is an edge case here in your data with regard to what should happen for a record which is the last (or first) year for that make and model. In that case, there are only two years available for the three year moving average. I made the assumption in this case that you would be OK with actually just reporting a two year moving average. For example, for the Subaru Forester in 2013, I report a three year moving average of 17561, which is actually the average of the 2013 price 18533 and the previous 2012 price 16589.