Problem with SQL In Line Table Function... Query - sql

Hi I have the following query running a function to get the Standard Deviation for a set of Tickers in the following table...
GO
CREATE TABLE [dbo].[Tickers](
[ticker] [varchar](10) NULL,
[date] [datetime] NULL,
[high] [float] NULL,
[low] [float] NULL,
[open] [float] NULL,
[close] [float] NULL,
[volume] [float] NULL,
[time] [datetime] NULL,
[change] [float] NULL
) ON [PRIMARY]
THE PROBLEM: THE FOLLOWING IN LINE TABLE FUNCTION RETURNS STDDEV CALC which is in turn used by a SPROC To calculate Bollinger bands ... (mov average + 2 * STDEV) etc...
The results that I get for some Tickers has weird data ... this is the result set for the ticker 'ATE' or just a sample of the result set.
dayno ticker stddev
484 11/13/2009 0.544772123613694
485 11/16/2009 0.323959874058724
486 11/17/2009 0.287909129182731
487 11/18/2009 0.225018517756637
488 11/19/2009 4.94974746848848E-02
489 11/20/2009 4.94974746848848E-02
As you can see the last two values for some of the tickers results in 'weird data' and the actual ticker table is within very normal ranges.
As you can see from the following in line table function there was some funny stuff going on at the end because it is using a 20 day period and the last value always came back as NULL, so I asked experts to adjust and this is what Peter came up with... it usually works find but as you can see above sometimes does not - does anyone have a suggestion on how I may fix this dilemma??
ALTER FUNCTION dbo.GetStdDev3 (#TKR VARCHAR(10))
RETURNS #results TABLE (
dayno SMALLINT IDENTITY(1,1) PRIMARY KEY
, [date] DATETIME
, [stddev] FLOAT
)
AS BEGIN
DECLARE #min_sysdate DATETIME, #min_tkrdate DATETIME, #rowcount SMALLINT
SET #min_sysdate = DATEADD(DAY,-731,GETDATE())
SET #min_tkrdate = DATEADD(DAY,20,(
SELECT MIN(DATE) FROM TICKERS WHERE TICKER = #TKR))
INSERT #results ([date],[stddev])
SELECT x.[date], ISNULL(STDEV(y.[Close]),0) AS stdev
FROM Tickers x
JOIN Tickers y ON x.[DATE] BETWEEN DATEADD(DAY,-20,y.[DATE]) AND y.[DATE]
WHERE x.[DATE] > #min_tkrdate
AND x.[DATE] > #min_sysdate
AND x.TICKER = #TKR
AND y.TICKER = #TKR
GROUP BY x.[DATE]
SET #rowcount = ##ROWCOUNT
UPDATE #results SET [stddev] = (
SELECT [stddev] FROM #results WHERE dayno = #rowcount-1)
WHERE dayno = #rowcount
RETURN

4.94974746848848E-02 is actually the same thing as 0.0494974746848848
Are you sure this is in error? Seems to me it could just be a low deviation.

Ditto what "d." said. The standard deviation for the last two dates is low, but it was decreasing over time anyway. Also, all that the last update statement does is to set the last row (latest date) in the set equal to the second-to-last value. (Perhaps "adjsut" might have been "delete"?)

Related

Timestamp Field Incriminating

I have a table as such (with a timestamp and a varbinary)
CREATE TABLE [dbo].[CASE]
(
[CASE_ID] [int] IDENTITY(1,1) NOT NULL,
[CASE_TITLE] [varchar](50) NOT NULL,
[CASE_STATUS] [varchar](50) NOT NULL,
[MODIFIED_TS] [timestamp] NOT NULL,
[SYNCED_TS] [varbinary](8) NULL
)
Then I add an item to it, and update it...
UPDATE [CASE]
SET CASE_STATUS = 'Something New'
WHERE CASE_ID = 1
When I do that, then I update the Synced_TS column:
UPDATE [CASE]
SET SYNCED_TS = MODIFIED_TS
WHERE CASE_ID = 1
But then, when I run this....
SELECT
*,
CAST(CONVERT(BIGINT, MODIFIED_TS) - CONVERT(INT, SYNCED_TS) AS DECIMAL)
FROM
[CASE]
WHERE
CAST(CONVERT(BIGINT, MODIFIED_TS) - CONVERT(INT, SYNCED_TS) AS DECIMAL) > 1
OR SYNCED_TS IS NULL
I have two values that are totally different, for example, A0D, and A0A, its OK they are different, but shouldn't it be A0D, and A0C?
MODIFIED_TS SYNCED_TS
---------------------------------------
0x0000000000000A0D 0x0000000000000A0A
The reason why its an issue, is that I am trying to convert it to an integer to compare it, so I can determine if the record needs to be synced or not.

Return zero for time slot if data is not present

I'm trying to get data for a period of two minutes every minute there should be data for each second for mid,sid,pid combination. if data is not present for a second for each combination it should return IC value as zero.For two minutes there will be 120 time slots if data is not present for mid,sid, pid combination for any time slot it should return zero.This data is used to plot line chart if data is not present it should go down to zero.
CREATE TABLE [dbo].[DeviceData](
[Id] [BIGINT] IDENTITY(1,1) NOT NULL,
[MId] [INT] NOT NULL,
[SId] [INT] NOT NULL,
[PId] [INT] NOT NULL,
[DataTime] [DATETIME] NOT NULL,
[IC] [INT] NOT NULL,
CONSTRAINT [PK_DeviceData] PRIMARY KEY CLUSTERED
(
[Id] ASC
)
SELECT [MId] ,
[SId] ,
[PId] ,
[DataTime] ,
SUM([IC]) AS Value
FROM [DeviceData]
WHERE DataTime BETWEEN DATEADD(MINUTE, -2, GETUTCDATE())
AND GETUTCDATE()
GROUP BY [MId] ,
SID ,
PId ,
[DataTime];
You need a numbers CTE:
with Numbers as
(
select 1 as NN
union all
select NN+1
from Numbers
where NN < 120
)
, Times as
(
select dateadd(ss,
NN,
DATEADD(MINUTE,
-2,
dateadd(ms,
-datepart(ms,
GETUTCDATE()),
GETUTCDATE()) ) as Timeslot
from Numbers
)
select Timeslot, DD.*
from Times
left join DeviceData DD
on Timeslot = dateadd(ms, -datepart(ms, GETUTCDATE()),GETUTCDATE())
OPTION (MAXRECURSION 1000) -- This will bypass the recursion error

Make column to always contain calculated value without triggers

I was doing practice tests before 70-461 exam and one of questions was to create table that:
Has 4 columns, saleid, unitprice, amount, and price.
Price is calculated by multiplication of unitprice and amount
You can't use triggers.
The last one killed me. How can I do it without triggers? Here is my solutions using instead of triggers.
CREATE TABLE [HR].[Stuff](
[saleid] [int] IDENTITY(1,1) NOT NULL,
[unitprice] [float] NOT NULL,
[amount] [float] NOT NULL,
[price] [float] NULL,
)
GO
CREATE TRIGGER [calculate_price_insert]
ON [HR].[Stuff]
INSTEAD OF INSERT
AS
DECLARE #unitprice float = (SELECT TOP 1 unitprice from inserted )
DECLARE #amount float = (SELECT TOP 1 amount from inserted)
INSERT INTO HR.[Stuff]
VALUES(#unitprice,#amount, #unitprice*#amount)
GO
CREATE TRIGGER [calculate_price_update]
ON [HR].[Stuff]
INSTEAD OF UPDATE
AS
DECLARE #unitprice float = (SELECT TOP 1 unitprice from inserted )
DECLARE #amount float = (SELECT TOP 1 amount from inserted)
UPDATE HR.[Stuff]
SET unitprice = #unitprice, amount = #amount, price = #unitprice*#amount
WHERE unitprice = (SELECT TOP 1 saleid from inserted)
GO
You need to use computed column:
CREATE TABLE [HR].[Stuff](
[saleid] [int] IDENTITY(1,1) NOT NULL,
[unitprice] [float] NOT NULL,
[amount] [float] NOT NULL,
[price] AS ([unitprice] * [amount])
)
LiveDemo
Also storing unitprice and amount as FLOAT may be dangerous because FLOAT isn't accurate datatype. Use DECIMAL(12,4) instead.
Your original trigger solution will fail, because trigger is executed per statement, not per row. Try with:
INSERT INTO [HR].[Stuff](unitprice, amount) VALUES (10, 20), (30, 50), (100,1);
You will loose records with INSERT and get false results with multiple UPDATE.
SqlFiddleDemo

SQL loop executes but new old values are over written

As my question title says, my program loops but all of my values I updated are being overwritten. Here's the code posted below. Say minRownum is 1 and max is 12, I see the loop execute 12 times correctly and min gets updated +1 each time. But in the end result, only the final row in my column whose RowNum is 12 have any values
I'm not exactly sure why overwriting is occurring since I'm saying "Update it where the rownumber = minrownumber" then I increment minrownum.
Can anyone point to what I am doing wrong? Thanks
WHILE (#MinRownum <= #MaxRownum)
BEGIN
print ' here'
UPDATE #usp_sec
set amount=(
SELECT sum(amount) as amount
FROM dbo.coverage
inner join dbo.owner
on coverage.api=owner.api
where RowNum=#MinRownum
);
SET #MinRownum = #MinRownum + 1
END
PS: I edited this line to say (below) and now every value has the same wrong number (its not distinct but duplicated to all.
set amount = (SELECT sum(amount) as amount
FROM dbo.coverage
INNER JOIN dbo.owner ON coverage.api = owner.api
where RowNum=#MinRownum
) WHERE RowNum = #MinRownum;
Tables:
CREATE TABLE dbo. #usp_sec
(
RowNum int,
amount numeric(20,2),
discount numeric(3,2)
)
CREATE TABLE [dbo].[handler](
[recordid] [int] IDENTITY(1,1) NOT NULL,
[covid] [varchar](25) NULL,
[ownerid] [char](10) NULL
)
CREATE TABLE [dbo].[coverage](
[covid] [varchar](25) NULL,
[api] [char](12) NULL,
[owncovid] [numeric](12, 0) NULL,
[amount] [numeric](14, 2) NULL,
[knote] [char](10) NULL
)
CREATE TABLE [dbo].[owner](
[api] [char](12) NOT NULL,
[owncovid] [numeric](12, 0) NULL,
[ownerid] [char](10) NOT NULL,
[officer] [char](20) NOT NULL,
[appldate] [date] NOT NULL
)
Your UPDATE statement needs its own WHERE clause. Otherwise, each UPDATE will update every row in the table.
And the way you have this written, your subquery still needs its WHERE clause too. In fact, you need to definitively correlate the subquery to your table's (#usp_sec) rows. We cannot tell you how that should be done without more information such as your table definitions.

Projected Payments based on Schedule table?

I have a payment_schedule table:
CREATE TABLE [dbo].[scheduled_transaction](
[id] [int] IDENTITY(1,1) NOT NULL,
[description] [varchar](20) NOT NULL,
[account_id] [int] NOT NULL,
[account_transaction_type_id] [int] NOT NULL,
[third_party_id] [int] NOT NULL,
[first_payment_date] [date] NOT NULL,
[last_payment_date] [date] NULL,
[payment_frequency] [int] NOT NULL,
[payment_frequency_type_id] [int] NOT NULL,
[payment_amount] [decimal](18, 2) NOT NULL,
[notes] [varchar](100) NULL,
[deleted] [datetime] NULL,
[createuser] [int] NOT NULL,
[createdate] [datetime] NOT NULL,
[lastupdateuser] [int] NULL,
[lastupdatedate] [datetime] NULL) ON [PRIMARY]
)
This table holds scheduled bill payments for my home system. The frequency is simply Daily, weekly or monthly. So, payment frequency = 1, and payment frequency type = 3 (monthly) means that the payment is done every one month.
I also have a calendar table, which is a table of all dates between a large period (2000 and 2040). This is just a reference table that I think is useful for what I will be doing.
What I want to do now, is create a procedure that will return a table of dates from a given startdate to a given enddate, and for each date, return any payments that should be done on that date, based on my schedule table.
My plan is to create a temp table with all dates where payments will be due:
DECLARE #StartDate DATE
DECLARE #EndDate DATE
Set #StartDate = '01-JAN-2013'
SET #EndDate = '31-DEC-2013'
DECLARE #Schedule TABLE
(
ID INT NOT NULL IDENTITY(1,1),
TransactionDate DATE NOT NULL,
scheduled_transaction_id INT NOT NULL
)
Once that's populated, I can then use the calendar table and create a balance forecast.
But, getting the data into that table is tricky.
I think I need to go through each scheduled_transaction, and then, run through the calendar and see if a transaction would be done on that date? And then insert the row into my temp table?
So, then I think it would be nested cursors. For each scheduled_transaction row, then for each calendar row, and use some form of 'DATEADD' or something?
Could anyone assist me with this?
I'm assuming that you have #days table with a date for each day in calendar so 2013-01-01, 2013-01-02 etc.
Also I don't know when will you pay someone with monthly schedule and first payment date 2013-01-31...? So I will ignore such cases:
select d.d as [day], st.id as transactionId
from #days d
inner join [scheduled_transaction] st
on (d.d >= st.first_payment_date
and d.d <= st.last_payment_date
and (
(
st.payment_frequency = 2
and datediff(day, d.d, st.first_payment_date) % 7 = 0
)
or
(
st.payment_frequency = 1
)
or
(st.payment_frequency = 3
and day(st.first_payment_date) = day(d.d)
)
)
)
This can be done using common Table expressions. Execute the below code to list all payments due in the given date range.
DECLARE #StartDate DATE
DECLARE #EndDate DATE
Set #StartDate = '01-JAN-2013'
SET #EndDate = '31-DEC-2013'
;with schedule as
(
SELECT first_payment_date as Next_payment_date,* FROM scheduled_transaction
UNION ALL
SELECT DATEADD( dd,case when payment_frequency_type_id =1 then 1 -- Daily
else case when payment_frequency_type_id =2 then 7 --Weekly
else 30 end end --Monthly
,Next_payment_date) ,
id, description, account_id, account_transaction_type_id, third_party_id, first_payment_date, last_payment_date, payment_frequency, payment_frequency_type_id,
payment_amount, notes, deleted, createuser, createdate, lastupdateuser, lastupdatedate
FROM schedule
WHERE Next_payment_date < last_payment_date
)
SELECT * FROM SCHEDULE
WHERE Next_payment_date between #StarDate and #EndDate
This code assumes the payment frequency is stored in payment_frequency_type_id. If it is different make changes in the code accordingly.