Finding lowest two minimum values and finding difference between the two in SQL Server?











up vote
0
down vote

favorite












I have a transaction table where I have to find the first and second date of transaction of every customer. Finding first date is very simple where I can use MIN() func to find the first date but the second and in particular finding the difference between the two is getting very challenging and somehow I am not able to find out any feasible way:



select a.customer_id, a.transaction_date, a.Row_Count2
from ( select
transaction_date as transaction_date,
reference_no as customer_id,
row_number() over (partition by reference_no
ORDER BY reference_no, transaction_date) AS Row_Count2
from transaction_detail
) a
where a.Row_Count2 < 3
ORDER BY a.customer_id, a.transaction_date, a.Row_Count2


Gives me this :



enter image description here



What I want is , following columns:



||CustomerID|| ||FirstDateofPurchase|| ||SecondDateofPuchase|| ||Diff. b/w Second & First Date ||










share|improve this question
























  • Please explain the results that you want. The query seems to answer your question.
    – Gordon Linoff
    Nov 13 at 19:21












  • ||CustomerID|| ||First Date of Purchase || || SubsequentSecond Date of Purchase|| || Diff. b/w Second & First Date ||
    – user9230890
    Nov 13 at 19:24






  • 1




    Are the results not what you want? If not, it seems like you could remove the reference_no from the order by to fix the ordering.
    – scsimon
    Nov 13 at 19:25















up vote
0
down vote

favorite












I have a transaction table where I have to find the first and second date of transaction of every customer. Finding first date is very simple where I can use MIN() func to find the first date but the second and in particular finding the difference between the two is getting very challenging and somehow I am not able to find out any feasible way:



select a.customer_id, a.transaction_date, a.Row_Count2
from ( select
transaction_date as transaction_date,
reference_no as customer_id,
row_number() over (partition by reference_no
ORDER BY reference_no, transaction_date) AS Row_Count2
from transaction_detail
) a
where a.Row_Count2 < 3
ORDER BY a.customer_id, a.transaction_date, a.Row_Count2


Gives me this :



enter image description here



What I want is , following columns:



||CustomerID|| ||FirstDateofPurchase|| ||SecondDateofPuchase|| ||Diff. b/w Second & First Date ||










share|improve this question
























  • Please explain the results that you want. The query seems to answer your question.
    – Gordon Linoff
    Nov 13 at 19:21












  • ||CustomerID|| ||First Date of Purchase || || SubsequentSecond Date of Purchase|| || Diff. b/w Second & First Date ||
    – user9230890
    Nov 13 at 19:24






  • 1




    Are the results not what you want? If not, it seems like you could remove the reference_no from the order by to fix the ordering.
    – scsimon
    Nov 13 at 19:25













up vote
0
down vote

favorite









up vote
0
down vote

favorite











I have a transaction table where I have to find the first and second date of transaction of every customer. Finding first date is very simple where I can use MIN() func to find the first date but the second and in particular finding the difference between the two is getting very challenging and somehow I am not able to find out any feasible way:



select a.customer_id, a.transaction_date, a.Row_Count2
from ( select
transaction_date as transaction_date,
reference_no as customer_id,
row_number() over (partition by reference_no
ORDER BY reference_no, transaction_date) AS Row_Count2
from transaction_detail
) a
where a.Row_Count2 < 3
ORDER BY a.customer_id, a.transaction_date, a.Row_Count2


Gives me this :



enter image description here



What I want is , following columns:



||CustomerID|| ||FirstDateofPurchase|| ||SecondDateofPuchase|| ||Diff. b/w Second & First Date ||










share|improve this question















I have a transaction table where I have to find the first and second date of transaction of every customer. Finding first date is very simple where I can use MIN() func to find the first date but the second and in particular finding the difference between the two is getting very challenging and somehow I am not able to find out any feasible way:



select a.customer_id, a.transaction_date, a.Row_Count2
from ( select
transaction_date as transaction_date,
reference_no as customer_id,
row_number() over (partition by reference_no
ORDER BY reference_no, transaction_date) AS Row_Count2
from transaction_detail
) a
where a.Row_Count2 < 3
ORDER BY a.customer_id, a.transaction_date, a.Row_Count2


Gives me this :



enter image description here



What I want is , following columns:



||CustomerID|| ||FirstDateofPurchase|| ||SecondDateofPuchase|| ||Diff. b/w Second & First Date ||







sql sql-server






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 13 at 19:49









paparazzo

37.3k1673134




37.3k1673134










asked Nov 13 at 19:20









user9230890

2013




2013












  • Please explain the results that you want. The query seems to answer your question.
    – Gordon Linoff
    Nov 13 at 19:21












  • ||CustomerID|| ||First Date of Purchase || || SubsequentSecond Date of Purchase|| || Diff. b/w Second & First Date ||
    – user9230890
    Nov 13 at 19:24






  • 1




    Are the results not what you want? If not, it seems like you could remove the reference_no from the order by to fix the ordering.
    – scsimon
    Nov 13 at 19:25


















  • Please explain the results that you want. The query seems to answer your question.
    – Gordon Linoff
    Nov 13 at 19:21












  • ||CustomerID|| ||First Date of Purchase || || SubsequentSecond Date of Purchase|| || Diff. b/w Second & First Date ||
    – user9230890
    Nov 13 at 19:24






  • 1




    Are the results not what you want? If not, it seems like you could remove the reference_no from the order by to fix the ordering.
    – scsimon
    Nov 13 at 19:25
















Please explain the results that you want. The query seems to answer your question.
– Gordon Linoff
Nov 13 at 19:21






Please explain the results that you want. The query seems to answer your question.
– Gordon Linoff
Nov 13 at 19:21














||CustomerID|| ||First Date of Purchase || || SubsequentSecond Date of Purchase|| || Diff. b/w Second & First Date ||
– user9230890
Nov 13 at 19:24




||CustomerID|| ||First Date of Purchase || || SubsequentSecond Date of Purchase|| || Diff. b/w Second & First Date ||
– user9230890
Nov 13 at 19:24




1




1




Are the results not what you want? If not, it seems like you could remove the reference_no from the order by to fix the ordering.
– scsimon
Nov 13 at 19:25




Are the results not what you want? If not, it seems like you could remove the reference_no from the order by to fix the ordering.
– scsimon
Nov 13 at 19:25












2 Answers
2






active

oldest

votes

















up vote
0
down vote



accepted










You can use window functions LEAD/LAG to return results you are looking for



First try to find all the leading dates by reference number using LEAD, generate row number for each row using your original logic. You can then do difference on dates for row number value 1 row from the result set.



Ex (I'm not excluding same day transactions and treating them as separate and generating row number based on result set from your query above, you can easily change the sql below to consider these as one and remove them so that you get next date as second date):



declare @tbl table(reference_no int, transaction_date datetime)
insert into @tbl
select 1000, '2018-07-11'
UNION ALL
select 1001, '2018-07-12'
UNION ALL
select 1001, '2018-07-12'
UNIOn ALL
select 1001, '2018-07-13'
UNIOn ALL
select 1002, '2018-07-11'
UNIOn ALL
select 1002, '2018-07-15'

select customer_id, transaction_date as firstdate,
transaction_date_next seconddate,
datediff(day, transaction_date, transaction_date_next) diff_in_days
from
(
select reference_no as customer_id, transaction_date,
lead(transaction_date) over (partition by reference_no
order by transaction_date) transaction_date_next,
row_number() over (partition by reference_no ORDER BY transaction_date) AS Row_Count
from @tbl
) src
where Row_Count = 1





share|improve this answer





















  • I am not aware of Lead/Lag func in SQL and still do not understand them but somehow your solution worked. Thank You.
    – user9230890
    Nov 13 at 21:27


















up vote
0
down vote













You can do this with CROSS APPLY.



SELECT td.customer_id, MIN(ca.transaction_date), MAX(ca.transaction_date),
DATEDIFF(day, MIN(ca.transaction_date), MAX(ca.transaction_date))
FROM transaction_detail td
CROSS APPLY (SELECT TOP 2 *
FROM transaction_detail
WHERE customer_id = td.customer_id
ORDER BY transaction_date) ca
GROUP BY td.customer_id





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',
    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%2f53288098%2ffinding-lowest-two-minimum-values-and-finding-difference-between-the-two-in-sql%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








    up vote
    0
    down vote



    accepted










    You can use window functions LEAD/LAG to return results you are looking for



    First try to find all the leading dates by reference number using LEAD, generate row number for each row using your original logic. You can then do difference on dates for row number value 1 row from the result set.



    Ex (I'm not excluding same day transactions and treating them as separate and generating row number based on result set from your query above, you can easily change the sql below to consider these as one and remove them so that you get next date as second date):



    declare @tbl table(reference_no int, transaction_date datetime)
    insert into @tbl
    select 1000, '2018-07-11'
    UNION ALL
    select 1001, '2018-07-12'
    UNION ALL
    select 1001, '2018-07-12'
    UNIOn ALL
    select 1001, '2018-07-13'
    UNIOn ALL
    select 1002, '2018-07-11'
    UNIOn ALL
    select 1002, '2018-07-15'

    select customer_id, transaction_date as firstdate,
    transaction_date_next seconddate,
    datediff(day, transaction_date, transaction_date_next) diff_in_days
    from
    (
    select reference_no as customer_id, transaction_date,
    lead(transaction_date) over (partition by reference_no
    order by transaction_date) transaction_date_next,
    row_number() over (partition by reference_no ORDER BY transaction_date) AS Row_Count
    from @tbl
    ) src
    where Row_Count = 1





    share|improve this answer





















    • I am not aware of Lead/Lag func in SQL and still do not understand them but somehow your solution worked. Thank You.
      – user9230890
      Nov 13 at 21:27















    up vote
    0
    down vote



    accepted










    You can use window functions LEAD/LAG to return results you are looking for



    First try to find all the leading dates by reference number using LEAD, generate row number for each row using your original logic. You can then do difference on dates for row number value 1 row from the result set.



    Ex (I'm not excluding same day transactions and treating them as separate and generating row number based on result set from your query above, you can easily change the sql below to consider these as one and remove them so that you get next date as second date):



    declare @tbl table(reference_no int, transaction_date datetime)
    insert into @tbl
    select 1000, '2018-07-11'
    UNION ALL
    select 1001, '2018-07-12'
    UNION ALL
    select 1001, '2018-07-12'
    UNIOn ALL
    select 1001, '2018-07-13'
    UNIOn ALL
    select 1002, '2018-07-11'
    UNIOn ALL
    select 1002, '2018-07-15'

    select customer_id, transaction_date as firstdate,
    transaction_date_next seconddate,
    datediff(day, transaction_date, transaction_date_next) diff_in_days
    from
    (
    select reference_no as customer_id, transaction_date,
    lead(transaction_date) over (partition by reference_no
    order by transaction_date) transaction_date_next,
    row_number() over (partition by reference_no ORDER BY transaction_date) AS Row_Count
    from @tbl
    ) src
    where Row_Count = 1





    share|improve this answer





















    • I am not aware of Lead/Lag func in SQL and still do not understand them but somehow your solution worked. Thank You.
      – user9230890
      Nov 13 at 21:27













    up vote
    0
    down vote



    accepted







    up vote
    0
    down vote



    accepted






    You can use window functions LEAD/LAG to return results you are looking for



    First try to find all the leading dates by reference number using LEAD, generate row number for each row using your original logic. You can then do difference on dates for row number value 1 row from the result set.



    Ex (I'm not excluding same day transactions and treating them as separate and generating row number based on result set from your query above, you can easily change the sql below to consider these as one and remove them so that you get next date as second date):



    declare @tbl table(reference_no int, transaction_date datetime)
    insert into @tbl
    select 1000, '2018-07-11'
    UNION ALL
    select 1001, '2018-07-12'
    UNION ALL
    select 1001, '2018-07-12'
    UNIOn ALL
    select 1001, '2018-07-13'
    UNIOn ALL
    select 1002, '2018-07-11'
    UNIOn ALL
    select 1002, '2018-07-15'

    select customer_id, transaction_date as firstdate,
    transaction_date_next seconddate,
    datediff(day, transaction_date, transaction_date_next) diff_in_days
    from
    (
    select reference_no as customer_id, transaction_date,
    lead(transaction_date) over (partition by reference_no
    order by transaction_date) transaction_date_next,
    row_number() over (partition by reference_no ORDER BY transaction_date) AS Row_Count
    from @tbl
    ) src
    where Row_Count = 1





    share|improve this answer












    You can use window functions LEAD/LAG to return results you are looking for



    First try to find all the leading dates by reference number using LEAD, generate row number for each row using your original logic. You can then do difference on dates for row number value 1 row from the result set.



    Ex (I'm not excluding same day transactions and treating them as separate and generating row number based on result set from your query above, you can easily change the sql below to consider these as one and remove them so that you get next date as second date):



    declare @tbl table(reference_no int, transaction_date datetime)
    insert into @tbl
    select 1000, '2018-07-11'
    UNION ALL
    select 1001, '2018-07-12'
    UNION ALL
    select 1001, '2018-07-12'
    UNIOn ALL
    select 1001, '2018-07-13'
    UNIOn ALL
    select 1002, '2018-07-11'
    UNIOn ALL
    select 1002, '2018-07-15'

    select customer_id, transaction_date as firstdate,
    transaction_date_next seconddate,
    datediff(day, transaction_date, transaction_date_next) diff_in_days
    from
    (
    select reference_no as customer_id, transaction_date,
    lead(transaction_date) over (partition by reference_no
    order by transaction_date) transaction_date_next,
    row_number() over (partition by reference_no ORDER BY transaction_date) AS Row_Count
    from @tbl
    ) src
    where Row_Count = 1






    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Nov 13 at 19:36









    rs.

    20.1k75280




    20.1k75280












    • I am not aware of Lead/Lag func in SQL and still do not understand them but somehow your solution worked. Thank You.
      – user9230890
      Nov 13 at 21:27


















    • I am not aware of Lead/Lag func in SQL and still do not understand them but somehow your solution worked. Thank You.
      – user9230890
      Nov 13 at 21:27
















    I am not aware of Lead/Lag func in SQL and still do not understand them but somehow your solution worked. Thank You.
    – user9230890
    Nov 13 at 21:27




    I am not aware of Lead/Lag func in SQL and still do not understand them but somehow your solution worked. Thank You.
    – user9230890
    Nov 13 at 21:27












    up vote
    0
    down vote













    You can do this with CROSS APPLY.



    SELECT td.customer_id, MIN(ca.transaction_date), MAX(ca.transaction_date),
    DATEDIFF(day, MIN(ca.transaction_date), MAX(ca.transaction_date))
    FROM transaction_detail td
    CROSS APPLY (SELECT TOP 2 *
    FROM transaction_detail
    WHERE customer_id = td.customer_id
    ORDER BY transaction_date) ca
    GROUP BY td.customer_id





    share|improve this answer



























      up vote
      0
      down vote













      You can do this with CROSS APPLY.



      SELECT td.customer_id, MIN(ca.transaction_date), MAX(ca.transaction_date),
      DATEDIFF(day, MIN(ca.transaction_date), MAX(ca.transaction_date))
      FROM transaction_detail td
      CROSS APPLY (SELECT TOP 2 *
      FROM transaction_detail
      WHERE customer_id = td.customer_id
      ORDER BY transaction_date) ca
      GROUP BY td.customer_id





      share|improve this answer

























        up vote
        0
        down vote










        up vote
        0
        down vote









        You can do this with CROSS APPLY.



        SELECT td.customer_id, MIN(ca.transaction_date), MAX(ca.transaction_date),
        DATEDIFF(day, MIN(ca.transaction_date), MAX(ca.transaction_date))
        FROM transaction_detail td
        CROSS APPLY (SELECT TOP 2 *
        FROM transaction_detail
        WHERE customer_id = td.customer_id
        ORDER BY transaction_date) ca
        GROUP BY td.customer_id





        share|improve this answer














        You can do this with CROSS APPLY.



        SELECT td.customer_id, MIN(ca.transaction_date), MAX(ca.transaction_date),
        DATEDIFF(day, MIN(ca.transaction_date), MAX(ca.transaction_date))
        FROM transaction_detail td
        CROSS APPLY (SELECT TOP 2 *
        FROM transaction_detail
        WHERE customer_id = td.customer_id
        ORDER BY transaction_date) ca
        GROUP BY td.customer_id






        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Nov 13 at 19:49

























        answered Nov 13 at 19:44









        Derrick Moeller

        2,51321333




        2,51321333






























            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.





            Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


            Please pay close attention to the following guidance:


            • 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%2f53288098%2ffinding-lowest-two-minimum-values-and-finding-difference-between-the-two-in-sql%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

            How to send String Array data to Server using php in android

            Title Spacing in Bjornstrup Chapter, Removing Chapter Number From Contents

            Is anime1.com a legal site for watching anime?