Cumulative Adding in SQL SERVER 2008 - sql-server-2008

This is what i have got in my SQL SERVER database table, where I am trying to calculate Balance Leave of an employee.
My actual data is:
EmpId EmpName EvalDate OpeningEL EnjoyedEL BalanceEL
12 CHANDRA 2014-04-01 18:30:00.000 0.95 0.00 0.95
12 CHANDRA 2014-05-01 18:30:00.000 1.30 0.00 1.30
12 CHANDRA 2014-06-01 18:30:00.000 1.20 1.00 1.20
12 CHANDRA 2014-07-01 18:30:00.000 1.25 0.00 1.25
12 CHANDRA 2014-08-01 18:30:00.000 1.25 1.00 1.25
But i need the data in below way
EmpId EmpName EvalDate OpeningEL EnjoyedEL BalanceEL
12 CHANDRA 2014-04-01 18:30:00.000 0.95 0.00 0.95
12 CHANDRA 2014-05-01 18:30:00.000 2.25 0.00 2.25
12 CHANDRA 2014-06-01 18:30:00.000 3.45 1.00 2.45
12 CHANDRA 2014-07-01 18:30:00.000 3.70 0.00 3.70
12 CHANDRA 2014-08-01 18:30:00.000 4.95 1.00 3.95
Previous BalanceELs are added with next OpeningELs.
So, how to achieve this....Please suggest something.

You can use CROSS APPLY and GROUP BY to achieve this
OpeningEL and BalanceEL from CROSS APPLY will get the sum of current and previous records for an employee.
SELECT
EL1.EmpId,
EL1.EmpName,
EL1.EvalDate,
Temp.OpeningEL,
EL1.EnjoyedEL,
Temp.BalanceEL
FROM EmployeeLeave EL1
CROSS APPLY
(
SELECT
SUM(OpeningEL) as OpeningEL,
SUM(BalanceEL) - SUM(EnjoyedEL) as BalanceEL
FROM EmployeeLeave EL2
WHERE EL2.EmpId = EL1.EmpId
AND EL2.EvalDate <= EL1.EvalDate
)Temp;

Related

Create view with delta for each column in SQL

I have a table named pwrDay containing electric index counters (always growing).
jour
pwrconsohp
pwrconsohc
pwrprod
pwrprodmax
2021-09-26
35 736 527
18 073 331
12 629 677
0
2021-09-27
35 754 125
18 073 331
12 637 154
0
2021-09-28
35 780 113
18 073 331
12 646 963
0
2021-09-29
35 807 081
18 073 331
12 657 084
0
2021-09-30
35 833 193
18 073 331
12 668 804
0
2021-10-01
35 861 259
18 073 331
12 682 444
0
2021-10-02
35 888 342
18 073 331
12 693 908
0
2021-10-03
35 917 218
18 073 331
12 704 696
0
2021-10-04
35 944 869
18 073 331
12 706 056
0
2021-10-05
35 972 043
18 073 331
12 708 309
0
I need to extract the difference between previous and current row (maybe create a view?) The following query works for most days, but it's wrong every first day of month (or if I miss a control day):
SELECT pwr.jour,
(pwr.pwrconsoHP-ifnull(oldpwr.pwrconsoHP, 0)) as deltaconsoHP,
(pwr.pwrconsoHC-ifnull(oldpwr.pwrconsoHC, 0)) as deltaconsoHC,
(pwr.pwrProd-ifnull(oldpwr.pwrProd, 0)) as deltaProd
FROM pwrDay pwr
LEFT OUTER JOIN pwrDay oldpwr ON
(day(pwr.jour)-day(oldpwr.jour)=1 AND MONTH(pwr.jour)=MONTH(oldpwr.jour))
ORDER BY jour;
I also tried this query:
SELECT pwr.jour,
(pwr.pwrconsoHP-LAG(pwr.pwrconsoHP, 0)) as deltaconsoHP,
(pwr.pwrconsoHC-LAG(pwr.pwrconsoHC, 0)) as deltaconsoHC,
(pwr.pwrProd-LAG(pwr.pwrProd, 0)) as deltaProd
FROM pwrDay pwr
ORDER BY jour;
However, it doesn't run at all. I get this error message:
Erreur SQL (1305) : FUNCTION velbus.LAG does not exist
How can I write this query?
SELECT pwr.jour,
(pwr.pwrconsoHP-LAG(pwr.pwrconsoHP, 0) OVER(order by jour)) as deltaconsoHP,
(pwr.pwrconsoHC-LAG(pwr.pwrconsoHC, 0) OVER(order by jour)) as deltaconsoHC,
(pwr.pwrProd-LAG(pwr.pwrProd, 0) OVER(order by jour)) as deltaProd
FROM pwrDay pwr
ORDER BY jour;
give it a try ...

Anomaly in Mysql query

This is not my query, its a query that someone wrote that i am now working with.
I have a database like so
id date high low open close open_id close_id
1 2009-05-01 00:00:00 0.729125 0.729225 0.72889 0.72889 1 74
2 2009-05-01 00:01:00 0.72888 0.728895 0.72883 0.72887 75 98
3 2009-05-01 00:02:00 0.728865 0.72889 0.72881 0.72888 99 121
4 2009-05-01 00:03:00 0.72891 0.72901 0.72891 0.729 122 141
5 2009-05-01 00:04:00 0.728975 0.729115 0.728745 0.72878 142 225
6 2009-05-01 00:05:00 0.728785 0.72882 0.72867 0.72882 226 271
7 2009-05-01 00:06:00 0.72884 0.72887 0.728735 0.728785 272 293
8 2009-05-01 00:07:00 0.728775 0.728835 0.72871 0.728835 294 317
9 2009-05-01 00:08:00 0.728825 0.72899 0.728795 0.72897 318 338
10 2009-05-01 00:09:00 0.72898 0.729255 0.72898 0.72922 339 383
11 2009-05-01 00:10:00 0.72922 0.729325 0.72908 0.729105 384 437
12 2009-05-01 00:11:00 0.729115 0.72918 0.728635 0.72905 438 553
(this is 12 out of about 200k rows)
This is my query
SELECT x.date, t.high, t.low, t.open, t.close, x.open_id, x.close_id from (SELECT MIN(`date`) as `date`, MAX(`close_id`) as `close_id`, MIN(`open_id`) as `open_id`
FROM `AUDNZD_minutes`
WHERE `date` >= '2011-03-07 00:00:00' and `date` < '2011-03-11 12:00:00'
GROUP BY round(UNIX_TIMESTAMP(date) / 600) order by `date`) as x inner join `AUDNZD_minutes` as t on x.close_id = t.close_id
It is selecting rows from that data base in 10 minute intervals. However I always have this Anomaly.
2011-03-07 00:00:00 1.3761 1.375595 1.375815 1.37589 55180489 55181083
2011-03-07 00:05:00 1.376055 1.37568 1.375925 1.37594 55181084 55181751
2011-03-07 00:15:00 1.37609 1.375835 1.375835 1.37606 55181752 55182003
2011-03-07 00:25:00 1.37578 1.37526 1.375505 1.375555 55182004 55182615
2011-03-07 00:35:00 1.374645 1.374455 1.374535 1.374645 55182616 55183178
2011-03-07 00:45:00 1.37463 1.373775 1.374085 1.374025 55183179 55183820
You can see that the diffrence between the first row and the second is 5 minutes and everythign after this is 10 minutes. this happens with any interval i try.
For example, 20 miunte intervals
2011-03-07 00:00:00 1.376155 1.375915 1.37594 1.376025 55180489 55181434
2011-03-07 00:10:00 1.376105 1.37592 1.37593 1.376085 55181435 55182273
2011-03-07 00:30:00 1.374025 1.37388 1.373965 1.37401 55182274 55183429
2011-03-07 00:50:00 1.373895 1.373595 1.37365 1.373595 55183430 55184894
2011-03-07 01:10:00 1.37382 1.373505 1.37373 1.373715 55184895 55185885
2011-03-07 01:30:00 1.373305 1.373025 1.373265 1.373055 55185886 55187306
How can i correct this query?
round function rounds numbers using basic math rules you probably learned in primary:
select FROM_UNIXTIME(round(UNIX_TIMESTAMP('2009-05-01 00:04:00') / 600) *600) from dual;
results with 2009-05-01 00:00:00 and
select FROM_UNIXTIME(round(UNIX_TIMESTAMP('2009-05-01 00:06:00') / 600) *600) from dual;
results with 2009-05-01 00:10:00, so you will always (on the provided dataset) have half of the interval in the first line if you keep using it.
Consider ceil or floor functions instead.
As a side note, #Strawberry made a point. Try to use anything like http://sqlfiddle.com/ to show some efforts in asking question at least.

Calculation to be made while updating a field

Origin Dest Date Amount 50% Due
92509 0021 2013-07-30 00:00:00.000 5.37 0.00
92509 0021 2013-07-30 00:00:00.000 5.37 0.00
92509 0021 2013-07-30 00:00:00.000 5.37 0.00
92509 0021 2013-07-31 00:00:00.000 5.37 2.69
92509 0021 2013-07-31 00:00:00.000 5.37 2.69
92509 0021 2013-07-31 00:00:00.000 5.37 2.69
92509 0021 2013-08-01 00:00:00.000 5.37 2.69
92509 0021 2013-08-01 00:00:00.000 5.37 2.69
42101 0029 2013-03-06 00:00:00.000 6.06 0.00
42101 0029 2013-03-06 00:00:00.000 6.06 0.00
42101 0029 2013-03-07 00:00:00.000 6.06 3.03
42101 0029 2013-03-07 00:00:00.000 6.06 3.03
42101 0030 2013-03-06 00:00:00.000 6.06 0.00
42101 0030 2013-03-06 00:00:00.000 6.06 0.00
42101 0030 2013-03-07 00:00:00.000 6.06 3.03
42101 0030 2013-03-07 00:00:00.000 6.06 3.03
So I have a table something similar to what i shown above. Right now, the 50% Due field is empty. I need to fill that field with values as shown above.
The 50% due field should populate values that are half of what is present in the Amount field. But, it should fill zero for the initial date (2013-07-30 00:00:00.000) and for the consecutive days it should fill half of what is present in the Amount field.
I have a lot of rows like these that needs to get updated. Also there are rows with different Origin and Destination.
I am dealing with some freight parcels. The data describes the parcels that were sent to the same destination from same origin on consecutive days. The parcels that were sent on consecutive days could have been sent together on the initial date itself. So I am trying to generate a claim for those parcels that were sent on consecutive days to the same destination from the same origin. And the 50% Due would be the claim!
I am fairly new to SQL! This seems to be very complicated for me. Please help.
If you want to update all origin/dest combinations that had an entry on the prior day then you can do this:
update t
set [50% due]=coalesce(cast(p.amount/2.0 as smallmoney),0.00)
from [table] t
left join [table] p
on t.origin=p.origin and t.dest=p.dest
and dateadd(D,-1,cast(t.[date] as date))=cast(p.[date] as date)
or use a cte and LAG in SQL 2012 and later versions:
;with previous as
(
select origin,dest,[date]
,LAG(cast([date] as date),1,cast([date] as date)) OVER (PARTITION BY origin,dest ORDER BY cast([date] as date)) as previous
from (select distinct origin, dest, [date]
from [table]) a
)
update t
set [50% Due]=case when dateadd(D,-1,cast(t.[date] as date))<>cte.previous then 0.00 else cast(t.[amount]/2.0 as smallmoney) end
from [table] t
join previous cte
on cte.origin=t.origin and cte.dest=t.dest and cte.[date]=t.[date]
If you want to update all your records based on the earliest day that the origin/dest combination occurred, then this will work in SQL Server:
;with earliest as
(
select origin,dest,min(cast([date] as date)) earliest
from [table]
group by origin,dest
)
update t
set [50% Due]=case when cast(t.[date] as date)=cte.earliest then 0.00 else cast(t.[amount]/2.0 as smallmoney) end
from [table] t
join earliest cte
on cte.origin=t.origin and cte.dest=t.dest
If you want to update all your records only based on the earliest day in the table and you don't care about the orgin/dest combination then you don't need the cte to group the earliest dates and you can simply do the compare in the update.
UPDATE t
set [50% Due]=case when cast(t.[date] as date)=(select min(cast(t.date as date))) then 0.00 else cast(t.[amount]/2.0 as smallmoney) end

How to first order by column A, return a top-3, then order the result by column B in one query?

(Please refer to SQLFiddle for a working example of this post)
I have a table with stock information, as follows:
sp100_id _date bullishness agreement
----------------------------------------------
1 2011-03-16 1.01 0.33
1 2011-03-17 0.85 1.28
1 2011-03-18 0.89 1.25
1 2011-03-21 1.46 1.21
1 2011-03-22 0.39 2.53
2 2011-03-16 3.07 1.27
2 2011-03-17 2.09 0.80
2 2011-03-18 0.91 0.12
2 2011-03-21 1.50 0.00
2 2011-03-22 2.62 1.10
3 2011-03-16 0.73 1.13
3 2011-03-17 1.13 1.21
3 2011-03-18 1.12 0.45
3 2011-03-21 1.00 1.01
3 2011-03-22 1.00 0.53
4 2011-03-16 0.40 1.10
4 2011-03-17 2.40 0.03
4 2011-03-18 3.16 0.10
4 2011-03-21 0.86 0.50
4 2011-03-22 1.00 0.10
I need to order the companies (sp100_id) by their averge bullishness over time into a top-3:
SELECT
sp100_id,
AVG(bullishness) as bullishness,
AVG(agreement) AS agreement
FROM stocks
WHERE _date BETWEEN '2011-03-16' AND '2011-03-22'
GROUP BY sp100_id LIMIT 3
This works fine, as the result is
SP100_ID BULLISHNESS AGREEMENT
2 2.038 0.658
4 1.564 0.366
3 0.996 0.866
Now that I have the top-3, I need the top-3 to be re-ordered by AGREEMENT, ascending:
SP100_ID BULLISHNESS AGREEMENT
4 1.564 0.366
2 2.038 0.658
3 0.996 0.866
Is this possible to do with one query? I tried the following but it didn't work. It still only orders by bullishness
SELECT
sp100_id,
AVG(bullishness) as bullishness,
AVG(agreement) AS agreement
FROM stocks
WHERE _date BETWEEN '2011-03-16' AND '2011-03-22'
GROUP BY sp100_id
ORDER BY bullishness DESC, agreement ASC LIMIT 3
So to be clear: (1) I need to find the top-3 companies with highest average bullsihness (2) this top-3 then needs to be ordered from lowest to highest agreement. Preferably with one query. Do you know how?
It's called structured query language because you can build structures in which queries (aka virtual tables) are nested inside other queries.
Take your first query, which is correct except it needs its own ORDER BY clause, and nest it in another, like so.
SELECT *
FROM (
SELECT sp100_id,
AVG(bullishness) as bullishness,
AVG(agreement) AS agreement
FROM stocks
WHERE _date BETWEEN '2011-03-16' AND '2011-03-22'
GROUP BY sp100_id
ORDER BY bullishness DESC
LIMIT 3
) subquery
ORDER BY agreement ASC
Go fiddle: http://sqlfiddle.com/#!2/c9ff0/7/0

MySQL Count Numbers Are Off

I am not sure why my numbers are drastically off from each other.
A query with no max id:
SELECT id, DATE_FORMAT(t_stamp, '%Y-%m-%d %H:00:00') as date, COUNT(*) as count
FROM test_ips
WHERE id > 0
AND viewip != ""
GROUP BY HOUR(t_stamp)
ORDER BY t_stamp ASC;
I get:
1 2012-07-18 19:00:00 1313
106 2012-07-18 20:00:00 1567
107 2012-07-19 09:00:00 847
225 2012-07-19 10:00:00 5095
421 2012-07-19 11:00:00 205
423 2012-07-19 12:00:00 900
461 2012-07-19 13:00:00 619
490 2012-07-20 15:00:00 729
575 2012-07-20 16:00:00 1682
1060 2012-07-20 17:00:00 2063
2260 2012-07-20 18:00:00 1417
5859 2012-07-20 21:00:00 1303
7060 2012-07-20 22:00:00 1340
8280 2012-07-20 23:00:00 1211
9149 2012-07-21 00:00:00 1675
10418 2012-07-21 01:00:00 721
11127 2012-07-21 02:00:00 825
But if I add a max id:
AND id <= 8279
I get:
1 2012-07-18 19:00:00 1313
106 2012-07-18 20:00:00 1201
107 2012-07-19 09:00:00 118
225 2012-07-19 10:00:00 196
421 2012-07-19 11:00:00 2
423 2012-07-19 12:00:00 38
461 2012-07-19 13:00:00 20
490 2012-07-20 15:00:00 85
575 2012-07-20 16:00:00 483
1060 2012-07-20 17:00:00 1200
2260 2012-07-20 18:00:00 1200
5859 2012-07-20 21:00:00 1201
7060 2012-07-20 22:00:00 1220
The numbers are WAY off from each other. Something is goofy.
EDIT: Here is my table structure:
id t_stamp bID viewip unique
1 2012-07-18 19:22:20 5 192.168.1.1 1
2 2012-07-18 19:22:21 1 192.168.1.1 1
3 2012-07-18 19:22:22 5 192.168.1.1 0
4 2012-07-18 19:22:22 3 192.168.1.1 1
You are not grouping by ID and I think you intend to.
Try:
SELECT id, DATE_FORMAT(t_stamp, '%Y-%m-%d %H:00:00') as date, COUNT(*) as count
FROM test_ips
WHERE id > 0
AND viewip != ""
GROUP BY id, DATE_FORMAT(t_stamp, '%Y-%m-%d %H:00:00')
ORDER BY t_stamp;
Your query is not consistent.
In your select statement you are displaying the full date.
But you are grouping your data by the hour. So your count statement is taking the count of all the data for each hour of the day.
As an example take your first result:
1 2012-07-18 19:00:00 1313
The count of 1313 contains the records for all of your dates (7/18, 7/19, 7/20, 7/21, 7/22, etc) that have an hour of 19:00.
But the way you have your query setup, it looks like it should be the count of all records for 2012-07-18 19:00:00.
So when you add AND id <= 8279" The dates of 7/21 and some of 7/20 or no longer being counted so your count values are now lower.
I'm guessing you are meaning to group by the date and hour and not just the hour.