Since the question does not indicate that the solution is the "only" request ;-), here is another approach: using the "quirky update" function, which updates the variable, at the same time you update the column. Overcoming the complexity of this operation, I create a scratch table to hold the piece that is most difficult to calculate: EP_ID
. Once this is done, it will be combined into a simple query and will provide a window for calculating the fields EP_IN_DATETIME
and EP_OUT_DATETIME
.
Steps:
- Create Scratch Table
- Put a scratch table with all the
ADM_ID
values - this allows us to do UPDATE since all rows already exist. - Refresh Scratch Table
- Make the final, simple choice connecting the scratch table to the main table.
Test setup
SET ANSI_NULLS ON; SET NOCOUNT ON; CREATE TABLE
Step 1. Create and populate a Scratch table
CREATE TABLE #Scratch ( ADM_ID INT NOT NULL PRIMARY KEY, EP_ID INT NOT NULL -- Might need WH_PID and WH_IN_DATETIME fields to guarantee proper UPDATE ordering ); INSERT INTO #Scratch (ADM_ID, EP_ID) SELECT ADM_ID, 0 FROM #Table;
An alternative scratch table structure to ensure the correct update order (since the “fancy update” uses the cluster index order as indicated at the bottom of this answer):
CREATE TABLE #Scratch ( WH_PID INT NOT NULL, WH_IN_DATETIME DATETIME NOT NULL, ADM_ID INT NOT NULL, EP_ID INT NOT NULL ); INSERT INTO #Scratch (WH_PID, WH_IN_DATETIME, ADM_ID, EP_ID) SELECT WH_PID, WH_IN_DATETIME, ADM_ID, 0 FROM #Table; CREATE UNIQUE CLUSTERED INDEX [CIX_Scratch] ON #Scratch (WH_PID, WH_IN_DATETIME, ADM_ID);
Step 2: update the Scratch Table using a local variable to track the previous value
DECLARE @EP_ID INT; -- this is used in the UPDATE ;WITH cte AS ( SELECT TOP (100) PERCENT t1.*, t2.WH_OUT_DATETIME AS [PriorOut], t2.ADM_ID AS [PriorID], ROW_NUMBER() OVER (PARTITION BY t1.WH_PID ORDER BY t1.WH_IN_DATETIME) AS [RowNum] FROM
Step 3: Select “Attach Scratch Table”
SELECT tab.ADM_ID, tab.WH_PID, sc.EP_ID, MIN(tab.WH_IN_DATETIME) OVER (PARTITION BY tab.WH_PID, sc.EP_ID) AS [EP_IN_DATETIME], MAX(tab.WH_OUT_DATETIME) OVER (PARTITION BY tab.WH_PID, sc.EP_ID) AS [EP_OUT_DATETIME], tab.WH_IN_DATETIME, tab.WH_OUT_DATETIME FROM
Resources
MSDN Page for UPDATE
look for "@variable = column = expression"
Performance analysis of current results (not quite the same as here, but not too far)
This blog post mentions:
- PRO: this method is usually pretty fast
- CON: "The UPDATE order is controlled by the order of the clustered index." Such behavior may preclude the use of this method as the case may be. But in this particular case, if the
WH_PID
values are at least not naturally grouped by ordering the clustered index and ordered by WH_IN_DATETIME
, then these two fields are simply added to the scratch table and PK (with the implied clustered index) becomes (WH_PID, WH_IN_DATETIME, ADM_ID)
.