Rank order grouped data in MySQL without session variables?












2















My data looks like this:



Table Name = sales_orders

Customer_id| Order_id| Item_Id
-------------------------------
1 | 1 | 10
1 | 1 | 24
1 | 1 | 37
1 | 2 | 11
1 | 2 | 15
1 | 3 | 28
2 | 4 | 37
4 | 6 | 10
2 | 7 | 10


However, I need it to look like this:



Customer_id| Order_id| Item_Id |Order_rank
------------------------------------------
1 | 1 | 10 | 1
1 | 1 | 24 | 1
1 | 1 | 37 | 1
1 | 2 | 11 | 2
1 | 2 | 15 | 2
1 | 3 | 28 | 3
2 | 4 | 37 | 1
4 | 6 | 10 | 1
2 | 7 | 10 | 2


Customer_Id is a unique person



Order_id is a unique order



item_id is the product code



To further explain, the first three lines are from Customer #1's first order (order_id = 1) where this person ordered 3 different items (10,24, and 37). They then purchased another order (order_id =2) with two other products. Person with customer_id =2 has 2 unique orders (4 and 6), while customer with ID '4' has one unique order (order_id =6)



Essentially, what I need to do is rank these orders by customer_id and order Id, so that I can say "Order_id = 7 is the second order for customer_id = 2, because Order_rank = 2"



The challenge here is that I can't use session variables (e.g. @grp := customer_id ) in the MySQL query



For example, a query such as this is NOT allowed:



SELECT 
customer_id,
order_id,
@ss := CASE WHEN @grp = customer_id THEN @ss + 1 ELSE 1 END AS
order_rank,
@grp := customer_id
FROM
(
SELECT
customer_id,
order_id
FROM sales_orders
GROUP BY customer_id, order_id
ORDER BY customer_id, order_id ASC
) AS t_1
CROSS JOIN (SELECT @ss := 0, @grp = NULL)ss

ORDER BY customer_id asc


Thanks for the help!










share|improve this question



























    2















    My data looks like this:



    Table Name = sales_orders

    Customer_id| Order_id| Item_Id
    -------------------------------
    1 | 1 | 10
    1 | 1 | 24
    1 | 1 | 37
    1 | 2 | 11
    1 | 2 | 15
    1 | 3 | 28
    2 | 4 | 37
    4 | 6 | 10
    2 | 7 | 10


    However, I need it to look like this:



    Customer_id| Order_id| Item_Id |Order_rank
    ------------------------------------------
    1 | 1 | 10 | 1
    1 | 1 | 24 | 1
    1 | 1 | 37 | 1
    1 | 2 | 11 | 2
    1 | 2 | 15 | 2
    1 | 3 | 28 | 3
    2 | 4 | 37 | 1
    4 | 6 | 10 | 1
    2 | 7 | 10 | 2


    Customer_Id is a unique person



    Order_id is a unique order



    item_id is the product code



    To further explain, the first three lines are from Customer #1's first order (order_id = 1) where this person ordered 3 different items (10,24, and 37). They then purchased another order (order_id =2) with two other products. Person with customer_id =2 has 2 unique orders (4 and 6), while customer with ID '4' has one unique order (order_id =6)



    Essentially, what I need to do is rank these orders by customer_id and order Id, so that I can say "Order_id = 7 is the second order for customer_id = 2, because Order_rank = 2"



    The challenge here is that I can't use session variables (e.g. @grp := customer_id ) in the MySQL query



    For example, a query such as this is NOT allowed:



    SELECT 
    customer_id,
    order_id,
    @ss := CASE WHEN @grp = customer_id THEN @ss + 1 ELSE 1 END AS
    order_rank,
    @grp := customer_id
    FROM
    (
    SELECT
    customer_id,
    order_id
    FROM sales_orders
    GROUP BY customer_id, order_id
    ORDER BY customer_id, order_id ASC
    ) AS t_1
    CROSS JOIN (SELECT @ss := 0, @grp = NULL)ss

    ORDER BY customer_id asc


    Thanks for the help!










    share|improve this question

























      2












      2








      2








      My data looks like this:



      Table Name = sales_orders

      Customer_id| Order_id| Item_Id
      -------------------------------
      1 | 1 | 10
      1 | 1 | 24
      1 | 1 | 37
      1 | 2 | 11
      1 | 2 | 15
      1 | 3 | 28
      2 | 4 | 37
      4 | 6 | 10
      2 | 7 | 10


      However, I need it to look like this:



      Customer_id| Order_id| Item_Id |Order_rank
      ------------------------------------------
      1 | 1 | 10 | 1
      1 | 1 | 24 | 1
      1 | 1 | 37 | 1
      1 | 2 | 11 | 2
      1 | 2 | 15 | 2
      1 | 3 | 28 | 3
      2 | 4 | 37 | 1
      4 | 6 | 10 | 1
      2 | 7 | 10 | 2


      Customer_Id is a unique person



      Order_id is a unique order



      item_id is the product code



      To further explain, the first three lines are from Customer #1's first order (order_id = 1) where this person ordered 3 different items (10,24, and 37). They then purchased another order (order_id =2) with two other products. Person with customer_id =2 has 2 unique orders (4 and 6), while customer with ID '4' has one unique order (order_id =6)



      Essentially, what I need to do is rank these orders by customer_id and order Id, so that I can say "Order_id = 7 is the second order for customer_id = 2, because Order_rank = 2"



      The challenge here is that I can't use session variables (e.g. @grp := customer_id ) in the MySQL query



      For example, a query such as this is NOT allowed:



      SELECT 
      customer_id,
      order_id,
      @ss := CASE WHEN @grp = customer_id THEN @ss + 1 ELSE 1 END AS
      order_rank,
      @grp := customer_id
      FROM
      (
      SELECT
      customer_id,
      order_id
      FROM sales_orders
      GROUP BY customer_id, order_id
      ORDER BY customer_id, order_id ASC
      ) AS t_1
      CROSS JOIN (SELECT @ss := 0, @grp = NULL)ss

      ORDER BY customer_id asc


      Thanks for the help!










      share|improve this question














      My data looks like this:



      Table Name = sales_orders

      Customer_id| Order_id| Item_Id
      -------------------------------
      1 | 1 | 10
      1 | 1 | 24
      1 | 1 | 37
      1 | 2 | 11
      1 | 2 | 15
      1 | 3 | 28
      2 | 4 | 37
      4 | 6 | 10
      2 | 7 | 10


      However, I need it to look like this:



      Customer_id| Order_id| Item_Id |Order_rank
      ------------------------------------------
      1 | 1 | 10 | 1
      1 | 1 | 24 | 1
      1 | 1 | 37 | 1
      1 | 2 | 11 | 2
      1 | 2 | 15 | 2
      1 | 3 | 28 | 3
      2 | 4 | 37 | 1
      4 | 6 | 10 | 1
      2 | 7 | 10 | 2


      Customer_Id is a unique person



      Order_id is a unique order



      item_id is the product code



      To further explain, the first three lines are from Customer #1's first order (order_id = 1) where this person ordered 3 different items (10,24, and 37). They then purchased another order (order_id =2) with two other products. Person with customer_id =2 has 2 unique orders (4 and 6), while customer with ID '4' has one unique order (order_id =6)



      Essentially, what I need to do is rank these orders by customer_id and order Id, so that I can say "Order_id = 7 is the second order for customer_id = 2, because Order_rank = 2"



      The challenge here is that I can't use session variables (e.g. @grp := customer_id ) in the MySQL query



      For example, a query such as this is NOT allowed:



      SELECT 
      customer_id,
      order_id,
      @ss := CASE WHEN @grp = customer_id THEN @ss + 1 ELSE 1 END AS
      order_rank,
      @grp := customer_id
      FROM
      (
      SELECT
      customer_id,
      order_id
      FROM sales_orders
      GROUP BY customer_id, order_id
      ORDER BY customer_id, order_id ASC
      ) AS t_1
      CROSS JOIN (SELECT @ss := 0, @grp = NULL)ss

      ORDER BY customer_id asc


      Thanks for the help!







      mysql sql session-variables ranking rank






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 21 '18 at 1:38









      Negative CorrelationNegative Correlation

      588




      588
























          2 Answers
          2






          active

          oldest

          votes


















          3














          In a Correlated Subquery, we can Count(..) the unique and previous order_id values for a specific row's customer_id and order_id to determine the rank.



          We need to count unique values because you have multiple rows per order (due to multiple items).





          Query



          SELECT 
          t1.Customer_id,
          t1.Order_id,
          t1.Item_Id,
          (SELECT COUNT(DISTINCT t2.Order_id)
          FROM sales_orders t2
          WHERE t2.Customer_id = t1.Customer_id AND
          t2.Order_id <= t1.Order_id
          ) AS Order_rank
          FROM sales_orders AS t1;


          Result



          | Customer_id | Order_id | Item_Id | Order_rank |
          | ----------- | -------- | ------- | ---------- |
          | 1 | 1 | 10 | 1 |
          | 1 | 1 | 24 | 1 |
          | 1 | 1 | 37 | 1 |
          | 1 | 2 | 11 | 2 |
          | 1 | 2 | 15 | 2 |
          | 1 | 3 | 28 | 3 |
          | 2 | 4 | 37 | 1 |
          | 4 | 6 | 10 | 1 |
          | 2 | 7 | 10 | 2 |




          View on DB Fiddle






          share|improve this answer

































            0














            You can use a correlated subquery:



            select so.*,
            (select count(*)
            from sales_orders so2
            where so2.Customer_id = so.Customer_id and
            so2.order_id <= so.order_id
            ) as rank_order
            from sales_orders so;


            Or in MySQL 8+:



            select so.*,
            dense_rank() over (partition by Customer_Id order by Order_Id) as rank_order
            from sales_orders so;





            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%2f53404131%2frank-order-grouped-data-in-mysql-without-session-variables%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









              3














              In a Correlated Subquery, we can Count(..) the unique and previous order_id values for a specific row's customer_id and order_id to determine the rank.



              We need to count unique values because you have multiple rows per order (due to multiple items).





              Query



              SELECT 
              t1.Customer_id,
              t1.Order_id,
              t1.Item_Id,
              (SELECT COUNT(DISTINCT t2.Order_id)
              FROM sales_orders t2
              WHERE t2.Customer_id = t1.Customer_id AND
              t2.Order_id <= t1.Order_id
              ) AS Order_rank
              FROM sales_orders AS t1;


              Result



              | Customer_id | Order_id | Item_Id | Order_rank |
              | ----------- | -------- | ------- | ---------- |
              | 1 | 1 | 10 | 1 |
              | 1 | 1 | 24 | 1 |
              | 1 | 1 | 37 | 1 |
              | 1 | 2 | 11 | 2 |
              | 1 | 2 | 15 | 2 |
              | 1 | 3 | 28 | 3 |
              | 2 | 4 | 37 | 1 |
              | 4 | 6 | 10 | 1 |
              | 2 | 7 | 10 | 2 |




              View on DB Fiddle






              share|improve this answer






























                3














                In a Correlated Subquery, we can Count(..) the unique and previous order_id values for a specific row's customer_id and order_id to determine the rank.



                We need to count unique values because you have multiple rows per order (due to multiple items).





                Query



                SELECT 
                t1.Customer_id,
                t1.Order_id,
                t1.Item_Id,
                (SELECT COUNT(DISTINCT t2.Order_id)
                FROM sales_orders t2
                WHERE t2.Customer_id = t1.Customer_id AND
                t2.Order_id <= t1.Order_id
                ) AS Order_rank
                FROM sales_orders AS t1;


                Result



                | Customer_id | Order_id | Item_Id | Order_rank |
                | ----------- | -------- | ------- | ---------- |
                | 1 | 1 | 10 | 1 |
                | 1 | 1 | 24 | 1 |
                | 1 | 1 | 37 | 1 |
                | 1 | 2 | 11 | 2 |
                | 1 | 2 | 15 | 2 |
                | 1 | 3 | 28 | 3 |
                | 2 | 4 | 37 | 1 |
                | 4 | 6 | 10 | 1 |
                | 2 | 7 | 10 | 2 |




                View on DB Fiddle






                share|improve this answer




























                  3












                  3








                  3







                  In a Correlated Subquery, we can Count(..) the unique and previous order_id values for a specific row's customer_id and order_id to determine the rank.



                  We need to count unique values because you have multiple rows per order (due to multiple items).





                  Query



                  SELECT 
                  t1.Customer_id,
                  t1.Order_id,
                  t1.Item_Id,
                  (SELECT COUNT(DISTINCT t2.Order_id)
                  FROM sales_orders t2
                  WHERE t2.Customer_id = t1.Customer_id AND
                  t2.Order_id <= t1.Order_id
                  ) AS Order_rank
                  FROM sales_orders AS t1;


                  Result



                  | Customer_id | Order_id | Item_Id | Order_rank |
                  | ----------- | -------- | ------- | ---------- |
                  | 1 | 1 | 10 | 1 |
                  | 1 | 1 | 24 | 1 |
                  | 1 | 1 | 37 | 1 |
                  | 1 | 2 | 11 | 2 |
                  | 1 | 2 | 15 | 2 |
                  | 1 | 3 | 28 | 3 |
                  | 2 | 4 | 37 | 1 |
                  | 4 | 6 | 10 | 1 |
                  | 2 | 7 | 10 | 2 |




                  View on DB Fiddle






                  share|improve this answer















                  In a Correlated Subquery, we can Count(..) the unique and previous order_id values for a specific row's customer_id and order_id to determine the rank.



                  We need to count unique values because you have multiple rows per order (due to multiple items).





                  Query



                  SELECT 
                  t1.Customer_id,
                  t1.Order_id,
                  t1.Item_Id,
                  (SELECT COUNT(DISTINCT t2.Order_id)
                  FROM sales_orders t2
                  WHERE t2.Customer_id = t1.Customer_id AND
                  t2.Order_id <= t1.Order_id
                  ) AS Order_rank
                  FROM sales_orders AS t1;


                  Result



                  | Customer_id | Order_id | Item_Id | Order_rank |
                  | ----------- | -------- | ------- | ---------- |
                  | 1 | 1 | 10 | 1 |
                  | 1 | 1 | 24 | 1 |
                  | 1 | 1 | 37 | 1 |
                  | 1 | 2 | 11 | 2 |
                  | 1 | 2 | 15 | 2 |
                  | 1 | 3 | 28 | 3 |
                  | 2 | 4 | 37 | 1 |
                  | 4 | 6 | 10 | 1 |
                  | 2 | 7 | 10 | 2 |




                  View on DB Fiddle







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Nov 21 '18 at 5:58

























                  answered Nov 21 '18 at 5:33









                  Madhur BhaiyaMadhur Bhaiya

                  19.6k62236




                  19.6k62236

























                      0














                      You can use a correlated subquery:



                      select so.*,
                      (select count(*)
                      from sales_orders so2
                      where so2.Customer_id = so.Customer_id and
                      so2.order_id <= so.order_id
                      ) as rank_order
                      from sales_orders so;


                      Or in MySQL 8+:



                      select so.*,
                      dense_rank() over (partition by Customer_Id order by Order_Id) as rank_order
                      from sales_orders so;





                      share|improve this answer




























                        0














                        You can use a correlated subquery:



                        select so.*,
                        (select count(*)
                        from sales_orders so2
                        where so2.Customer_id = so.Customer_id and
                        so2.order_id <= so.order_id
                        ) as rank_order
                        from sales_orders so;


                        Or in MySQL 8+:



                        select so.*,
                        dense_rank() over (partition by Customer_Id order by Order_Id) as rank_order
                        from sales_orders so;





                        share|improve this answer


























                          0












                          0








                          0







                          You can use a correlated subquery:



                          select so.*,
                          (select count(*)
                          from sales_orders so2
                          where so2.Customer_id = so.Customer_id and
                          so2.order_id <= so.order_id
                          ) as rank_order
                          from sales_orders so;


                          Or in MySQL 8+:



                          select so.*,
                          dense_rank() over (partition by Customer_Id order by Order_Id) as rank_order
                          from sales_orders so;





                          share|improve this answer













                          You can use a correlated subquery:



                          select so.*,
                          (select count(*)
                          from sales_orders so2
                          where so2.Customer_id = so.Customer_id and
                          so2.order_id <= so.order_id
                          ) as rank_order
                          from sales_orders so;


                          Or in MySQL 8+:



                          select so.*,
                          dense_rank() over (partition by Customer_Id order by Order_Id) as rank_order
                          from sales_orders so;






                          share|improve this answer












                          share|improve this answer



                          share|improve this answer










                          answered Nov 21 '18 at 1:49









                          Gordon LinoffGordon Linoff

                          783k35310414




                          783k35310414






























                              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%2f53404131%2frank-order-grouped-data-in-mysql-without-session-variables%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

                              Biblatex bibliography style without URLs when DOI exists (in Overleaf with Zotero bibliography)

                              ComboBox Display Member on multiple fields

                              Is it possible to collect Nectar points via Trainline?