2

I have the following problem: I need to sort some products where one needs to be a specific row and others to be random.

So if I have products: A B C D, I need for example B to be the third product while others can be random like:

C  1
A  2
B  3
D  4

Best shot I have tried is (3 is a dynamic value):

SELECT
    product_name,
    CASE
        WHEN product = 'B' THEN 3
        ELSE ( CASE WHEN rownum < 3 THEN rownum ELSE rownum + 1 END )
    END sorting
FROM
    products
ORDER BY
    sorting ASC;

but I'm not always getting the desired outcome.

Any help or lead is appreciated.

4
  • Where in your query are you using random numbers? Where/how is rownum defined or generated? Commented Nov 5, 2019 at 12:35
  • Tip: You don't need to use a nested CASE WHEN: you can make rownum < 3 the second case in the top CASE WHEN expression. Commented Nov 5, 2019 at 12:36
  • By random I mean that is not important how other products are sorted. I only want them to be in between 1 - no. of products where one of the rows is specified by me. I hope I'm clear. Commented Nov 5, 2019 at 12:38
  • @ErgiNushi . . . This is a genuinely interesting question. Commented Nov 5, 2019 at 13:13

1 Answer 1

3

This is rather tricky, but you can use row_number() and a bunch of arithmetic:

select p.*
from (select p.*,
             row_number() over (order by case when product = 'B' then 2 else 1 end),
                                         dbms_random.value
                               ) as seqnum
      from products p
     ) p
order by (case when seqnum < 3 then seqnum end),
         (case when product = 'B' then 1 else 2 end),
         seqnum;

The logic is:

  • Enumerate the values randomly, with the special value going last.
  • Put in the rows with lower values.
  • Put in the row with the special value.
  • Put in the rest of the rows.

The above uses a subquery because the randomness is enforced. You can do this without a subquery as:

order by (case when row_number() over (order by (case when product = 'B' then 2 else 1 end) < 3
               then dbms_random.value
               else 2  -- bigger than value
          end),
         (case when product = 'B' then 1 else 2 end),
         dbms_random.value;
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for your reply. Randomness is not enforced in fact. I only need that the specific product to be in the specific place I imply. Other products can be in a random order in between 1 - no. of products I have. Like I mentioned in my question.
@ErgiNushi . . . That is not an important part of this answer, but your question does specific say "random", so I included it.
After making a few changes this worked perfectly. Thank you very much :D

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.