Question : Modify SQL SP to ignore initial Start Value

I'm using the 2 SP below to compare Values from a table, and from the differences, work out costs etc..

The problem I'm having is that if the HistorianDB.TLData DATA column doesn't start from Zero, the first value returned by the SP is very high.

For example, the TLData table is logging data from a data logger every 15mins. If the first value to be logged in the Data column is 2000, then the value increases 10 units every 15min sample. All samples will show a neat line on the chart displaying 10. However, the first datapoint on the Chart will show a huge spike of 2000, as it sees the initial start of 2000, as a change from Null (or 0), to 2000.

So, what I need is to modify the SP, so that it always ignores the first comparison from Null (or 0 and nothing), to the first row, and only compares Ro1 and row2.

Hope this makes sense.
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
219:
220:
221:
222:
223:
224:
225:
226:
227:
228:
229:
230:
231:
232:
233:
234:
235:
236:
237:
238:
239:
240:
241:
242:
243:
244:
245:
246:
247:
248:
249:
250:
251:
252:
253:
254:
255:
256:
257:
258:
259:
260:
261:
262:
263:
264:
265:
266:
267:
268:
269:
270:
271:
272:
273:
274:
275:
276:
277:
278:
279:
280:
281:
282:
283:
284:
285:
286:
287:
288:
289:
290:
USE [EnergySuiteDB]
GO
/****** Object:  StoredProcedure [dbo].[GetCostPerPeriod]    Script Date: 07/09/2010 15:32:24 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[GetCostPerPeriod] @sDate DATETIME,@Meter varchar(50),@GasRate int,@pf float,@util varchar(50),@reportselection char(1),@co2 float,@Carbon float

AS
BEGIN

--A power factor of 0 will throw exception, so this needs to be taken care of
if isnull(@pf,0)=0 set @pf = 1

-- declare and set up some variables based on incoming parameters

DECLARE @PrevVal NUMERIC(12, 4)
declare @grate numeric(12,4)
declare @edate datetime
declare @intervals int

set @sdate = convert(char(8),@sdate,112)   -- make sure time is at "start" of period
If @reportselection = 'M' set @sdate = DATEADD(month, DATEDIFF(month, 0, @sdate),0)
If @reportselection = 'Y' set @sdate = datename(year,@sdate) + '0101'

set @edate = convert(char(8),@sdate,112) + ' 23:59:59.997'
If @reportselection = 'W' set @edate = convert(char(8),@sdate+6,112) + ' 23:59:59.997'
If @reportselection = 'M' set @edate = DATEADD(month, DATEDIFF(month, -1, @sdate),0) - 0.00000005
If @reportselection = 'Y' set @edate = datename(year,@sdate) + '1231 23:59:59.997'

set @intervals = day(dateadd(month,datediff(month,-1,@sdate),0) - 1) 
If @reportselection = 'D' set @intervals = @intervals * 96  -- 96 quarter hours in a day.
If @reportselection = 'Y' set @intervals = 1

if isnull(@gasrate,0) = 1
   set @grate = 11.0786 -- 1.02264 * 39 / 3.6
else
   set @grate = 1.0

-- now create our temp report data extract from main history table

IF OBJECT_ID('tempdb..#ReportData','U') IS NOT NULL DROP TABLE #ReportData  -- should not be needed
 
CREATE TABLE #ReportData
(
    ID int identity primary key,
    TimeStamp DATETIME,
    Hundredths INT,      
    Data NUMERIC(12, 4),
    DataChange NUMERIC(12, 4),
    DateStamp datetime
)

-- populate our report data

INSERT INTO #ReportData (Timestamp, Hundredths, Data, Datestamp)
SELECT Timestamp, Hundredths, convert(real,Data) * @grate , case when @reportselection = 'Y' then convert(char(6),timestamp,112)+'01' else convert(char(8),timestamp,112) end
FROM HistorianDB.dbo.TLData 
WHERE TLInstance = @Meter 
AND timestamp between @sdate and @edate
AND Type=0 
AND isnumeric(data)=1
ORDER BY timestamp, recordnumber        

-- now prepare to update our data to calculate the difference between meter readings, but we need a starting point...

SET @PrevVal = isnull( (SELECT top 1 convert(real,Data) * @grate
                        FROM HistorianDB.dbo.TLData 
                        WHERE TLInstance = @Meter 
                        AND timestamp < @sdate
                        AND Type=0 
                        AND isnumeric(data)=1 
                        ORDER BY timestamp desc) , 0)

-- do the update our data to calculate the difference between meter readings and cost

UPDATE #reportdata
SET    DataChange = #reportdata.Data - isnull(prev.data,@prevval)
FROM   #ReportData 
left outer join #reportdata prev on #reportdata.id - 1 = prev.id

-- now we can run the report

;With Periods as
(
   Select case when @reportselection = 'D' then dateadd(minute,number * 15,@sdate) else case when @reportselection = 'Y' then dateadd(month,number,@sdate) else dateadd(day,number,@sdate) end end as PSDate 
   ,case when @reportselection = 'D' then dateadd(minute,number * 15 + 15,@sdate) - 0.00000005 else case when @reportselection = 'Y' then DATEADD(month, DATEDIFF(month, -1, dateadd(month,number,@sdate)),0) - 0.00000005 else convert(char(8),@sdate+number,112) + ' 23:59:59.997' end end as PEDate 
   ,case when @reportselection = 'D' then left(datename(dw,@sdate),03) +' '+ convert(char(8),@sdate,03) +right(convert(char(19),dateadd(minute,number * 15,@sdate),100),8) else case when @reportselection = 'Y' then left(datename(month,dateadd(month,number,@sdate)),3) + ' ' + datename(year,@sdate) else left(datename(dw,dateadd(day,number,@sdate)),3) + ' ' + convert(char(8),dateadd(day,number,@sdate),03) end end as PSName 
   ,case when @reportselection = 'D' then 1.0 / 96.0 else case when @reportselection in ('M','W') then 1.0 else day(dateadd(month, number+datediff(month, -1, @sdate),0) - 1) end end as dayparts
   from master..spt_values n with (nolock) 
   where type = 'p'
   and case when @reportselection = 'D' then dateadd(minute,number * 15,@sdate) else case when @reportselection = 'Y' then dateadd(month,number,@sdate) else dateadd(day,number,@sdate) end end < @edate
)
SELECT 
    PSname as Date,
    SUM(isnull(r1.datachange,0)) AS day_data,
    SUM(isnull(r1.datachange,0))*@CO2 AS CO2_data,
    SUM(isnull(r1.datachange,0))*@Carbon AS Carbon_data,
    SUM(isnull(r1.datachange,0)*chargerate) AS DataCost,
    SUM(isnull(r1.datachange,0)*levy) as TotalLevy,
    max(case when r1.datestamp is null then 0 else caprate end)/@intervals  as TotalCap,                           
    max(case when r1.datestamp is null then 0 else chargecap end)  as ChargeCap,
    max(case when r1.datestamp is null then 0 else dayparts * StandingDayCharge end) as StandingDayCharge,
    max(case when r1.datestamp is null then 0 else dayparts * StandingDayCharge end) 
    + SUM(isnull(r1.datachange,0)*(chargerate + levy)) 
    + max(case when r1.datestamp is null then 0 else caprate end)/@intervals  as TotalCost,
    isnull(((case when @reportselection = 'D' then SUM(isnull(r1.datachange,0)) else (select top 1 datachange from #reportdata r2 where r2.datestamp = r1.datestamp order by r2.datachange desc) end)*4)/@pf,0) as MaxkVA,
    isnull(((case when @reportselection = 'D' then SUM(isnull(r1.datachange,0)) else (select top 1 datachange from #reportdata r2 where r2.datestamp = r1.datestamp order by r2.datachange desc) end)*4),0) as MaxkW,
    (select top 1 timestamp from #reportdata r2 where r2.datestamp = r1.datestamp order by r2.datachange desc,r2.timestamp desc) as MaxDataChangeTimeStamp
 
FROM Periods
LEFT OUTER JOIN #ReportData r1 on r1.timestamp between psdate and pedate
cross apply dbo.udf_getrates_3(r1.Timestamp,@util)    
GROUP BY PSname,r1.datestamp,PSdate
ORDER BY PSdate
END




---------------------------------------------------------------------------





USE [EnergySuiteDB]
GO
/****** Object:  StoredProcedure [dbo].[GetCostPerPeriod_Virtual]    Script Date: 07/09/2010 15:32:51 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[GetCostPerPeriod_Virtual] @sDate DATETIME,@Meter varchar(1000), @calc varchar(1000),@operator varchar(1000),@GasRate int,@pf float,@util varchar(50),@reportselection char(1),@CO2 float,@Carbon float

AS
BEGIN

--A power factor of 0 will throw exception, so this needs to be taken care of
if isnull(@pf,0)=0 set @pf = 1

-- declare and set up some variables based on incoming parameters

DECLARE @PrevVal NUMERIC(12, 4)
declare @grate varchar(12) --numeric(12,4)
declare @edate datetime
declare @intervals int

declare @str_sdate varchar(20)
declare @str_edate varchar(20)

set @sdate = convert(char(8),@sdate,112)   -- make sure time is at "start" of period
If @reportselection = 'M' set @sdate = DATEADD(month, DATEDIFF(month, 0, @sdate),0)
If @reportselection = 'Y' set @sdate = datename(year,@sdate) + '0101'

set @edate = convert(char(8),@sdate,112) + ' 23:59:59.997'
If @reportselection = 'W' set @edate = convert(char(8),@sdate+6,112) + ' 23:59:59.997'
If @reportselection = 'M' set @edate = DATEADD(month, DATEDIFF(month, -1, @sdate),0) - 0.00000005
If @reportselection = 'Y' set @edate = datename(year,@sdate) + '1231 23:59:59.997'

set @str_sdate = convert(varchar,@sdate - 1,120)
set @str_edate = convert(varchar,@edate,120)

set @intervals = day(dateadd(month,datediff(month,-1,@sdate),0) - 1) 
If @reportselection = 'D' set @intervals = @intervals * 96  -- 96 quarter hours in a day.
If @reportselection = 'Y' set @intervals = 1

if isnull(@gasrate,0) = 1
   set @grate = '11.0786' -- 1.02264 * 39 / 3.6
else
   set @grate = '1.0'

-- now create our temp report data extract from main history table

IF OBJECT_ID('tempdb..#ReportData','U') IS NOT NULL DROP TABLE #ReportData  -- should not be needed
 
CREATE TABLE #ReportData
(
    ID int identity primary key,
    TLInstance int,
    TimeStamp DATETIME,
    Hundredths INT,      
    Data NUMERIC(12, 4),
    DataChange NUMERIC(12, 4),
    DateStamp datetime
)

-- populate our report data

INSERT INTO #ReportData (Timestamp, tlinstance, Hundredths, Data, Datestamp)
exec('SELECT Timestamp, tlinstance, Hundredths, convert(real,Data) * '+@grate+' , case when '''+@reportselection+''' = ''Y'' then convert(char(6),timestamp,112)+''01'' else convert(char(8),timestamp,112) end
FROM HistorianDB.dbo.TLData 
WHERE TLInstance in ('+@Meter+')
AND timestamp between '''+@str_sdate+''' and '''+@str_edate+'''
AND Type=0 
AND isnumeric(data)=1
ORDER BY tlinstance,timestamp, recordnumber')        

-- do the update our data to calculate the difference between meter readings and cost

UPDATE #reportdata
SET    DataChange = #reportdata.Data - isnull(prev.data,0.00)
FROM   #ReportData 
left outer join #reportdata prev on #reportdata.tlinstance = prev.tlinstance and #reportdata.id - 1 = prev.id 
where  #reportdata.timestamp between @sdate and @edate

-- now we have the datachange we can now consider @operations and @calc
if object_id('tempdb..#tmp_meter','U') is not null drop table #tmp_meter
if object_id('tempdb..#tmp_operator','U') is not null drop table #tmp_operator
if object_id('tempdb..#tmp_calc','U') is not null drop table #tmp_calc

select identity (int,1,1) as id, substring(@meter,number,charindex(',',@meter+',',number)-number) as meter
into #tmp_meter
from (select @meter as meters) m
cross join (select number from master..spt_values where type = 'p')  n
where substring(','+@meter,number,1) = ','
and number <= len(@meter)

select identity (int,1,1) as id, substring(@operator,number,charindex(',',@operator+',',number)-number) as operator
into #tmp_operator
from (select @operator as operators) m
cross join (select number from master..spt_values where type = 'p')  n
where substring(','+@operator,number,1) = ','
and number <= len(@operator)

select identity (int,1,1) as id, substring(@calc,number,charindex(',',@calc+',',number)-number) as calc
into #tmp_calc
from (select @calc as calcs) m
cross join (select number from master..spt_values where type = 'p')  n
where substring(','+@calc,number,1) = ','
and number <= len(@calc)

declare @parse varchar(4000)
select @parse = isnull(@parse+' ',' ') + operator + ' ( case when '''+operator+''' in (''*'',''/'') and isnull([' + meter + '],0) = 0 then 1 else isnull([' + meter + '],0) end' + ' * ' + calc + ' )'
from #tmp_meter m
inner join #tmp_calc c on m.id = c.id
inner join #tmp_operator o on m.id = o.id

declare @columns varchar(2000)
select @columns = isnull(@columns+',','') + '[' + meter + ']'
from #tmp_meter m
inner join #tmp_calc c on m.id = c.id
inner join #tmp_operator o on m.id = o.id
group by meter

if object_id('tempdb..#tmp_reportdata','U') is not null drop table #tmp_reportdata
create table #tmp_reportdata (timestamp datetime, datestamp datetime, datachange decimal(12,4))

insert #tmp_reportdata
exec ('select timestamp,datestamp,convert(decimal(12,4),0'+@parse+') as datachange from
(select timestamp,datestamp,tlinstance,convert(decimal(12,4),datachange) as datachange from #reportdata) src
PIVOT
(sum(datachange) for tlinstance in ('+@columns+')) pvt')

-- now we can run the report

;With Periods as
(
   Select case when @reportselection = 'D' then dateadd(minute,number * 15,@sdate) else case when @reportselection = 'Y' then dateadd(month,number,@sdate) else dateadd(day,number,@sdate) end end as PSDate 
   ,case when @reportselection = 'D' then dateadd(minute,number * 15 + 15,@sdate) - 0.00000005 else case when @reportselection = 'Y' then DATEADD(month, DATEDIFF(month, -1, dateadd(month,number,@sdate)),0) - 0.00000005 else convert(char(8),@sdate+number,112) + ' 23:59:59.997' end end as PEDate 
   ,case when @reportselection = 'D' then left(datename(dw,@sdate),03) +' '+ convert(char(8),@sdate,03) +right(convert(char(19),dateadd(minute,number * 15,@sdate),100),8) else case when @reportselection = 'Y' then left(datename(month,dateadd(month,number,@sdate)),3) + ' ' + datename(year,@sdate) else left(datename(dw,dateadd(day,number,@sdate)),3) + ' ' + convert(char(8),dateadd(day,number,@sdate),03) end end as PSName 
   ,case when @reportselection = 'D' then 1.0 / 96.0 else case when @reportselection in ('M','W') then 1.0 else day(dateadd(month, number+datediff(month, -1, @sdate),0) - 1) end end as dayparts
   from master..spt_values n with (nolock) 
   where type = 'p'
   and case when @reportselection = 'D' then dateadd(minute,number * 15,@sdate) else case when @reportselection = 'Y' then dateadd(month,number,@sdate) else dateadd(day,number,@sdate) end end < @edate
)
SELECT 
    PSname as Date,
    SUM(isnull(r1.datachange,0)) AS day_data,
    SUM(isnull(r1.datachange,0)*@CO2) AS CO2_data,
    SUM(isnull(r1.datachange,0)*@Carbon) AS Carbon_data,
    SUM(isnull(r1.datachange,0)*chargerate) AS DataCost,
    SUM(isnull(r1.datachange,0)*levy) as TotalLevy,
    max(case when r1.datestamp is null then 0 else caprate end)/@intervals  as TotalCap,                           
    max(case when r1.datestamp is null then 0 else chargecap end)  as ChargeCap,
    max(case when r1.datestamp is null then 0 else dayparts * StandingDayCharge end) as StandingDayCharge,
    max(case when r1.datestamp is null then 0 else dayparts * StandingDayCharge end) 
    + SUM(isnull(r1.datachange,0)*(chargerate + levy)) 
    + max(case when r1.datestamp is null then 0 else caprate end)/@intervals  as TotalCost,
    isnull(((case when @reportselection = 'D' then SUM(isnull(r1.datachange,0)) else (select top 1 datachange from #tmp_reportdata r2 where r2.datestamp = r1.datestamp order by r2.datachange desc) end)*4)/@pf,0) as MaxkVA,
    isnull(((case when @reportselection = 'D' then SUM(isnull(r1.datachange,0)) else (select top 1 datachange from #tmp_reportdata r2 where r2.datestamp = r1.datestamp order by r2.datachange desc) end)*4),0) as MaxkW,
    (select top 1 timestamp from #tmp_reportdata r2 where r2.datestamp = r1.datestamp order by r2.datachange desc,r2.timestamp desc) as MaxDataChangeTimeStamp
 
FROM Periods
LEFT OUTER JOIN #tmp_ReportData r1 on r1.timestamp between psdate and pedate
cross apply dbo.udf_getrates_3(r1.Timestamp,@util)    
GROUP BY PSname,r1.datestamp,PSdate
ORDER BY PSdate
END

Answer : Modify SQL SP to ignore initial Start Value

OK,

That will be in :

UPDATE #reportdata
SET    DataChange = #reportdata.Data - isnull(prev.data,@prevval)
FROM   #ReportData
left outer join #reportdata prev on #reportdata.id - 1 = prev.id


If there isnt a previous value, then we can do :

UPDATE #reportdata
SET    DataChange = #reportdata.Data - isnull(prev.data,#reportdata.Data)
FROM   #ReportData
left outer join #reportdata prev on #reportdata.id - 1 = prev.id


That also means we no longer need :

SET @PrevVal = isnull( (SELECT top 1 convert(real,Data) * @grate
                        FROM HistorianDB.dbo.TLData
                        WHERE TLInstance = @Meter
                        AND timestamp < @sdate
                        AND Type=0
                        AND isnumeric(data)=1
                        ORDER BY timestamp desc) , 0)

I think the original insert into the reportdata table did include ealier entries which is another option - minimise any inaccuracy by openin the range a little bit for the update, then make sure we only report on the specific range (or remove out of range rows after the update).




Random Solutions  
 
programming4us programming4us