I have a table with some records now want to repeat this table content with some logic. I have two date start date and termination date, means record start from start_date and end on termination date, it will working fine but problem is calculate amount on it,
Logic is amount calculation formula
basesalary / 12 * ( SUTARate / 100 ) * ( x.num+1)
if this amount is less than SUTAMaximumAmount this amount is used, else 0. And one more thing if amount will be remain and year is complete then restart calculation from next year.. x.num is temporary table which hold 90 number from 1 to 90
Table
BaseSalary| S_Date | T_Date | SUTARate| SUTAMaximumAmount |A_S_Percent
48000 | 7-1-2013 | 3-15-2015 | 1.1 | 300 | 5
My result is
DAte amount
2013-07-01 00:00:00.000 44
2013-08-01 00:00:00.000 44
2013-09-01 00:00:00.000 44
2013-10-01 00:00:00.000 44
2013-11-01 00:00:00.000 44
2013-12-01 00:00:00.000 44
2014-01-01 00:00:00.000 36
2014-02-01 00:00:00.000 -8
2014-03-01 00:00:00.000 -52
2014-04-01 00:00:00.000 -96
2014-05-01 00:00:00.000 -140
2014-06-01 00:00:00.000 -184
2014-07-01 00:00:00.000 -228
2014-08-01 00:00:00.000 -272
2014-09-01 00:00:00.000 -316
2014-10-01 00:00:00.000 -360
2014-11-01 00:00:00.000 -404
2014-12-01 00:00:00.000 -448
2015-01-01 00:00:00.000 -492
2015-02-01 00:00:00.000 -536
2015-03-01 00:00:00.000 -580
and I want result like this
Date | Amount
7-1-2013 44
8-1-2013 44
9-1-2013 44
10-1-2013 44
11-1-2013 44
12-1-2013 44
1-1-2014 44
2-1-2014 44
3-1-2014 44
4-1-2014 44
5-1-2014 44
6-1-2014 44
7-1-2014 36
1-1-2015 44
2-1-2015 44
3-1-2015 44
Query
SELECT dateadd(M, (x.num),d.StartDate) AS TheDate,
Round( case when ((convert(float,d.SUTARate)/100* convert(integer,d.BaseSalary) / 12)*(x.num+1)) <=CONVERT(money,d.SUTAMaximumAmount)
then (convert(float,d.SUTARate)/100* convert(integer,d.BaseSalary)* / 12)
else (CONVERT(money,d.SUTAMaximumAmount)-((convert(float,d.SUTARate)/100* (convert(integer,d.BaseSalary) / 12)*x.num)))*Power((1+convert(float,d.AnnualSalaryIncreasePercent)/100),Convert(int,x.num/12)) end, 2) AS Amount,
FROM #Table AS x, myTbl AS d
WHERE (x.num >= 0) AND (x.num <= (DateDiff(M, d.StartDate, d.TerminationDate)) )
temporary table
create TABLE #Table (
num int NOT NULL,
);
;WITH Nbrs ( n ) AS (
SELECT 0 UNION ALL
SELECT 1 + n FROM Nbrs WHERE n < 99 )
INSERT #Table(num)
SELECT n FROM Nbrs
OPTION ( MAXRECURSION 99 )
this table used as x in above query
I created this SQLFiddle.
-- Numbers table is probably a good idea
WITH Nbrs ( num ) AS
(
SELECT 0 UNION ALL
SELECT 1 + num FROM Nbrs WHERE num < 99
)
-- All columns, except for 'num' come from myTbl
SELECT dateadd(M, (num),S_Date) AS TheDate,
Round(
CASE
WHEN (SUTARate / 100) * (BaseSalary / 12) <= SUTAMaximumAmount
THEN (SUTARate / 100) * (BaseSalary / 12)
ELSE 0
END
, 2) As Amount
-- This may be the number you were trying to multiply
,DatePart(Month, dateadd(M, (num),S_Date)) As PotentialMultiiplier
FROM Nbrs AS x, myTbl AS d
WHERE (num >= 0)
AND (num <= (DateDiff(M, S_Date, T_Date)) )
I am not entirely sure what your goal is, but you are probably on the right track with a numbers table. Because the result you are going for does not change much over time (i.e., nearly every month has an amount of $44), it is difficult to determine the correct code for the query. So, I recommend you provide a different set of data for better result-checking.
If you fiddle with the SQL in the provided link, you can re-post with better code, and then we can better solve your issue.
Related
Here is my query , I have a column called cum_balance which is supposed to calculate the cumulative balance but after row number 10 there is an anamoly and it doesn't work as expected , all I notice is that from row number 10 onwards the hour column has same value. What's the right syntax for this?
[select
hour,
symbol,
amount_usd,
category,
sum(amount_usd) over (
order by
hour asc RANGE BETWEEN UNBOUNDED PRECEDING
AND CURRENT ROW
) as cum_balance
from
combined_transfers_usd_netflow
order by
hour][1]
I have tried removing RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW , adding a partition by hour and group by hour. None of them gave the expected result or errors
Row Number
Hour
SYMBOL
AMOUNT_USD
CATEGORY
CUM_BALANCE
1
2021-12-02 23:00:00
WETH
227.2795
in
227.2795
2
2021-12-03 00:00:00
WETH
-226.4801153
out
0.7993847087
3
2022-01-05 21:00:00
WETH
5123.716203
in
5124.515587
4
2022-01-18 14:00:00
WETH
-4466.2366
out
658.2789873
5
2022-01-19 00:00:00
WETH
2442.618599
in
3100.897586
6
2022-01-21 14:00:00
USDC
99928.68644
in
103029.584
7
2022-03-01 16:00:00
UNI
8545.36098
in
111574.945
8
2022-03-04 22:00:00
USDC
-2999.343
out
108575.602
9
2022-03-09 22:00:00
USDC
-5042.947675
out
103532.6543
10
2022-03-16 21:00:00
USDC
-4110.6579
out
98594.35101
11
2022-03-16 21:00:00
UNI
-3.209306045
out
98594.35101
12
2022-03-16 21:00:00
UNI
-16.04653022
out
98594.35101
13
2022-03-16 21:00:00
UNI
-16.04653022
out
98594.35101
14
2022-03-16 21:00:00
UNI
-16.04653022
out
98594.35101
15
2022-03-16 21:00:00
UNI
-6.418612089
out
98594.35101
The "problem" with your data in all the ORDER BY values after row 10 are the same.
So if we shrink the data down a little, and use for groups to repeat the experiment:
with data(grp, date, val) as (
select * from values
(1,'2021-01-01'::date, 10),
(1,'2021-01-02'::date, 11),
(1,'2021-01-03'::date, 12),
(2,'2021-01-01'::date, 20),
(2,'2021-01-02'::date, 21),
(2,'2021-01-02'::date, 22),
(2,'2021-01-04'::date, 23)
)
select d.*
,sum(val) over ( partition by grp order by date RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) as cum_val_1
,sum(val) over ( partition by grp order by date ) as cum_val_2
from data as d
order by 1,2;
we get:
GRP
DATE
VAL
CUM_VAL_1
CUM_VAL_2
1
2021-01-01
10
10
10
1
2021-01-02
11
21
21
1
2021-01-03
12
33
33
2
2021-01-01
20
20
20
2
2021-01-02
21
63
63
2
2021-01-02
22
63
63
2
2021-01-04
23
86
86
we see with group 1 that values accumulate as we expect. So for group 2 we put duplicate values as see those rows get the same value, but rows after "work as expected again".
This tells us how this function work across unstable data (values that sort the same) is that they are all stepped in one leap.
Thus if you want each row to be different they will need better ORDER distinctness. This could be forced by add random values of literal random nature, or feeling non random ROW_NUMBER, but really they would be random, albeit not explicit, AND if you use random, you might get duplicates, thus really should use ROW_NUMBER or SEQx to have unique values.
Also the second formula shows they are equal, and it's the ORDER BY problem not the framing of "which rows" are used.
with data(grp, date, val) as (
select * from values
(1,'2021-01-01'::date, 10),
(1,'2021-01-02'::date, 11),
(1,'2021-01-03'::date, 12),
(2,'2021-01-01'::date, 20),
(2,'2021-01-02'::date, 21),
(2,'2021-01-02'::date, 22),
(2,'2021-01-04'::date, 23)
)
select d.*
,seq8() as s
,sum(val) over ( partition by grp order by date ) as cum_val_1
,sum(val) over ( partition by grp order by date, s ) as cum_val_2
,sum(val) over ( partition by grp order by date, seq8() ) as cum_val_3
from data as d
order by 1,2;
gives:
GRP
DATE
VAL S
CUM_VAL_1
CUM_VAL_2
CUM_VAL_2_2
1
2021-01-01
10
0
10
10
1
2021-01-02
11
1
21
21
1
2021-01-03
12
2
33
33
2
2021-01-01
20
3
20
20
2
2021-01-02
21
4
63
41
2
2021-01-02
22
5
63
63
2
2021-01-04
23
6
86
86
I am trying to eliminate the data anomalies in the data I am receiving from eventhub and send only selected data to azure functions through Azure stream analytics for that I am writing a sql query where I need some help
Requirement: I need to collect the past 60 seconds data and need to group by Id and compare the records that I received in the 60 seconds and If any record value is way higher than the selected values than ignore that record (for example, I will collect the 4 records in past 60 seconds and if the data is 40 40 40 40 5. We should drop the 5. Example 2 - 20 20 20 500 drop the 500. ).
My sql table will be something like this:
id Temp date datetime
123 30 2023-01-01 2023-01-01 12:00:00
124 35 2023-01-01 2023-01-01 12:00:00
123 31 2023-01-01 2023-01-01 12:00:00
123 33 2023-01-01 2023-01-01 12:00:00
123 60 2023-01-01 2023-01-01 12:00:00
124 36 2023-01-01 2023-01-01 12:00:00
124 36 2023-01-01 2023-01-01 12:00:00
124 8 2023-01-01 2023-01-01 12:00:00
124 36 2023-01-01 2023-01-01 12:00:00
I need to eliminate the records that are not in the range with the other records
I'll leave the details of the comparison up to you, but you can use a CROSS APPLY to gather the data for comparison.
Something like:
SELECT *
FROM TemperatureData T
CROSS APPLY (
SELECT AVG(T2.Temp * 1.0) AS PriorAvgTemp, COUNT(*) As PriorCount
FROM TemperatureData T2
WHERE T2.id = T.id
AND T2.datetime >= DATEADD(second, -60, T.datetime)
AND T2.datetime < T.datetime
) P
WHERE T.Temp BETWEEN P.PriorAvgTemp - 10 AND P.PriorAvgTemp + 10
--OR P.PriorCount < 3 -- Should we allow if there is insufficient prior data
--AND P.PriorCount >= 3 -- Should we omit if there is insufficient prior data
Be sure you have an index on TemperatureData(id, datetime).
If you are willing to accept the last N values instead of a time range, windowed aggregate calculation may be more efficient.
SELECT *
FROM (
SELECT *,
AVG(T.Temp * 1.0)
OVER(PARTITION BY id ORDER BY datetime
ROWS BETWEEN 60 PRECEDING AND 1 PRECEDING)
AS PriorAvgTemp,
COUNT(*)
OVER(PARTITION BY id ORDER BY datetime
ROWS BETWEEN 60 PRECEDING AND 1 PRECEDING)
AS PriorCount
FROM TemperatureData T
) TT
WHERE TT.Temp BETWEEN TT.PriorAvgTemp - 10 AND TT.PriorAvgTemp + 10
--OR TT.PriorCount < 3 -- Should we allow if there is insufficient prior data
--AND TT.PriorCount >= 3 -- Should we omit if there is insufficient prior data
Please note: The above is untested code, which may need some syntax fixes and debugging. If you discover errors, please comment and I will correct the post.
Good day,
I have been wracking my brain for the past few hours to build a table that looks like this:
I have about 33 000 entries that have their own opening and closing dates. I am trying to build a table that puts each of the dates (including the opening and closing dates) in a single row per entry (JOURNAL_NO) below each other in SQL Server Management Studio.
I need to run a check on each day for each entry and I have tried to build the table by making use of my primary table and a calendar table that I created. Please refer to the code below (I have also included the calendar code below this):
Code I'm trying to get working:
DECLARE #START_DATE date = '2014-01-01',
#END_DATE date = '2018-12-31'
WHILE #START_DATE <= #END_DATE
BEGIN
SET #START_DATE = DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY N) - 1, #START_DATE)
SELECT LO_MASTER.JOURAL_NO, --(33000 entries)
LO_MASTER.START_DATE, -- each entry has a different opening date
CAL.DATE -- date in calendar table
CAL.DAY AS DATEPART(DAY,[DATE]),
CAL.MONTH AS DATEPART(MONTH,[DATE]),
CAL.YEAR AS DATEPART(YEAR,[DATE]), -- these will be the date parts between the OPEN_DATE & CLOSE_DATE for each account
LO_MASTER.END_DATE -- each entry has a different closing date
FROM [dbo.][F1_master] as LO_MASTER
inner join CALENDAR_TABLE as CAL LO_MASTER.DATE = CAL.DATE
WHERE CAL.DATE between LO_MASTER.START_DATE and LO_MASTER.END_DATE -- range where the fields from table b need to be populated for each account
END
Table definition:
USE [master]
GO
/****** Object: Table [dbo].[dummy_data] Script Date: 11/02/2019 07:31:59 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[dummy_data](
[JOURNAL_NO] [int] NULL,
[START_DATE] [date] NULL,
[END_DATE] [date] NULL,
[DURATION_ON_BOOK] [int] NULL
) ON [PRIMARY]
GO
Sample data:
JOURNAL_NO START_DATE END_DATE DURATION_ON_BOOK
101388 15/01/2014 01/01/2017 35
101499 14/01/2014 21/01/2017 36
101502 17/01/2014 17/02/2017 53
101876 06/01/2014 30/09/2017 35
101877 06/01/2014 24/01/2018 60
101878 07/01/2014 28/02/2018 60
101879 07/01/2014 19/01/2017 50
101881 07/01/2014 16/04/2018 58
101882 07/01/2014 13/11/2018 58
101883 08/01/2014 17/11/2016 59
101884 13/01/2014 26/06/2018 60
101886 13/01/2014 20/12/2016 59
101887 13/01/2014 13/12/2016 60
101888 13/01/2014 11/09/2017 43
101889 14/01/2014 07/12/2017 68
101890 14/01/2014 02/01/2018 58
101892 15/01/2014 21/02/2017 38
101893 17/01/2014 15/09/2017 64
101894 21/01/2014 02/02/2017 40
101896 21/01/2014 09/05/2016 38
101904 27/01/2014 21/12/2016 69
101906 27/01/2014 11/11/2016 36
101966 07/01/2014 10/03/2017 36
101967 07/01/2014 09/07/2018 40
102073 07/01/2014 15/09/2016 60
102074 13/01/2014 20/06/2017 40
102076 14/01/2014 15/06/2016 40
102077 15/01/2014 01/12/2016 60
102079 17/01/2014 12/10/2016 40
102081 21/01/2014 20/04/2017 40
102082 23/01/2014 14/02/2017 38
102234 02/01/2014 20/09/2017 46
102236 08/01/2014 05/05/2017 36
102237 15/01/2014 23/08/2017 68
102240 21/01/2014 27/02/2018 50
102241 21/01/2014 25/08/2016 37
102253 06/01/2014 26/10/2016 27
102254 07/01/2014 17/11/2016 61
102255 07/01/2014 26/04/2017 38
102256 10/01/2014 11/10/2017 42
102258 13/01/2014 18/05/2017 26
102263 17/01/2014 29/11/2018 74
102265 20/01/2014 31/10/2016 31
102372 06/01/2014 25/04/2017 35
102463 09/01/2014 25/08/2017 69
102464 09/01/2014 01/07/2016 26
102465 15/01/2014 24/12/2016 36
102530 06/01/2014 24/12/2017 48
102531 07/01/2014 28/08/2017 76
102532 09/01/2014 21/06/2017 39
Could anyone please assist me? I haven't been coding that long and my troubleshoot attempts aren't providing any correct solutions. It would be greatly appreciated.
Thank you.
Using a tally table this is pretty simple. I keep one on my system as a view that is lightning fast because it doesn't need any disc I/O at all. It look amazingly similar to what you had posted initially.
create View [dbo].[cteTally] as
WITH
E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
cteTally(N) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
)
select N from cteTally
GO
Next we need some sample data. I stripped this down to just a couple of journals to demonstrate.
declare #dummy_data table
(
JOURNAL_NO int
, START_DATE datetime
, END_DATE datetime
, DURATION_ON_BOOK int
)
insert #dummy_data values
(101388, '20140115', '20170101', 35)
, (101499, '20160114', '20170121', 36)
Now we just need to leverage the power of a tally table with your data. This is what your query might look like. No need for loops, just some basic date math.
select *
, EachDay = dateadd(day, t.N - 1, d.Start_Date)
, MyDay = t.N
, MyMonth = datediff(month, d.Start_DATE, dateadd(day, t.N - 1, d.Start_Date)) + 1
, MyYear = datepart(year, dateadd(day, t.N - 1, d.Start_Date))
from #dummy_data d
join cteTally t on t.N <= datediff(day, d.START_DATE, d.END_DATE) + 1
I have a problem. I have table with following columns and sample data:
RN Date Time
---------------------
1 2015-02-02 12
2 2015-02-02 25
3 2015-02-02 27
1 2015-02-08 42
2 2015-02-08 45
1 2015-03-01 60
2 2015-03-01 62
3 2015-03-01 63
4 2015-03-01 63
I need get a difference between time start and time end of every day.
For example:
27-12
45-42
63-60
Any suggestions? :)
select
Date, max(Time) as mx, min(Time) as mn, max(Time) - min(Time) as diff
from table_name
group by Date
Hello currently I have a working script below. I am using Oracle 10
SELECT z.no as "ID_One",
MAX(r.value) as "Max",
round(MAX(r.value)/80000,2) as "ROUND"
FROM Table1 r, Table2 z
WHERE r.timestamp > ((SYSDATE - TO_DATE('01/01/1970 00:00:00', 'MM-DD-YYYY HH24:MI:SS')) * 24 * 60 * 60) - 80000
AND r.va=21
AND r.nor IN ('7','98','3','3')
AND r.nor = z.re
GROUP BY r.nor, r.varr, z.no;
It produces a table like this
ID_ONE MAX ROUND
105 500 232
106 232 32
333 23 .21
444 34 .321
I want to select a row call timestamp from table r. However when I add " r.timestamp " in to my query it produces 500 rows of data instead of 4. It looks like it is producing the the highest number for each timestamp instead. How would I produce a table that looks like this ? fyi timestamp column is in unix time. I can do the conversion myself. I just need to know how to get out these rows.
ID_ONE MAX ROUND TIMESTAMP
105 500 232 DEC 21,2021 10:00
106 232 32 DEC 21,2021 23:12
333 23 .21 DEC 31,2021 2:12
444 34 .321 DEC 31,2021 23:12
When I add the column time stamp it does not create what is above. What I am getting instead is something like that looks like this the other two ids are below in this 500 long row of data. I only wanted the 4 that is the highest value (MAX) from this set of time. ID_ONE is my id for a stock of inventory for a warehouse.
ID_ONE ROUND TIMESTAMP MAX
106 338
.06 1406694567
106 355
.06 1406696037
106 246
.04 1406696337
106 363
.06 1406700687
106 330
.06 1406700987
106 512
.09 1406701347
106 459
.08 1406704047
106 427
.07 1406711038
106 596
.1 1406713111
106 401
.07 1406715872
106 682
.11 1406726192
106 2776
.46 1406726492
105 414
.07 1406728863
105 380
.06 1406734055
105 378
.06 1406734655
105 722
.12 1406735555
105 144
.02 1406665697
105 5
I have edited my answer kindly try the below
SELECT z.no as "ID_One",
max(r.value) as "Max",
round(MAX(r.value)/80000,2) as "ROUND",r.Timestamp
FROM Table1 r, Table2 z
where r.timestamp > ((SYSDATE - TO_DATE ('01/01/1970 00:00:00', 'MM
-DD-YYYY HH24:MI:SS')) * 24 * 60 * 60) - 80000
and r.va=21
AND r.nor IN ('7','98','3','3')
AND r.value=(select max(r1.value) from Table1 r1 where r1.va=r.va and r1.nor=r.nor)
AND r.nor = z.re group by r.nor, r.varr, z.no;
This looks like an ideal use case for analytic functions:
SELECT
v1.*,
round(v1.value/80000,2) as rounded_max_value
FROM (
SELECT
z.no as id_one,
r.value,
row_number() over (partition by r.nor, r.varr, z.no order by r.value desc) as rn,
r.timestamp
FROM Table1 r, Table2 z
WHERE r.timestamp >
((SYSDATE - TO_DATE('01/01/1970 00:00:00', 'MM-DD-YYYY HH24:MI:SS')) * 24 * 60 * 60) - 80000
AND r.va=21
AND r.nor IN ('7','98','3','3')
AND r.nor = z.re
) v1
where v1.rn = 1
This query
uses row_number over (partition by .. order by ) to get an ordering of the rows within a group
uses rn = 1 in the outer query to get only the row having the maximum value
Some additional recommendations:
if your r.nor column is numeric, then don't use string literals; use IN (7,98,3,3) instead (BTW: why do you have 3 twice in your IN list?
don't use " for column aliases unless absolutely necessary (since it makes them case-sensitive) ; they are a PITA
don't put your JOIN conditions into the WHERE clause; it makes your query harder to read. Use ANSI style joins instead.