I have budget data for a company in the following montly format. SqlFiddle link here.
Dept# YearMonth Budget($)
--------------------------
001 201301 100
001 201302 110
001 201303 105
.. ..... ...
002 201301 200
... ..... ...
I am required to break this up into daily records, which would look like this:
Dept# Date Budget($)
--------------------------
001 20130101 xxx
001 20130102 xxx
001 20130103 xxx
.. ..... ...
I need to generate daily records from each record in the source table. I don't want to assume that each month has 30 days. How do I determine the actual number of days for each month and break it up in the format shown above?
I appreciate any kind of help. Thanks!
Try:
with cte as
(select [dept#], [YearMonth], convert(datetime,[YearMonth]+'01',112) [Date], [Budget($)]
from budget
union all
select [dept#], [YearMonth], dateadd(d, 1, [Date]) [Date], [Budget($)]
from cte
where datediff(m,[Date],dateadd(d, 1, [Date]))=0
)
select [dept#], [Date],
1.0*[Budget($)] / count(*) over (partition by [dept#], [YearMonth]) [DailyBudget($)]
from cte
order by 1,2
(There's an implicit conversion from integer to floating point in the budget, as otherwise the daily rate will be rounded to the nearest dollar - this will not be necessary if the budget datatype is already held as something like numeric(10,2).)
(SQLFiddle here)
Related
I have records of smartmeter in an mysql database.
Records in timestamp order looking in generall as follow:
key
timestamp
watt now
000001
2022-10-04-01-01-01
10
000002
2022-10-04-01-02-01
10
000003
2022-10-04-01-03-01
101
000004
2022-10-04-01-04-01
101
000005
2022-10-04-01-05-01
102
000006
2022-10-04-01-06-01
101
000007
2022-10-04-01-07-01
102
000008
2022-10-04-01-08-01
10
000009
2022-10-04-01-09-01
10
000010
2022-10-04-01-09-01
10
000011
2022-10-04-01-09-01
107
000012
2022-10-04-01-09-01
101
000013
2022-10-04-01-09-01
109
000014
2022-10-04-01-09-01
10
000015
2022-10-04-01-09-01
10
I want to identify the groups with bigger number (lets say > 100)
and give them an incresing id. Also I want to get per group the first and last key id
Result of query should look like this:
month
day
numbers of group
first id
last id
average watt
10
04
0
000003
000007
102
10
04
1
000011
0000013
105
Any help apreciated
You'll need something to identify them as a group. My first thought was using RANK() or DENSE_RANK() but after multiple tries, I couldn't find a way. Then I thought about using LAG() but still I'm stuck at how to re-identify the rows as new group. After testing many times, I come up with this suggestion:
WITH cte AS (
SELECT s1.*,
#n := COALESCE(IF(s1.skey=1,1,s2.skey), #n) As newGroup
FROM smartmeter s1
LEFT JOIN (
SELECT skey,
stimestamp,
watt,
LENGTH(watt) AS lenwatt,
LAG(LENGTH(watt)) OVER (ORDER BY skey) llwatt
FROM smartmeter) s2 ON s1.skey=s2.skey
AND lenwatt != llwatt)
SELECT MONTH(stimestamp) AS Month,
DAY(stimestamp) AS Day,
ROW_NUMBER() OVER (ORDER BY MIN(skey)) AS 'numbers of group',
MIN(skey) AS 'first id',
MAX(skey) AS 'last id',
AVG(watt) AS 'Average watt',
CEIL(AVG(watt)) AS 'Average watt rounded',
newGroup
FROM cte
WHERE watt >= 100
GROUP BY newGroup, MONTH(stimestamp), DAY(stimestamp)
By the way, I've changed some of your column names because key is actually a reserve word. Although you can use it as column name as long as you wrap it in backticks, I personally find it's a hassle to do it every time.
Ok, so my idea was to use LENGTH(watt) and ORDER BY skey in the LAG() function. Then I'll separate those rows where the length doesn't match and use that as a starting point for each new group. After that, I left join the result of that with smartmeter table. The next challenge is to assign each of the rows that doesn't match with previous skey value then I've found this answer and applied it into the cte.
Once those are done, I just write another query to fulfil your expected result. Although, some part of it is not exactly as what you expected.
Here's a demo fiddle
I am trying to create a new column that has stores the 'Average weight of the field'. For example, the answer for RaceID = 123 would be 54.5. The RaceID's are not organised from smaller to largest and are displayed randomly like the example below.
RaceID
Weight
No. Starters
123
56
2
124
58
2
123
53
2
125
60
2
125
51
2
124
62
2
Try below query, It will display current table data along with average column :
select t.*,
avg(Weight) over(partition by raceID order by raceID ) avg_raceID
from table t;
SELECT RaceID, AVG(Weight) AS val_1
FROM dataset_name
GROUP BY RaceID;
By using above code we can get the average value of weights for every unique RaceID. Check the below image for better understanding.
https://i.stack.imgur.com/kMA68.png
Let me know if there are any modifications or error.
tablo1 tablo2
-------------------------- ------------------------------
fiyat1 tarih1 fiyat2 tarih2
---------- ------------ ----------- -----------
1200 03-2017 2100 03-2017
1050 03-2017 5200 03-2017
3250 04-2017 3200 04-2017
2501 04-2017
6100 05-2017
1100 05-2017
Collecting the same dates at price 1, collecting the same dates at price 2,
subtract 2 totals, group by date.
I want to print something like this:
-----------------------
05-2017 7200
04-2017 2511
03-2017 -5050
The question is true, but the result is wrong. I tried this.
SELECT tablo1.tarih1,
tablo1.fiyat1,
SUM(tablo1.fiyat1),
tablo2.tarih2,
tablo2.fiyat2,
SUM(tablo1.fiyat1),
(SUM(tablo1.fiyat1) - SUM(tablo2.fiyat2)) AS sonuc
FROM tablo1 INNER JOIN
tablo2 ON tablo1.tarih1 = tablo2.tarih2
GROUP BY tablo1.tarih1
With the table structure being as it is, the query that can be written to get the desired result is:
SELECT t1.tarih1, (COALESCE(t1.fiyat1, 0) - COALESCE(t2.fiyat2, 0)) AS sonuc
FROM
(SELECT tarih1, SUM(fiyat1) AS fiyat1
FROM tablo1
GROUP BY tarih1
) AS t1
LEFT JOIN
(SELECT tarih2, SUM(fiyat2) AS fiyat2
FROM tablo2
GROUP BY tarih2
) AS t2
ON t1.tarih1 = t2.tarih2
ORDER BY t1.tarih1 DESC;
However, I'd like to offer a couple of suggestions:
It's generally a good idea to store the date in MySQL date format: YYYY-MM-DD. It'll be much easier for you to run yearly reports, if there ever was a need.
As far as book-keeping is concerned, maybe you'll find the following Q&A to be of your interest: What is a common way to save 'debit' and 'credit' information?
Not sure what exactly it is I should be looking for, so I'm reaching out for help.
I have two tables that through queries I need to spit out one. the two tables are as follows:
Transactions:
TransactionID SiteID EmployeeName
520 2 Michael
521 3 Gene
TransactionResponse:
TransactionID PromptMessage Response PromptID
520 Enter Odometer 4500 14
520 Enter Vehicle ID 345 13
521 Enter Odometer 5427 14
521 Enter Vehicle ID 346 13
But what I need is the following, let's call it TransactionSummary:
TransactionID SiteID EmployeeName 'Odometer' 'VehicleID'
520 2 Michael 4500 345
521 3 Gene 5427 346
The "PromptID" column is the number version of "PromptMessage" so I could query off that if it's easier.
A good direction for what this query would be called is the least I'm hoping for. True extra credit for working examples or even using this provided example would be awesome!
For a predefined number of possible PromptID values you can use something like the following query:
SELECT t.TransactionID, t.SiteID, t.EmployeeName,
MAX(CASE WHEN PromptID = 13 THEN Response END) AS 'VehicleID',
MAX(CASE WHEN PromptID = 14 THEN Response END) AS 'Odometer'
FROM Transactions AS t
LEFT JOIN TransactionResponse AS tr
ON t.TransactionID = tr.TransactionID AND t.SiteID = tr.SiteID
GROUP BY t.TransactionID, t.SiteID, t.EmployeeName
The above query uses what is called conditional aggregation: a CASE expression is used within an aggregate function, so as to conditionally account for a subset of records within a group.
I normally work in Access but cannot figure this logic within it. I'm now branching to MySQL in hopes i can do this.
Have table Visits with CUSTOMERID, VISITDATE
CUSTOMERID VISITDATE
1001 7/6/2015
2315 9/1/2015
2315 12/30/2014
9851 5/5/2013
9851 1/7/2014
9851 3/21/2014
I'd like to add a column called 'Visit Number' so I can label in ascending order each Customer's visitdate as his first, second, etc...
It would look like:
CUSTOMERID VISITDATE VISITNUMBER
1001 7/6/2015 1
2315 9/1/2015 1
2315 12/30/2014 2
9851 5/5/2013 1
9851 1/7/2014 2
9851 3/21/2014 3
It's an incrementation based on the ascending dates, but also grouped by CUSTOMERID.
Would seriously appreciate any tips on this. Thanks.
OK. So you have a query that you use to update your date whenever someone visits.
You want to cause an additional action at this point because this equates to an increment of visits.
if I'm not incorrect, a simple bundle of:
YOUR UPDATE SQL;
UPDATE mytable
SET visitnumber = visitnumber + 1
WHERE customerid = (the id of the user you are updating);