2

I needed to develop a scheduled job to be executed daily at nights. I've completed the task but had to use a While loop. Which makes me feel "guilty". I'm in need of some advices about how to convert this operation into a set-based operation and increase the performance.

My table looks like (simplified it as much as possible) :

T_POOL
PoolID | ContactID | ContactState
  1    |     1     |      1
  1    |     2     |      1
  1    |     3     |      1
  2    |     4     |      2
  2    |     5     |      3

 T_POOL_DEC
 PoolID | Layer4ID
   1    |    1
   2    |    3
   3    |    5

 T_LAYER4
 Layer4ID | ConditionValue1(Count) | ConditionValue2(Month)
    1     |       5                | 3

The reason why I've used a while loop is to retrieve ContactID values (as a group) relative to the PoolID. Storing distinct poolID values in a temp table and fetching these poolID values in a loop.So my While Loop, loops through Distinct values of PoolIDs (not looping through all the table row-by-row) And i'm doing update operations, which can be demonstrated like :

  While (True)
    Take Next @PoolID

    Update T_Pool TP SET ContactState ={some value} 
    INNER JOIN T_POOL_DEC PD ON PD.PoolID = TP.PoolID
    INNER JOIN T_LAYER4 L4 ON L4.Layer4ID = PD.Layer4ID
    Where {COUNT(TP.ContactID) >= L4.ConditionValue1 
    AND ContactID.CreateDate >=DATEADD(MM,L4.ConditionValue2*-1,GETDATE()}
    AND PoolID = @PoolID

    If it has passed through all available PoolIDs, break;
  END

I hope I could demonstrate the situation as clear as possible, since im not able to write all the query here.

Edit for comments : Forgot to add that, What prevents me from updating the whole table is, PoolID is a FK above. And each PoolID has a Layer4ID, I'm making some calculations for each ContactID in a Pool depending on Layer4 values of that PoolID (like counting each contact in a pool depending on their state, and checking if the count result is equal or greater than its Pool's Layer4 value. Editing my table demonstration part to be more clear.

So as It can be seen above, each Pool has a Layer4ID. And each Layer4 has some conditions, in this case those are both integers (ConditionValue1 indicates the minimum count of ContactIDs to be updated(updating the state in T_POOL table i mean) and ConditionValue2 indicates the number of months past of current Date for each Contact to be treated as valid. (to update its state) -Retrieving ContactID's create date from its own table.-

Edit2 Added some joins to my sample query (ignore syntax error, group by etc)

Edit3

My current query can be seen as follows : So simply, this needs to be "freed" from while loop, namely, eliminating @PoolID usages.

UPDATE T_POOL SET ContactState= 4
WHERE PoolID= @PoolID AND ContactState=2
AND EXISTS(
SELECT T.ContactID FROM(
   SELECT TP.ContactID,
      L4.ConditionValue1,
      COUNT(TP.ContactID) OVER (PARTITION BY TP.PoolID) AS TOTAL_CONTACT_COUNT
   FROM Contact C
   INNER JOIN T_POOL TP ON TP.ContactID= C.ContactID
   INNER JOIN T_POOL_DEC PD ON PD.PoolID = TP.PoolID
       INNER JOIN T_LAYER4 L4 ON L4.Layer4ID = PD.Layer4ID
   WHERE PD.PoolID= @PoolID AND TP.State=2 AND TP.LOG_STATUS NOT IN (9,10) AND  C.LOG_CREATE_DATE >= DATEADD(MM,L4.ConditionValue2*-1,GETDATE()))T 

 WHERE T.TOTAL_CONTACT_COUNT>=T.ConditionValue1 AND C.ContactID= ContactID)
OzanYukruk
  • 205
  • 4
  • 13
  • 1
    Based on your code here, there is no need for a WHILE loop. In fact, I'd say that 99% of the time there's no need for a WHILE loop in a RDBMS – Stuart Ainsworth Nov 18 '11 at 19:11
  • 1
    You're going to have to expand a bit more. What is it about the update statement that prevents you from just updating the whoel table at once? – Derek Kromm Nov 18 '11 at 19:13
  • 2
    Even after the edits I don't see why you can't make it set-based. – JNK Nov 18 '11 at 20:07
  • 1
    Solved my issue with a set-based approach, the thing is that i simply didnt focus on "thinking" set-based, before posting this. – OzanYukruk Nov 20 '11 at 15:49

0 Answers0