TSQL - Referencing a changed value from previous row










1















I am trying to do a row calculation whereby the larger value will carry forward to the subsequent rows until a larger value is being compared. It is done by comparing the current value to the previous row using the lag() function.



Code



DECLARE @TAB TABLE (id varchar(1),d1 INT , d2 INT)

INSERT INTO @TAB (id,d1,d2)

VALUES ('A',0,5)
,('A',1,2)
,('A',2,4)
,('A',3,6)
,('B',0,4)
,('B',2,3)
,('B',3,2)
,('B',4,5)

SELECT id
,d1
,d2 = CASE WHEN id <> (LAG(id,1,0) OVER (ORDER BY id,d1)) THEN d2
WHEN d2 < (LAG(d2,1,0) OVER (ORDER BY id,d1)) THEN (LAG(d2,1,0) OVER (ORDER BY id,d1))
ELSE d2 END


Output (Added row od2 for clarity)



 +----+----+----+ +----+
| id | d1 | d2 | | od2|
+----+----+----+ +----+
| A | 0 | 5 | | 5 |
| A | 1 | 5 | | 2 |
| A | 2 | 4 | | 4 |
| A | 3 | 6 | | 6 |
| B | 0 | 4 | | 4 |
| B | 2 | 4 | | 3 |
| B | 3 | 3 | | 2 |
| B | 4 | 5 | | 5 |
+----+----+----+ +----+


As you can see from the output it lag function is referencing the original value of the previous row rather than the new value. Is there anyway to achieve this?



Desired Output



 +----+----+----+ +----+
| id | d1 | d2 | | od2|
+----+----+----+ +----+
| A | 0 | 5 | | 5 |
| A | 1 | 5 | | 2 |
| A | 2 | 5 | | 4 |
| A | 3 | 6 | | 6 |
| B | 0 | 4 | | 4 |
| B | 2 | 4 | | 3 |
| B | 3 | 4 | | 2 |
| B | 4 | 5 | | 5 |
+----+----+----+ +----+









share|improve this question


























    1















    I am trying to do a row calculation whereby the larger value will carry forward to the subsequent rows until a larger value is being compared. It is done by comparing the current value to the previous row using the lag() function.



    Code



    DECLARE @TAB TABLE (id varchar(1),d1 INT , d2 INT)

    INSERT INTO @TAB (id,d1,d2)

    VALUES ('A',0,5)
    ,('A',1,2)
    ,('A',2,4)
    ,('A',3,6)
    ,('B',0,4)
    ,('B',2,3)
    ,('B',3,2)
    ,('B',4,5)

    SELECT id
    ,d1
    ,d2 = CASE WHEN id <> (LAG(id,1,0) OVER (ORDER BY id,d1)) THEN d2
    WHEN d2 < (LAG(d2,1,0) OVER (ORDER BY id,d1)) THEN (LAG(d2,1,0) OVER (ORDER BY id,d1))
    ELSE d2 END


    Output (Added row od2 for clarity)



     +----+----+----+ +----+
    | id | d1 | d2 | | od2|
    +----+----+----+ +----+
    | A | 0 | 5 | | 5 |
    | A | 1 | 5 | | 2 |
    | A | 2 | 4 | | 4 |
    | A | 3 | 6 | | 6 |
    | B | 0 | 4 | | 4 |
    | B | 2 | 4 | | 3 |
    | B | 3 | 3 | | 2 |
    | B | 4 | 5 | | 5 |
    +----+----+----+ +----+


    As you can see from the output it lag function is referencing the original value of the previous row rather than the new value. Is there anyway to achieve this?



    Desired Output



     +----+----+----+ +----+
    | id | d1 | d2 | | od2|
    +----+----+----+ +----+
    | A | 0 | 5 | | 5 |
    | A | 1 | 5 | | 2 |
    | A | 2 | 5 | | 4 |
    | A | 3 | 6 | | 6 |
    | B | 0 | 4 | | 4 |
    | B | 2 | 4 | | 3 |
    | B | 3 | 4 | | 2 |
    | B | 4 | 5 | | 5 |
    +----+----+----+ +----+









    share|improve this question
























      1












      1








      1








      I am trying to do a row calculation whereby the larger value will carry forward to the subsequent rows until a larger value is being compared. It is done by comparing the current value to the previous row using the lag() function.



      Code



      DECLARE @TAB TABLE (id varchar(1),d1 INT , d2 INT)

      INSERT INTO @TAB (id,d1,d2)

      VALUES ('A',0,5)
      ,('A',1,2)
      ,('A',2,4)
      ,('A',3,6)
      ,('B',0,4)
      ,('B',2,3)
      ,('B',3,2)
      ,('B',4,5)

      SELECT id
      ,d1
      ,d2 = CASE WHEN id <> (LAG(id,1,0) OVER (ORDER BY id,d1)) THEN d2
      WHEN d2 < (LAG(d2,1,0) OVER (ORDER BY id,d1)) THEN (LAG(d2,1,0) OVER (ORDER BY id,d1))
      ELSE d2 END


      Output (Added row od2 for clarity)



       +----+----+----+ +----+
      | id | d1 | d2 | | od2|
      +----+----+----+ +----+
      | A | 0 | 5 | | 5 |
      | A | 1 | 5 | | 2 |
      | A | 2 | 4 | | 4 |
      | A | 3 | 6 | | 6 |
      | B | 0 | 4 | | 4 |
      | B | 2 | 4 | | 3 |
      | B | 3 | 3 | | 2 |
      | B | 4 | 5 | | 5 |
      +----+----+----+ +----+


      As you can see from the output it lag function is referencing the original value of the previous row rather than the new value. Is there anyway to achieve this?



      Desired Output



       +----+----+----+ +----+
      | id | d1 | d2 | | od2|
      +----+----+----+ +----+
      | A | 0 | 5 | | 5 |
      | A | 1 | 5 | | 2 |
      | A | 2 | 5 | | 4 |
      | A | 3 | 6 | | 6 |
      | B | 0 | 4 | | 4 |
      | B | 2 | 4 | | 3 |
      | B | 3 | 4 | | 2 |
      | B | 4 | 5 | | 5 |
      +----+----+----+ +----+









      share|improve this question














      I am trying to do a row calculation whereby the larger value will carry forward to the subsequent rows until a larger value is being compared. It is done by comparing the current value to the previous row using the lag() function.



      Code



      DECLARE @TAB TABLE (id varchar(1),d1 INT , d2 INT)

      INSERT INTO @TAB (id,d1,d2)

      VALUES ('A',0,5)
      ,('A',1,2)
      ,('A',2,4)
      ,('A',3,6)
      ,('B',0,4)
      ,('B',2,3)
      ,('B',3,2)
      ,('B',4,5)

      SELECT id
      ,d1
      ,d2 = CASE WHEN id <> (LAG(id,1,0) OVER (ORDER BY id,d1)) THEN d2
      WHEN d2 < (LAG(d2,1,0) OVER (ORDER BY id,d1)) THEN (LAG(d2,1,0) OVER (ORDER BY id,d1))
      ELSE d2 END


      Output (Added row od2 for clarity)



       +----+----+----+ +----+
      | id | d1 | d2 | | od2|
      +----+----+----+ +----+
      | A | 0 | 5 | | 5 |
      | A | 1 | 5 | | 2 |
      | A | 2 | 4 | | 4 |
      | A | 3 | 6 | | 6 |
      | B | 0 | 4 | | 4 |
      | B | 2 | 4 | | 3 |
      | B | 3 | 3 | | 2 |
      | B | 4 | 5 | | 5 |
      +----+----+----+ +----+


      As you can see from the output it lag function is referencing the original value of the previous row rather than the new value. Is there anyway to achieve this?



      Desired Output



       +----+----+----+ +----+
      | id | d1 | d2 | | od2|
      +----+----+----+ +----+
      | A | 0 | 5 | | 5 |
      | A | 1 | 5 | | 2 |
      | A | 2 | 5 | | 4 |
      | A | 3 | 6 | | 6 |
      | B | 0 | 4 | | 4 |
      | B | 2 | 4 | | 3 |
      | B | 3 | 4 | | 2 |
      | B | 4 | 5 | | 5 |
      +----+----+----+ +----+






      sql sql-server tsql sql-server-2012






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 16 '18 at 7:54









      KyriveKyrive

      424




      424






















          2 Answers
          2






          active

          oldest

          votes


















          2














          Try this:



          SELECT id
          ,d1
          ,d2
          ,MAX(d2) OVER (PARTITION BY ID ORDER BY d1)
          FROM @TAB


          enter image description here



          The idea is to use the MAX to get the max value from the beginning to the current row for each partition.






          share|improve this answer






























            0














            Thanks for providing the DDL scripts and the DML.



            One way of doing it would be using recursive cte as follows.
            1. First rank all the records according to id, d1 and d2. -> cte block
            2. Use recursive cte and get the first elements using rnk=1
            3. the field "compared_val" will check against the values from the previous rnk to see if the value is > than the existing and if so it would swap



            DECLARE @TAB TABLE (id varchar(1),d1 INT , d2 INT)

            INSERT INTO @TAB (id,d1,d2)

            VALUES ('A',0,5)
            ,('A',1,2)
            ,('A',2,4)
            ,('A',3,6)
            ,('B',0,4)
            ,('B',2,3)
            ,('B',3,2)
            ,('B',4,5)

            ;with cte
            as (select row_number() over(partition by id order by d1,d2) as rnk
            ,id,d1,d2
            from @TAB
            )
            ,data(rnk,id,d1,d2,compared_val)
            as (select rnk,id,d1,d2,d2 as compared_val
            from cte
            where rnk=1
            union all
            select a.rnk,a.id,a.d1,a.d2,case when b.compared_val > a.d2 then
            b.compared_val
            else a.d2
            end
            from cte a
            join data b
            on a.id=b.id
            and a.rnk=b.rnk+1
            )
            select * from data order by id,d1,d2





            share|improve this answer























              Your Answer






              StackExchange.ifUsing("editor", function ()
              StackExchange.using("externalEditor", function ()
              StackExchange.using("snippets", function ()
              StackExchange.snippets.init();
              );
              );
              , "code-snippets");

              StackExchange.ready(function()
              var channelOptions =
              tags: "".split(" "),
              id: "1"
              ;
              initTagRenderer("".split(" "), "".split(" "), channelOptions);

              StackExchange.using("externalEditor", function()
              // Have to fire editor after snippets, if snippets enabled
              if (StackExchange.settings.snippets.snippetsEnabled)
              StackExchange.using("snippets", function()
              createEditor();
              );

              else
              createEditor();

              );

              function createEditor()
              StackExchange.prepareEditor(
              heartbeatType: 'answer',
              autoActivateHeartbeat: false,
              convertImagesToLinks: true,
              noModals: true,
              showLowRepImageUploadWarning: true,
              reputationToPostImages: 10,
              bindNavPrevention: true,
              postfix: "",
              imageUploader:
              brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
              contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
              allowUrls: true
              ,
              onDemand: true,
              discardSelector: ".discard-answer"
              ,immediatelyShowMarkdownHelp:true
              );



              );













              draft saved

              draft discarded


















              StackExchange.ready(
              function ()
              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53333586%2ftsql-referencing-a-changed-value-from-previous-row%23new-answer', 'question_page');

              );

              Post as a guest















              Required, but never shown

























              2 Answers
              2






              active

              oldest

              votes








              2 Answers
              2






              active

              oldest

              votes









              active

              oldest

              votes






              active

              oldest

              votes









              2














              Try this:



              SELECT id
              ,d1
              ,d2
              ,MAX(d2) OVER (PARTITION BY ID ORDER BY d1)
              FROM @TAB


              enter image description here



              The idea is to use the MAX to get the max value from the beginning to the current row for each partition.






              share|improve this answer



























                2














                Try this:



                SELECT id
                ,d1
                ,d2
                ,MAX(d2) OVER (PARTITION BY ID ORDER BY d1)
                FROM @TAB


                enter image description here



                The idea is to use the MAX to get the max value from the beginning to the current row for each partition.






                share|improve this answer

























                  2












                  2








                  2







                  Try this:



                  SELECT id
                  ,d1
                  ,d2
                  ,MAX(d2) OVER (PARTITION BY ID ORDER BY d1)
                  FROM @TAB


                  enter image description here



                  The idea is to use the MAX to get the max value from the beginning to the current row for each partition.






                  share|improve this answer













                  Try this:



                  SELECT id
                  ,d1
                  ,d2
                  ,MAX(d2) OVER (PARTITION BY ID ORDER BY d1)
                  FROM @TAB


                  enter image description here



                  The idea is to use the MAX to get the max value from the beginning to the current row for each partition.







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Nov 16 '18 at 7:59









                  gotqngotqn

                  20.8k32119194




                  20.8k32119194























                      0














                      Thanks for providing the DDL scripts and the DML.



                      One way of doing it would be using recursive cte as follows.
                      1. First rank all the records according to id, d1 and d2. -> cte block
                      2. Use recursive cte and get the first elements using rnk=1
                      3. the field "compared_val" will check against the values from the previous rnk to see if the value is > than the existing and if so it would swap



                      DECLARE @TAB TABLE (id varchar(1),d1 INT , d2 INT)

                      INSERT INTO @TAB (id,d1,d2)

                      VALUES ('A',0,5)
                      ,('A',1,2)
                      ,('A',2,4)
                      ,('A',3,6)
                      ,('B',0,4)
                      ,('B',2,3)
                      ,('B',3,2)
                      ,('B',4,5)

                      ;with cte
                      as (select row_number() over(partition by id order by d1,d2) as rnk
                      ,id,d1,d2
                      from @TAB
                      )
                      ,data(rnk,id,d1,d2,compared_val)
                      as (select rnk,id,d1,d2,d2 as compared_val
                      from cte
                      where rnk=1
                      union all
                      select a.rnk,a.id,a.d1,a.d2,case when b.compared_val > a.d2 then
                      b.compared_val
                      else a.d2
                      end
                      from cte a
                      join data b
                      on a.id=b.id
                      and a.rnk=b.rnk+1
                      )
                      select * from data order by id,d1,d2





                      share|improve this answer



























                        0














                        Thanks for providing the DDL scripts and the DML.



                        One way of doing it would be using recursive cte as follows.
                        1. First rank all the records according to id, d1 and d2. -> cte block
                        2. Use recursive cte and get the first elements using rnk=1
                        3. the field "compared_val" will check against the values from the previous rnk to see if the value is > than the existing and if so it would swap



                        DECLARE @TAB TABLE (id varchar(1),d1 INT , d2 INT)

                        INSERT INTO @TAB (id,d1,d2)

                        VALUES ('A',0,5)
                        ,('A',1,2)
                        ,('A',2,4)
                        ,('A',3,6)
                        ,('B',0,4)
                        ,('B',2,3)
                        ,('B',3,2)
                        ,('B',4,5)

                        ;with cte
                        as (select row_number() over(partition by id order by d1,d2) as rnk
                        ,id,d1,d2
                        from @TAB
                        )
                        ,data(rnk,id,d1,d2,compared_val)
                        as (select rnk,id,d1,d2,d2 as compared_val
                        from cte
                        where rnk=1
                        union all
                        select a.rnk,a.id,a.d1,a.d2,case when b.compared_val > a.d2 then
                        b.compared_val
                        else a.d2
                        end
                        from cte a
                        join data b
                        on a.id=b.id
                        and a.rnk=b.rnk+1
                        )
                        select * from data order by id,d1,d2





                        share|improve this answer

























                          0












                          0








                          0







                          Thanks for providing the DDL scripts and the DML.



                          One way of doing it would be using recursive cte as follows.
                          1. First rank all the records according to id, d1 and d2. -> cte block
                          2. Use recursive cte and get the first elements using rnk=1
                          3. the field "compared_val" will check against the values from the previous rnk to see if the value is > than the existing and if so it would swap



                          DECLARE @TAB TABLE (id varchar(1),d1 INT , d2 INT)

                          INSERT INTO @TAB (id,d1,d2)

                          VALUES ('A',0,5)
                          ,('A',1,2)
                          ,('A',2,4)
                          ,('A',3,6)
                          ,('B',0,4)
                          ,('B',2,3)
                          ,('B',3,2)
                          ,('B',4,5)

                          ;with cte
                          as (select row_number() over(partition by id order by d1,d2) as rnk
                          ,id,d1,d2
                          from @TAB
                          )
                          ,data(rnk,id,d1,d2,compared_val)
                          as (select rnk,id,d1,d2,d2 as compared_val
                          from cte
                          where rnk=1
                          union all
                          select a.rnk,a.id,a.d1,a.d2,case when b.compared_val > a.d2 then
                          b.compared_val
                          else a.d2
                          end
                          from cte a
                          join data b
                          on a.id=b.id
                          and a.rnk=b.rnk+1
                          )
                          select * from data order by id,d1,d2





                          share|improve this answer













                          Thanks for providing the DDL scripts and the DML.



                          One way of doing it would be using recursive cte as follows.
                          1. First rank all the records according to id, d1 and d2. -> cte block
                          2. Use recursive cte and get the first elements using rnk=1
                          3. the field "compared_val" will check against the values from the previous rnk to see if the value is > than the existing and if so it would swap



                          DECLARE @TAB TABLE (id varchar(1),d1 INT , d2 INT)

                          INSERT INTO @TAB (id,d1,d2)

                          VALUES ('A',0,5)
                          ,('A',1,2)
                          ,('A',2,4)
                          ,('A',3,6)
                          ,('B',0,4)
                          ,('B',2,3)
                          ,('B',3,2)
                          ,('B',4,5)

                          ;with cte
                          as (select row_number() over(partition by id order by d1,d2) as rnk
                          ,id,d1,d2
                          from @TAB
                          )
                          ,data(rnk,id,d1,d2,compared_val)
                          as (select rnk,id,d1,d2,d2 as compared_val
                          from cte
                          where rnk=1
                          union all
                          select a.rnk,a.id,a.d1,a.d2,case when b.compared_val > a.d2 then
                          b.compared_val
                          else a.d2
                          end
                          from cte a
                          join data b
                          on a.id=b.id
                          and a.rnk=b.rnk+1
                          )
                          select * from data order by id,d1,d2






                          share|improve this answer












                          share|improve this answer



                          share|improve this answer










                          answered Nov 16 '18 at 8:10









                          George JosephGeorge Joseph

                          1,590510




                          1,590510



























                              draft saved

                              draft discarded
















































                              Thanks for contributing an answer to Stack Overflow!


                              • Please be sure to answer the question. Provide details and share your research!

                              But avoid


                              • Asking for help, clarification, or responding to other answers.

                              • Making statements based on opinion; back them up with references or personal experience.

                              To learn more, see our tips on writing great answers.




                              draft saved


                              draft discarded














                              StackExchange.ready(
                              function ()
                              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53333586%2ftsql-referencing-a-changed-value-from-previous-row%23new-answer', 'question_page');

                              );

                              Post as a guest















                              Required, but never shown





















































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown

































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown







                              Popular posts from this blog

                              Top Tejano songwriter Luis Silva dead of heart attack at 64

                              政党

                              天津地下鉄3号線