I have the data as below.
stock
datetime
AVG_Price
MF
NetMF
ABCD
2022-12-06 09:15:00
234.50
237864
237864
ABCD
2022-12-06 09:16:00
236.55
357784
595648
ABCD
2022-12-06 09:17:00
233.23
334959
260689
ABCD
2022-12-06 09:18:00
233.23
498756
759445
ABCD
2022-12-06 09:19:00
225.23
456789
302656
ABCD
2022-12-06 09:20:00
222.23
678546
-375890
ABCD
2022-12-06 09:21:00
222.23
567483
-943373
ABCD
2022-12-06 09:22:00
220.23
67483
-1010856
The desired output in NetMF
I want to calculate Net MF using below conditions.
At datetime 9:15, I will return MF value into Net MF
From 9:16 onwards below is the logic i want to follow
If AVG_Price at 9:16 > AVG_Price at 9:15 then Net MF at 9:16 = Net MF at 9:15 + MF at 9:16
If AVG_Price at 9:16 < AVG_Price at 9:15 then Net MF at 9:16 = Net MF at 9:15 - MF at 9:16
If AVG_Price at 9:16 = AVG_Price at 9:15 and Net MF at 9:15 < 0 then Net MF at 9:16 = Net MF at 9:15 - MF at 9:16
If AVG_Price at 9:16 = AVG_Price at 9:15 and Net MF at 9:15 >= 0 then Net MF at 9:16 = Net MF at 9:15 + MF at 9:16
This logic continues till the end of the time period.
I need this logic to work for Multiple stock codes and multiple datetimes.
Currently I have below code in place. This code returns only values for first 1 or 2 rows
WITH v_table_name AS
(
SELECT stock_code,[datetime], [AVG_Price],[MF], CASE WHEN cast(datetime as time) = '09:15:00.000' and close_price >= open_price THEN [MF]
WHEN cast(datetime as time) = '09:15:00.000' and close_price < open_price THEN -1*[MF]
WHEN Avg_Price > LAG(Avg_Price,1,-1) over (Partition by stock_code order by datetime asc) THEN (LAG([Net MF],1,-1) over (Partition by stock_code order by datetime asc)) + [MF]
WHEN Avg_Price < LAG(Avg_Price,1,-1) over (Partition by stock_code order by datetime asc) THEN (LAG([Net MF],1,-1) over (Partition by stock_code order by datetime asc)) - [MF]
WHEN Avg_Price = LAG(Avg_Price,1,-1) over (Partition by stock_code order by datetime asc) and (LAG([Net MF],1,-1) over (Partition by stock_code order by datetime asc)) < 0 THEN (LAG([Net MF],1,-1) over (Partition by stock_code order by datetime asc)) - [MF]
WHEN Avg_Price = LAG(Avg_Price,1,-1) over (Partition by stock_code order by datetime asc) and (LAG([Net MF],1,-1) over (Partition by stock_code order by datetime asc)) > 0 THEN (LAG([Net MF],1,-1) over (Partition by stock_code order by datetime asc)) + [MF]
END as [Net MF] from Equity
)
UPDATE [Equity] set Equity.[Net MF] = v_table_name.[Net MF]
FROM v_table_name
WHERE Equity.stock_code = v_table_name.stock_code
and Equity.datetime = v_table_name.datetime
As the Net MF depends on previous row value, one simple solution is to use a recursive CTE and calculate the Net MF in the recursive part of the CTE based on your required condition
with
cte as
(
select rn = row_number() over (partition by stock_code order by [datetime]),
stock_code, [datetime], AVG_Price, [MF]
from Equity
),
rcte as
(
-- anchor
select c.rn, c.stock_code, c.[datetime], c.AVG_Price, c.[MF], [Net MF] = c.[MF]
from cte c
where c.rn = 1
union all
-- recursive
select c.rn, c.stock_code, c.[datetime], c.AVG_Price, c.[MF],
[Net MF] = case when c.AVG_Price > r.AVG_Price
then r.[Net MF] + c.[MF]
when c.AVG_Price < r.AVG_Price
then r.[Net MF] - c.[MF]
when c.AVG_Price = r.AVG_Price
and r.[Net MF] < 0
then r.[Net MF] - c.[MF]
when c.AVG_Price = r.AVG_Price
and r.[Net MF] >= 0
then r.[Net MF] + c.[MF]
end
from cte c
inner join rcte r on c.stock_code = r.stock_code
and c.rn = r.rn + 1
)
update e
set [Net MF] = r.[Net MF]
from rcte r
inner join Equity e on r.stock_code = e.stock_code
and r.[datetime] = e.[datetime]
OPTION (MAXRECURSION 0);
Note : open/close price logic is not in as it is not clear for me. You may add it in yourself
db<>fiddle demo
Related
I'm trying to create a PIVOT TSQL statment that totals the products by date and state/province and provides the AVG Transit Time. Here is what I have so far:
select *
from (select createdate [Date Processed],
stateprovince as [Province],
count(*) as [Total],
avg(datediff(day,createdate,t.eventdate)) as [AVG Delivery],
product
from recipient C left outer join
(select delivid, product, eventdesc, eventdate, eventcode
from deliverystatus
where delivid in (select max(deliv_id)
from deliverystatus
where eventcode = 'DELIVERED'
group by product)) as t ON c.product = t.product
where account = 3519 and consol <>'' and trknum <> '' and C.createdate between '2/4/2016' and '2/4/2016'
group by C.createdate, c.stateprovince, c.product
) as Q
pivot (
count(product)
for [Province] in (NY, IL, GA)
) as PVT
My Result is:
Date Processed Total AVG Transit NY IL GA
2016-02-04 00:00:00.000 1 8 0 0 1
2016-02-04 00:00:00.000 1 11 2 4 1
2016-02-04 00:00:00.000 1 12 0 0 0
2016-02-04 00:00:00.000 1 15 0 0 0
I need the result to be:
Date Processed Total AVG Transit NY IL GA
2016-02-04 00:00:00.000 8 11.5 2 4 2
The ultimate goal is to have the AVG Transit listed by State/Province like this:
Date Processed Total Total AVG NY AVG IL AVG GA AVG
2016-02-04 00:00:00.000 8 11.5 2 8 4 11 2 15
Thanks in advance.
You need to add a GROUP BY clause after the pivot and either take the AVG SUM or MAX value for each output column:
select [Date Processed], SUM(NY+IL+GA) AS [Total], AVG([AVG Delivery]) AS [AVG Delivery], SUM(NY) AS NY, SUM(IL) AS IL, SUM(GA) AS GA
from (select createdate [Date Processed],
stateprovince as [Province],
count(*) as [Total],
avg(datediff(day,createdate,t.eventdate)) as [AVG Delivery],
product
from recipient C left outer join
(select delivid, product, eventdesc, eventdate, eventcode
from deliverystatus
where delivid in (select max(deliv_id)
from deliverystatus
where eventcode = 'DELIVERED'
group by product)) as t ON c.product = t.product
where account = 3519 and consol <>'' and trknum <> '' and C.createdate between '2/4/2016' and '2/4/2016'
group by C.createdate, c.stateprovince, c.product
) as Q
pivot (
count(product)
for [Province] in (NY, IL, GA)
) as PVT
group by [Date Processed]
I'm fairly new to SQL and find this site to be a brilliant resource. I'm hoping for a little bit of help with a task I've been assigned.
Basically I need to find the number of periods of sickness a member of staff has taken in the last 12 month and the duration of each period of sickness.
I have a simple table that looks like this:
Agent Date Status
A 01/07/2015 SHIFT
A 02/07/2015 SHIFT
A 03/07/2015 SICK
A 04/07/2015 SHIFT
A 05/07/2015 SHIFT
A 06/07/2015 SHIFT
B 01/07/2015 SICK
B 02/07/2015 SICK
B 03/07/2015 SHIFT
B 04/07/2015 SHIFT
B 05/07/2015 SICK
B 06/07/2015 SICK
C 01/07/2015 SHIFT
C 02/07/2015 SHIFT
C 03/07/2015 SICK
C 04/07/2015 SICK
C 05/07/2015 SICK
C 06/07/2015 SHIFT
I'm hoping someone can help me find some code that would produce the following kind of output:
Agent Days
A 1
B 2
B 2
C 3
Any help would be greatly appreciated.
Cheers
For sql-server:
select count(1) from TableA
where Status = 'SICK' and Date >= CAST(DATEADD(MONTH, -12, CURRENT_TIMESTAMP) AS DATE)
group by Agent
Grouped by periods of sickness:
WITH Cte AS(
SELECT *,
DATEDIFF(dd, '12/30/1899', [Date]) as [number],
RN = DATEDIFF(dd, '12/30/1899', [Date]) - ROW_NUMBER()
OVER(PARTITION BY Agent ORDER BY DATEDIFF(dd, '12/30/1899', [Date]))
FROM TableA
WHERE
[Status] = 'SICK' and
[Date] >= CAST(DATEADD(MONTH, -12, CURRENT_TIMESTAMP) AS DATE)
)
,CteFinal AS(
SELECT
Agent,
startNumber = MIN(number),
endNumber = MAX(number)
FROM Cte
GROUP BY Agent, RN
)
select Agent, endNumber - startNumber +1 as [Days] from CteFinal
group by agent, startNumber, endNumber
Sqlfiddle
In addition, for case with days off in table TableB:
WITH Cte AS(
SELECT distinct *,
DATEDIFF(dd, '12/30/1899', [Date]) as [number],
RN = DATEDIFF(dd, '12/30/1899', [Date]) - ROW_NUMBER()
OVER(PARTITION BY Agent ORDER BY DATEDIFF(dd, '12/30/1899', [Date]))
FROM (select distinct * from TableA
union all
select distinct Agent, b.Date, 'DAY OFF' from TableA cross join TableB b) TableA
WHERE
[Status] IN ('SICK', 'DAY OFF') and
[Date] >= CAST(DATEADD(MONTH, -12, CURRENT_TIMESTAMP) AS DATE)
)
,CteFinal AS(
SELECT
Agent,
startNumber = MIN(number),
endNumber = MAX(number),
dayOffs = SUM(CASE WHEN [Status] = 'DAY OFF' THEN 1 ELSE 0 END)
FROM Cte
GROUP BY Agent, RN
)
select Agent, endNumber - startNumber +1 - sum(dayOffs) as [Days] from CteFinal
group by agent, startNumber, endNumber
having(endNumber - startNumber +1 - sum(dayOffs) > 0)
Sqlfiddle
I have two tables
1) Fund details
ID Symbol
-------------------
1 ABC
2 XYZ
2) Fund Price data
Fund_id date Price
-------------------------------------------
1 2014-07-01 00:00:00.000 25.25
1 2014-07-02 00:00:00.000 25.45
......
2 2014-07-01 00:00:00.000 75.25
2 2014-07-02 00:00:00.000 75.42
.......
Now what I want to achieve is:
Here I am fetching the monthly data of a particular Fund as below:
SELECT YEAR(date) [Year], MONTH(date) [Month],
DATENAME(MONTH,date) [Month Name], COUNT(1) [Sales Count], F.Symbol
FROM FundData FD inner join FundDetails F on F.ID = FD.Fund_ID
where F.Symbol = 'ABC'
GROUP BY YEAR(date), MONTH(date), DATENAME(MONTH, date), F.Symbol
Output:
Year Month Month Name Sales Count Symbol
-------------------------------------------
2014 4 April 21 ABC
2014 5 May 21 ABC
2014 6 June 21 ABC
2014 7 July 3 ABC
.......
Total Rows: 301
So here this is only for only particular fund which has returned 301 rows.
Now I want to get all the funds from the Fund details table which has rows less than given count ex 216 which I will pass as a parameter
Use Following query:
Declare #YourParameter int = 10
SELECT YEAR(date) [Year],
MONTH(date) [Month],
DATENAME(MONTH,date) [Month Name],
COUNT(1) [Sales Count],
F.Symbol
FROM FundData FD
INNER JOIN FundDetails F on FD.ID = F.Fund_ID
Where FD.ID IN (SELECT z.Fund_ID
FROM FundDetails z
WHERE z.Fund_ID=FD.ID
GROUP BY z.Fund_ID, YEAR(z.date), MONTH(z.date)
HAVING COUNT(*) <= #YourParameter
)
GROUP BY YEAR(date), MONTH(date), DATENAME(MONTH, date), F.Symbol
I have fixed it:
Declare #YourParameter int = 110
WITH CTE AS
(
SELECT YEAR(date) [Year], MONTH(date) [Month],
DATENAME(MONTH,date) [Month Name], COUNT(1) [Sales Count], F.Symbol
FROM FundData FD inner join FundDetails F on F.ID = FD.Fund_ID
where F.ID
IN (SELECT z.ID FROM FundDetails z)
GROUP BY F.Symbol, YEAR(date), MONTH(date), DATENAME(MONTH, date)
)
SELECT Symbol, COUNT(*) as cnt FROM CTE
GROUP BY Symbol
having COUNT(*) >= #YourParameter
I have a query that is returning SUM of 2 columns with customer first name and last name.
It is returning about 40000 records. My query is :-
SELECT SUM(Orders.BusinessVolumeTotal) AS BV,
SUM(Orders.CommissionableVolumeTotal) AS PV,
ISNULL(Customers.FirstName,''), Customers.LastName
FROM Customers INNER JOIN Orders ON Customers.CustomerID = Orders.CustomerID
WHERE Orders.OrderDate >= convert(DATETIME, '1/1/2013 12:00:00 AM')
AND Orders.OrderDate < convert(DATETIME, '12/31/2013 12:00:00 AM')
GROUP BY Customers.FirstName, Customers.LastName
But I just want to return 10 rows with highest values in BV and PV coluymns.
Thanks in advance.
If you want the 10 highest rows per group you can use ROW_NUMBER in a CTE:
WITH CTE AS
(
SELECT SUM(Orders.BusinessVolumeTotal) OVER(PARTITION BY Customers.FirstName, Customers.LastName) AS BV,
SUM(Orders.CommissionableVolumeTotal) OVER(PARTITION BY Customers.FirstName, Customers.LastName) AS PV,
ISNULL(Customers.FirstName,'') As FirstName,
Customers.LastName,
RN = ROW_NUMBER()
OVER(PARTITION BY Customers.FirstName, Customers.LastName
ORDER BY (Orders.BusinessVolumeTotal + Orders.CommissionableVolumeTotal) DESC)
FROM Customers INNER JOIN Orders ON Customers.CustomerID = Orders.CustomerID
WHERE Orders.OrderDate >= convert(DATETIME, '1/1/2013 12:00:00 AM')
AND Orders.OrderDate < convert(DATETIME, '12/31/2013 12:00:00 AM')
)
SELECT * FROM CTE WHERE RN <= 10
Based on group of two columns, you can get top 10 rows like below :
SELECT TOP 10
SUM(Orders.BusinessVolumeTotal) AS BV,
SUM(Orders.CommissionableVolumeTotal) AS PV,
ISNULL(Customers.FirstName,''), Customers.LastName
FROM Customers INNER JOIN Orders ON Customers.CustomerID = Orders.CustomerID
WHERE Orders.OrderDate >= convert(DATETIME, '1/1/2013 12:00:00 AM')
AND Orders.OrderDate < convert(DATETIME, '12/31/2013 12:00:00 AM')
GROUP BY Customers.FirstName, Customers.LastName
ORDER BY SUM(Orders.BusinessVolumeTotal) + SUM(Orders.CommissionableVolumeTotal) DESC
One way to get both the top 10 for BV and the top ten for PV is to write one query for each:
SELECT TOP 10
SUM(Orders.BusinessVolumeTotal) AS BV, SUM(Orders.CommissionableVolumeTotal) AS PV, ISNULL(Customers.FirstName,''), Customers.LastName
FROM Customers INNER JOIN Orders ON Customers.CustomerID = Orders.CustomerID
WHERE Orders.OrderDate >= convert(DATETIME, '1/1/2013 12:00:00 AM')
AND Orders.OrderDate < convert(DATETIME, '12/31/2013 12:00:00 AM')
GROUP BY Customers.FirstName, Customers.LastName
ORDER BY BV DESC
SELECT TOP 10
SUM(Orders.BusinessVolumeTotal) AS BV, SUM(Orders.CommissionableVolumeTotal) AS PV, ISNULL(Customers.FirstName,''), Customers.LastName
FROM Customers INNER JOIN Orders ON Customers.CustomerID = Orders.CustomerID
WHERE Orders.OrderDate >= convert(DATETIME, '1/1/2013 12:00:00 AM')
AND Orders.OrderDate < convert(DATETIME, '12/31/2013 12:00:00 AM')
GROUP BY Customers.FirstName, Customers.LastName
ORDER BY PV DESC
I have a stored procedure like this:
ALTER PROCEDURE [dbo].[Driverperformance]
#Ecode NVARCHAR(50),
#startdate DATE,
#enddate DATE
AS BEGIN
SELECT
e.Ecode, q.dtime, e.Ename,
count(q.Ecode) CntEcode,
count(DelEcode) CntDelEcode,
CAST((count(q.Ecode) + count(DelEcode)) as float)/2 as Avrgpoint
FROM
EmployeeMaster_tbl e
INNER JOIN
Transaction_tbl q ON e.Ecode = q.Ecode
WHERE
q.Ecode = #Ecode
AND dtime BETWEEN #startdate AND #enddate
GROUP BY
e.Ecode, e.Ename, q.dtime
ORDER BY
e.Ecode DESC
END
while executing this: out put is getting like this:
Ecode dtime Ename CntEcode CntDelEcode Avrgpoint
E001 2013-05-25 12:55:23.000 Deepu M. Thomas 1 0 0.5
E001 2013-05-25 13:53:16.000 Deepu M. Thomas 1 0 0.5
E001 2013-05-27 03:24:59.000 Deepu M. Thomas 1 1 0.5
E001 2013-05-27 03:24:59.000 Deepu M. Thomas 1 0 0.5
E001 2013-05-28 03:24:59.000 Deepu M. Thomas 1 0 0.5
I want to get output totalcount of(CntEcode ,CntDelEcode ) for each date.expected out put like this:
Ecode dtime Ename CntEcode CntDelEcode
E001 2013-05-25 Deepu M. Thomas 2 0
E001 2013-05-27 Deepu M. Thomas 2 1
E001 2013-05-28 Deepu M. Thomas 1 0
If you want to look at just the date portion of dtime, use CAST(dtime AS DATE) to get just the date:
ALTER PROCEDURE [dbo].[Driverperformance]
#Ecode NVARCHAR(50),
#startdate DATE,
#enddate DATE
AS BEGIN
SELECT
e.Ecode,
CAST(q.dtime AS DATE), -- <== CAST to DATE
e.Ename,
count(q.Ecode) CntEcode,
count(DelEcode) CntDelEcode,
CAST((count(q.Ecode) + count(DelEcode)) as float)/2 as Avrgpoint
FROM
EmployeeMaster_tbl e
INNER JOIN
Transaction_tbl q ON e.Ecode = q.Ecode
WHERE
q.Ecode = #Ecode
AND dtime BETWEEN #startdate AND #enddate
GROUP BY
e.Ecode, e.Ename,
CAST(q.dtime AS DATE) -- <== CAST to DATE here, too!
ORDER BY
e.Ecode DESC
END