I'm trying to do an Excel kind of calculation in SQL. This involves using the closing rate (ClRate) from the previous row and using it to calculate values in the next row. The table starts from 1 Jan and has 1000 rows and each row has known data and data which needs to be calculated (shown in [ ])
Date RecQty RecAmt IssQty IssAmt ClQty ClAmt ClRate
1 Jan - - - - 100 $20,000 200
2 Jan +10 +$2100 -5 [ ] [ ] [ ] [ ]
The calculations to generate the desired result are in the table below
Date RecQty RecAmt IssQty IssAmt ClQty ClAmt ClRate
1 Jan 100 $20,000 200
2 Jan +10 +$2100 -5 -[200*5] [100+10-5] [20,000+2100-200*5] [ClAmt/ClQty]
The IssAmt for each day will be calculated by multiplying the IssQty by the previous days' ClRate. The ClQty is computed as previous day ClQty + current day RecQty - current day IssQty. The ClAmt is computed as previous day ClAmt+ current day RecAmt - current day IssAmt. Finally, the ClRate for each day is computed as ClAmt / ClQty
The only ClRate known is the opening inventory row of the table (1 Jan)- thereafter the ClRate for each subsequent row needs to be computed.
In Excel, you would simply do this calculation by linking the required cells of the previous row and copying/pasting the formula to all the rows below.
How would you do this in SQL? I have tried self joining CTEs, loops and LAG- none of these seems to work. The reason is that the ClRate for each row from 2 Jan onwards is not known - and while Excel can handle computing results on the fly which are used in the following row - SQL is unable to do this.
Seeking help to solve this problem. I'm using SQL Server 2017 and SSMS. If required I can provide the code
Table DDL
CREATE TABLE [Auto].[IronOreTbl](
[Id] [int] NULL,
[Counter] [int] NULL,
[TDate] [date] NOT NULL,
[RecQty] [decimal](16, 2) NULL,
[RecAmt] [decimal](16, 2) NULL,
[IssQty] [decimal](16, 2) NULL,
[IssAmt] [decimal](16, 2) NULL,
[ClQty] [decimal](16, 2) NULL,
[ClAmt] [decimal](16, 2) NULL,
[ClRate] [decimal](16, 2) NULL
) ON [PRIMARY]
GO
INSERT INTO [Auto].[IronOreTbl]
([Id],[Counter],[TDate],[RecQty],[RecAmt],[IssQty],[IssAmt],[ClQty],[ClAmt],[ClRate])
VALUES
(1,0,'2019-01-01',NULL,NULL,NULL,NULL,100,20000,200),
(2,1,'2019-01-02',10,2100,5,NULL,105,NULL,NULL),
(3,2,'2019-01-03',8,1600,2,NULL,111,NULL,NULL),
(4,3,'2019-01-04',20,2400,10,NULL,121,NULL,NULL)
CTE attempts
;WITH ClAmtCTE AS
(
SELECT
Id,RecQty,RecAmt,IssQty,ClQty,ClAmt,ClRate
,EffRate = ClRate
,CumHoldVal= ClAmt
--CAST(ClAmt AS decimal(16,2))
,CumClRt=CAST(ClRate AS decimal(16,2))
,[Counter]
FROM
[Auto].IronOreTbl
WHERE
Id=1
UNION ALL
SELECT
C2.Id,C2.RecQty,c2.RecAmt,C2.IssQty,C2.ClQty,C2.ClAmt,c2.ClRate,
EffRate = (SELECT CumClRt WHERE C2.ID=C2.[Counter]+1),
CumRN =
CAST(
(
CumHoldVal+ISNULL(C2.RecAmt,0)-
(EffRate)*ISNULL(C2.IssQty,0)
)
AS decimal(16,2)
),
CumClRt=CAST(CumHoldVal/C2.ClQty AS decimal(16,2)),
C2.[Counter],
FROM
[Auto].IronOreTbl C2
INNER JOIN ClAmtCTE C1 ON C1.Id = C2.[Counter]
The following code achieves the desired result - while I had got close several days ago, it still took all this time to tie up the last bit; of matching the ClRate with the correct row. There was an additional issue encountered where on days where there are no issues, but only receipts, the rate picked up belonged to the wrong row (I still have no clue why and how this was happening - all I know is that the previous code needed revision to resolve this discrepancy and the modified code attends to the same)
;WITH ClAmtCTE AS
(
SELECT
Id,RecQty,RecAmt,IssQty,ClQty,ClAmt,ClRate
,EffRate = ClRate
,CumHoldVal= ClAmt
--CAST(ClAmt AS decimal(16,2))
,CumClRt=CAST(ClRate AS decimal(16,2))
,[Counter]
FROM
[Auto].IronOreTbl
WHERE
Id=1
UNION ALL
SELECT
C2.Id,C2.RecQty,c2.RecAmt,C2.IssQty,C2.ClQty,C2.ClAmt,c2.ClRate,
EffRate = (SELECT CumClRt WHERE C2.ID=C2.[Counter]+1),
CumRN =
CAST(
(
CumHoldVal+ISNULL(C2.RecAmt,0)-
((SELECT CumClRt WHERE C2.ID=C2.[Counter]+1))*ISNULL(C2.IssQty,0)
)
AS decimal(16,2)
),
CumClRt=CAST((CumHoldVal+ISNULL(C2.RecAmt,0)-
((SELECT CumClRt WHERE C2.ID=C2.[Counter]+1))*ISNULL(C2.IssQty,0))/C2.ClQty AS decimal(16,2)),
C2.[Counter]
FROM
[Auto].IronOreTblC2
INNER JOIN ClAmtCTE C1 ON C1.Id = C2.[Counter]
)
UPDATE [Auto].IronOreTbl
SET ClRate = T1.CumClRt,
ClAmt=CumHoldVal
FROM ClAmtCTE T1
INNER JOIN [Auto].IronOreTbl T2
ON T1.ID = T2.Id
OPTION (MAXRECURSION 0)
Attempting and, in what appears to me as, solving it has taught me several things. Primarily these include:
Calculations which you can set up and run in a heartbeat in a spreadsheet are anything but in SQL
Excel has the ability to both calculate on the fly and utilise results calculated on the fly in the dependent calculations. SQL cannot do this. Having this ability in Excel means you do not have to iterate over the data - once to have Excel compute the results and then for Excel to apply the results where they are needed
For all its use and utility as a data housing medium SQL has a long way to go in attending to standard real world calculations - such as this example; multiple loans, changing interest rates and relevant interest calculations etc etc.
Related
I have the following tables:
Episodes:
Clients:
My DAX calculation sums up [Days_epi] unique values, from Episodes tbl, grouping them by [ProgramID_epi], [EpisodeID_epi], [ClientID_epi].
So, the SUM of [Days_epi] = 3 + 5 + 31 + 8 + 15 + 20 + 10 = 92
Here is my working code for this:
DaysSUM =
CALCULATE (
SUMX (
SUMMARIZE (
'Episodes',
'Episodes'[EpisodeID_epi],
'Episodes'[ProgramID_epi],
'Episodes'[ClientID_epi],
'Episodes'[Days_epi]
),
'Episodes'[Days_epi]
),
FILTER (
'Episodes',
'Episodes'[Category_epi] = "Homeless"
)
)
I need to add two advanced filters to the calculation above:
Filter 1 should ONLY KEEP records in Episodes, if the records in the Clients have the difference between [DischDate_clnt] and [AdmDate_clnt] >= 365.
Filter 1 in SQL statement is
DATEDIFF(DAY, [AdmDate_clnt], [DischDate_clnt]) >= 365)
After that, Filter 2 should ONLY KEEP records in Episodes, if the records in the Clients have
[Date_clnt] >= [AdmDate_clnt] + 12 months. (12 month after the Admission Date)
Filter 2 in SQL statement is
[Date_clnt] <= DATEADD(MONTH, 12, [[AdmDate_clnt])
So, after applying those two filters I expect the records 6 and 10 of the Episodes tbl must be excluded (filtered out), because the records 2 and 3 of the Clients tbl (highlighted in green) are not satisfied my Filter 1 / Filter 2.
Here is the final Episodes dataset I should have (without the 2 records in red):
I was starting to update my DAX code as the following (below).
But keep receiving error "Parameter is not the correct type"
enter
DaysSUM_Filters =
CALCULATE (
SUMX (
SUMMARIZE (
'Episodes',
'Episodes'[EpisodeID_epi],
'Episodes'[ProgramID_epi],
'Episodes'[ClientID_epi],
'Episodes'[Days_epi]
),
'Episodes'[Days_epi]
),
FILTER (
'Episodes',
'Episodes'[Category_epi] = "Homeless"
), TREATAS(DATEDIFF('Clients'[AdmDate_clnt],
'Clients'[DischDate_clnt], DAY)>=365,
'Clients'[Date_clnt])
)
Not exactly sure how to set those 2 filters correctly in DAX Power BI, as I
am relatively new to it.
Please help!
I can't say about all the case. But what is obvious is that you use TREATAS in a wrong way. It works like this TREATAS({"Red", "White", "Blue"}, 'Product'[Color]).
In your case
DATEDIFF('Clients'[AdmDate_clnt],
'Clients'[DischDate_clnt], DAY)>=365
will return TRUE or FALSE value. The first argument of TREATAS - is a column or set of columns not a single value.
You can use the filter like this:
FILTER(
'Clients'
,DATEDIFF(
'Clients'[AdmDate_clnt]
,'Clients'[DischDate_clnt]
,DAY
)>=365
)
This will return you a filtered table.
This may work if your tables are linked.
I am new to SQL. I have a problem which I would like to solve.
I would like to duplicate rows from an existing table - "Reports" within the same "Reports" table for tasks that remain outstanding from the previous financial year (e.g. 2021) to the new financial year (e.g. 2022).
If "TaskACompletedDate" and "TaskBCompletedDate" are not completed, it will remain outstanding and carried forward from Financial Year "2021" to "2022".
We will need to check for users who roll over the outstanding items from Financial Year "2021" to "2022" to ensure that there is no duplicate.
If the outstanding items are already roll-over, then check for whether there is an update on "TaskADueDate" and "TaskBDueDate" and update the changes accordingly.
My code is as below. But it is not working as expected.
/* Code for table creation */
IF NOT EXISTS (
select * from sysobjects where name='Report' and xtype='U')
CREATE TABLE Report (
[ReportId] INT,
[TaskADueDate] DATETIME,
[TaskACompletedDate] DATETIME,
[TaskBDueDate] DATETIME,
[TaskBCompletedDate] DATETIME,
[FinancialYear] INT
);
INSERT INTO Report VALUES
(1,'2021-12-12 00:00:00','2021-12-12 00:00:00','2021-12-31
00:00:00','2021-12-31 00:00:00',2021),
(2,'2021-12-13 00:00:00',NULL,'2022-01-01 00:00:00',NULL,2021),
(3,'2022-02-01 00:00:00',NULL,'2022-03-02 00:00:00',NULL,2021),
(4,'2022-02-02 00:00:00',NULL,'2022-03-03 00:00:00',NULL,2021);
/* Code for Roll Over to next financial year */
DECLARE #FinancialYearFrom int,
DECLARE #FinancialYearTo int
SET #FinancialYearFrom = 2021
SET #FinancialYearTo = 2022
/*View Outstanding Tasks in FY2021*/
SELECT * FROM REPORT TABLE
WHERE FinancialYear = #FinancialYearFrom AND TaskACompletedDate IS NULL AND TasKBCompletedDate IS NULL
/*Check rows to ensure that the rows in ReportID 2,3,4 is not carried forward to FY2022.
If copied over, just update DueDate if there is any changes.*/
IF(SELECT COUNT(*) FROM Report WHERE FinancialYear = #FinancialYearTo) <> 0
Update Report SET
TaskADueDate = NewTaskADueDate
TaskBDueDate = NewTaskBDueDate
ELSE
INSERT INTO Report (TaskADueDate, TaskACompletedDate, TaskBDueDate, TaskBCompletedDate, FinancialYear)
VALUES (SELECT TOP (1) [TaskADueDate] FROM Report WHERE FinancialYear = #FinancialYearFrom,
SELECT TOP (1) [TaskACompletedDate] FROM Report WHERE FinancialYear = #FinancialYearFrom,
SELECT TOP (1) [TaskBDueDate] FROM Report WHERE FinancialYear = #FinancialYearFrom,
SELECT TOP (1) [TaskBDueDate] FROM Report WHERE FinancialYear = #FinancialYearFrom,
#FinancialYearTo)
As an example, I'm just adding 10 to your ReportId to create the new rows, since you didn't use any kind of auto_increment in your schema. Just replace the fixed year with a parameter as needed.
The fiddle
INSERT INTO Report
SELECT ReportId + 10
, TaskADueDate, TaskACompletedDate
, TaskBDueDate, TaskBCompletedDate
, FinancialYear + 1
FROM Report
WHERE FinancialYear = 2021
AND (TaskBCompletedDate IS NULL AND TaskACompletedDate IS NULL)
;
Note: It's not possible to perform your UPDATE logic without a reference to the original row, or an additional key (unique per year) which allows joining the rows. Add that detail to the design and the question, if you want to update existing rows based on prior "related" rows.
Sample Data
SELECT A.PRDDATE, A.PRDTIM || '000' AS PRDTIM,
A.MACHCD, A.PRDCNT AS INPRDCNT, A.USEDWGT AS INUSEDWGT, ROUND(A.STDWGT,2) AS INSTDWGT, A.RATE*100 AS INRATE, A.PERWGT AS INPERWGT, ' ' AS INREMARK, B.PRDCNT AS OUTPRCNT, B.USEDWGT AS OUTUSEDWGT, ROUND(B.STDWGT,2) AS OUTSTDWGT, B.RATE*100 AS OUTRATE, B.PERWGT AS OUTPERWGT, ' ' AS OUTREMARK FROM (
SELECT A.PRDDATE, SUBSTR(A.PRDTIME,1,3) AS PRDTIM, MAX(A.MACHCD) AS MACHCD,
MIN(A.REFCNT) AS MINCNT, MAX(A.REFCNT) AS MAXCNT, DOUBLE(MAX(A.REFCNT)) - DOUBLE(MIN(A.REFCNT)) AS PRDCNT, DOUBLE(MIN(A.WEIGHT)) AS MINWGT, DOUBLE(MAX(A.WEIGHT)) AS MAXWGT, DOUBLE(MAX(A.WEIGHT))-DOUBLE(MIN(A.WEIGHT)) AS USEDWGT, DOUBLE(DOUBLE(MAX(A.REFCNT)) - DOUBLE(MIN(A.REFCNT)))*0.02 AS STDWGT, ROUND((DOUBLE(MAX(A.WEIGHT))-DOUBLE(MIN(A.WEIGHT))-(DOUBLE(DOUBLE(MAX(A.REFCNT)) - DOUBLE(MIN(A.REFCNT)))*0.02))/(DOUBLE(DOUBLE(MAX(A.REFCNT)) - DOUBLE(MIN(A.REFCNT)))*0.02),2) AS RATE, ROUND((DOUBLE(MAX(WEIGHT))-DOUBLE(MIN(WEIGHT)))/(DOUBLE(MAX(REFCNT)) - DOUBLE(MIN(REFCNT)))*1000,1) AS PERWGT FROM AGIF.POP3750 A WHERE WDATE = #{wdate} AND MACHCD = #{machcd} AND POSITION = 'I' GROUP BY A.PRDDATE,SUBSTR(A.PRDTIME,1,3) ORDER BY A.PRDDATE,SUBSTR(A.PRDTIME,1,3) ) A LEFT JOIN ( SELECT PRDDATE, SUBSTR(PRDTIME,1,3) AS PRDTIM,
MAX(MACHCD) AS MACHCD,
MIN(REFCNT) AS MINCNT, MAX(REFCNT) AS MAXCNT, DOUBLE(MAX(REFCNT)) - DOUBLE(MIN(REFCNT)) AS PRDCNT, DOUBLE(MIN(WEIGHT)) AS MINWGT, DOUBLE(MAX(WEIGHT)) AS MAXWGT, DOUBLE(MAX(WEIGHT))-DOUBLE(MIN(WEIGHT)) AS USEDWGT, DOUBLE(DOUBLE(MAX(REFCNT)) - DOUBLE(MIN(REFCNT)))*0.011 AS STDWGT, ROUND((DOUBLE(MAX(WEIGHT))-DOUBLE(MIN(WEIGHT))-(DOUBLE(DOUBLE(MAX(REFCNT)) - DOUBLE(MIN(REFCNT)))*0.011))/(DOUBLE(DOUBLE(MAX(REFCNT)) - DOUBLE(MIN(REFCNT)))*0.011),2) AS RATE, ROUND((DOUBLE(MAX(WEIGHT))-DOUBLE(MIN(WEIGHT)))/(DOUBLE(MAX(REFCNT)) - DOUBLE(MIN(REFCNT)))*1000,1) AS PERWGT FROM AGIF.POP3750 WHERE WDATE =#{wdate} AND MACHCD = #{machcd} AND "POSITION" = 'O' GROUP BY PRDDATE, SUBSTR(PRDTIME,1,3) ORDER BY PRDDATE, SUBSTR(PRDTIME,1,3) ) B ON A.PRDDATE = B.PRDDATE AND A.PRDTIM = B.PRDTIM ORDER BY A.PRDDATE,A.PRDTIM
This is my code currently. The database currently stores information by 1 minute intervals. I used SUBSTR to group the data into 10 minute intervals. However, I think that when it is being grouped, it is not including a line of data. For example, if 7:00 - 7:10 is grouped, when 7:10 - 7:20 is grouped, it should include 7:10 in the grouping, but is grouping from 7:11 - 7:20. Any suggestions on how to include that line of data, or another way of grouping by time intervals?
CREATE TABLE AGIF.POP3750 (
PRDDATE CHAR(8) DEFAULT ' ' NOT NULL,
PRDTIME CHAR(6) DEFAULT ' ' NOT NULL,
MACHCD CHAR(6) DEFAULT ' ' NOT NULL,
DST_FLAG CHAR(1) DEFAULT ' ' NOT NULL,
"POSITION" CHAR(1) DEFAULT ' ' NOT NULL,
WDATE CHAR(8) DEFAULT NULL,
WSHT CHAR(1) DEFAULT NULL,
REFCNT NUMERIC(6,0) DEFAULT NULL,
WEIGHT CHAR(6) DEFAULT NULL,
UPLOAD CHAR(14) DEFAULT NULL
SELECT GRP, COUNT(1) CNT
FROM
(
SELECT
T.V_TRUNCATED - (CASE V.I WHEN 2 THEN 10 ELSE 0 END) MINUTES GRP
, T.V
FROM
(
SELECT V, V - 60*MOD(MINUTE(V), 10) - SECOND(V) V_TRUNCATED
FROM
(
VALUES
TIME('07.00.00')
, TIME('07.05.00')
, TIME('07.10.00')
, TIME('07.15.00')
, TIME('07.18.00')
, TIME('07.20.00')
) T (V)
) T, (VALUES 1, 2) V(I)
WHERE V.I=1 OR V.I=2 AND T.V = T.V_TRUNCATED
)
GROUP BY GRP;
|GRP |CNT |
|--------|-----------|
|06:50:00|1 |
|07:00:00|3 |
|07:10:00|4 |
|07:20:00|1 |
Here is an idea how to do this on sample data. You may run it as is, add / change the values to check if it's suitable for you.
Brief description of what happens here.
First of all, we compute the V_TRUNCATED column for each row - time truncated to tens of minutes.
Secondly, if you want some row to be computed in different groups according to your requirements, then you must "copy" this row. This is why we cross-join our initial set of rows with a virtual table of 2 rows. The row is copied, if the actual time value is equal to its truncated one only.
Finally, the grouping expression is calculated as follows: if it's not copied row, then leave it as is, and if it's copied one, then subtract 10 minutes from it (to make it come to a previous group).
If such an algorithm is not suitable for you, then provide the result desired on my sample data.
I have a table with different objects and the objects evolve over time. One object is identified by object_number and we can track it with the object_line_number. And every evolution of the object has a status.
I want to calculate the time elapsed between some status.
Below is my table for one object_number "us1":
In yellow are the rowscontaining the starting date. They are found if (status_id = 0 and (old_status <> 0 or object_line_number = 1) and emergency_level = 1).
In green are the rows containing the ending date. They are found if (status_id =2,3,4,5 and old_status = 0).
The column old_status does not exist in the table. This is the status of the previous row (according to the object)line_number). I am retrieving it thanks to the following measure:
old_status = CALCULATE (
MAX(fact_object[status_id]),
FILTER (
ALL(fact_object),
fact_object[object_line_number] = IF(fact_object[object_line_number]=1, fact_object[object_line_number], MAX (fact_object[object_line_number])-1)),
VALUES (fact_object[object_number]))
I am in DirectQuery mode, so a lot of functions are not present for Calculated Columns, that's why I am using Measures.
Once that is done, I want then to be able to get for every green row the date_modification of the previous yellow row.
In this example, the result would be 4/4 then 1. So that I can calculate the time difference between the date_modification of the current green row and the date_modification of the previous yellow row.
So I was thinking of adding a new column named date_received, which is the date_modification of the previous yellow row;
From there, I just have to keep only the green rows and calculate the difference between date_modification and date_received.
My final calcul is actually to have this :
Result = (number of green rows which date difference between date_modification and date_received <= 15 min) / (number of green rows
which DAY(date_modification) = DAY(date_received))
But I don't know how to do it.
I have tried in the same spirit of the old_status measure to do this:
date_received = CALCULATE (
MAX(fact_object[date_modification]),
FILTER (
ALL(fact_object),
(fact_object[object_line_number] = MAX (fact_object[object_line_number])-1) && MY OTHER FILTERS
),
VALUES (fact_object[object_number])
)
But didn't succeed.
In SQL, the equivalent would be like this:
SELECT
SUM(CASE WHEN (DATEDIFF(MINUTE, T.date_received, T.date_planification) <= 15) THEN 1 ELSE 0 END) /
SUM(CASE WHEN (DAY(T.date_received) = DAY(T.date_planification)) THEN 1 ELSE 0 END) as result
FROM (
SELECT *, T.status_id as current_status,
LAG(T.date_modification) OVER(PARTITION BY T.object_number ORDER BY T.object_line_number) as date_received,
T.date_modification as date_planification
FROM
(
select *,
LAG (status_id) OVER(PARTITION BY object_number ORDER BY object_line_number) AS old_status
from dbo.fact_object
) AS T
WHERE ((T.status_id = 0 AND (T.old_status <> 0 OR T.object_line_number = 1) AND T.emergency_level = 1) OR (T.old_status = 0 AND T.status_id IN (2,3,4,5)))--974
) AS T
WHERE old_status = 0
(Well maybe there is a better way to do it in SQL that I've done).
How can I achieve this?
In this case, I would first sort the table by Object then by Object Line number (or Date Modified - but these appear not to change for each row.)
Duplicate the table
Table1 - Add an index starting at 1
Table2 - Add an index starting at 0
From Table1, merge it with table2, using the new index fields
Expand the MergedStatus ID (rename to NextStatusID) and the Object (rename to NextObject) field.
You can now create a new conditional column to compare the two status fields. E.g. Status 2 = If Object = NextObject then [NextStatusID] else null
My first question here..!
I'm not an expert in SQL, so bear over with me please! :)
I have a web page (not created by me) which gets report data from a MSSQL database, on the web page you enter start date and end date and data are fetched in this time interval from 00:00 on start date until 23:59 on end date.
I have managed to add more queries to the SQL, but now I would like to, for certain values only to return values which were logged in the time range 00:00:00 until 04:00:00 every day in the selected time interval.
Currently values are logged once an hour, but not always consistently. So far I have made a workaround in my web page which shows the first 4 values and skips the next 20, this loops for the selected interval. This method works 98% of the time, but occasionally there are more or fewer than 24 logged values per day which can cause the shown values will be skewed one way or another.
What I would like to do is change my SQL query so that it only returns values in the time range I want (between midnight and 04:00) for every day in the selected period. I hope someone can help me achieve this or give me some hints! :)
This is the existing SQL query running with the variables which I do want all values for. There are more variables than this but I edited them out, all the Ren*Time variables is the ones I want to make a 4-hour-every-day version of.
SET NOCOUNT ON;
IF OBJECT_ID('tempdb..#tmpValues') IS NOT NULL BEGIN DROP TABLE #tmpValues END;
CREATE TABLE #tmpValues(Id INT PRIMARY KEY IDENTITY(1,1),BatchId INT, TimePoint DATETIME, Ren1Time DECIMAL(10,2), Ren2Time DECIMAL(10,2), Ren3Time DECIMAL(10,2), RenTotTime DECIMAL(10,2));
INSERT INTO #tmpValues(BatchId)
SELECT BatchId
FROM Batch
WHERE Batch.LogTime BETWEEN <StartTime> AND <StopTime>;
CREATE UNIQUE INDEX I_BatcId ON #tmpValues(BatchId);
UPDATE #tmpValues SET
TimePoint = (SELECT LogTime FROM Batch WHERE Batch.BatchId = #tmpValues.BatchId),
Ren1Time = (SELECT SUM(_Float) FROM LogData WHERE LogData.BatchId = #tmpValues.BatchId AND LogData.TagId = 21),
Ren2Time = (SELECT SUM(_Float) FROM LogData WHERE LogData.BatchId = #tmpValues.BatchId AND LogData.TagId = 25),
Ren3Time = (SELECT SUM(_Float) FROM LogData WHERE LogData.BatchId = #tmpValues.BatchId AND LogData.TagId = 29),
RenTotTime = (SELECT SUM(_Float) FROM LogData WHERE LogData.BatchId = #tmpValues.BatchId AND (LogData.TagId = 25 OR LogData.TagId = 29 OR LogData.TagId = 33));
DECLARE
#TimePoint DATETIME,
#Ren1Time FLOAT,
#Ren2Time FLOAT,
#Ren3Time FLOAT,
#RenTotTime FLOAT;
INSERT INTO #tmpValues(TimePoint, Ren1Time, Ren2Time, Ren3Time, RenTotTime)
VALUES(#TimePoint, #Ren1Time, #Ren2Time,#Ren3Time, #RenTotTime);
SET NOCOUNT OFF;
SELECT * FROM #tmpValues;
IF OBJECT_ID('tempdb..#tmpValues') IS NOT NULL BEGIN DROP TABLE #tmpValues END;
Don't mess around with temp tables and processing every column separately. I also have no idea what you're trying to do with those variables. You declare them, never set them, then do an INSERT with them, which will just insert a row of NULL values.
Assuming that you're using SQL Server, the DATEPART function will let you get the hour of the day.
SELECT
B.BatchID,
B.LogTime AS TimePoint,
SUM(CASE WHEN B.TagId = 21 THEN _Float ELSE 0 END) AS Ren1Time,
SUM(CASE WHEN B.TagId = 25 THEN _Float ELSE 0 END) AS Ren2Time,
SUM(CASE WHEN B.TagId = 29 THEN _Float ELSE 0 END) AS Ren3Time,
SUM(CASE WHEN B.TagId IN (21, 25, 29) THEN _Float ELSE 0 END) AS RenTotTime
FROM
dbo.Batch B
INNER JOIN LogData LD ON LD.BatchId = B.BatchId
WHERE
B.LogTime BETWEEN <StartTime> AND <StopTime> AND
DATEPART(HOUR, B.LogTime) BETWEEN 0 AND 4
GROUP BY
B.BatchID,
B.TimePoint
Thank you very much for your swift reply!
I couldn't exactly get your suggestion to work, but I did solve my problem thanks to your suggestion!
Since the SQL query which should be limited to the 4 hours is used only from one webpage and there are no values in this web page which should be shown for all 24 hours, I thought I could copy the existing .SQL file to a new file and simply change the following:
WHERE Batch.LogTime BETWEEN <StartTime> AND <StopTime>;
To
WHERE Batch.LogTime BETWEEN <StartTime> AND <StopTime> AND DATEPART(HOUR, Batch.LogTime) BETWEEN 0 AND 3;
I changed the call to the .SQL file in the web page from the old to the new file and it works! Simple as that! Also changed 0 AND 4 to 0 AND 3 since I found 03:59:59 will be included, which is exactly what I want :)