• + 76 comments

    Let me break it down in steps (answer in MySQL)

    Step 1:

    Create a virtual table in your head of the data given to us. It look like this https://imgur.com/u6DEcNQ

    SELECT
        case when Occupation='Doctor' then Name end as Doctor,
        case when Occupation='Professor' then Name end as Professor,
        case when Occupation='Singer' then Name end as Singer,
        case when Occupation='Actor' then Name end as Actor
    FROM OCCUPATIONS
    

    Step 2:

    Create an index column with respect to occupation as "RowNumber".https://imgur.com/QzVCWFn

    Notice from the image, under professor column, the first Name is indexed as 1, the next name "Birtney" as 2. That is what I mean by index w.r.t occupation.

    The below code will only give the "RowNumber" column, to get the result like in image proceed to step 3.

    set @r1=0, @r2=0, @r3=0, @r4=0;
    
    SELECT case 
    	when Occupation='Doctor' then (@r1:=@r1+1)
            when Occupation='Professor' then (@r2:=@r2+1)
            when Occupation='Singer' then (@r3:=@r3+1)
            when Occupation='Actor' then (@r4:=@r4+1) end as RowNumber
    
    FROM OCCUPATIONS
    

    Step 3:

    Combine the result from step 1 and step 2:

    set @r1=0, @r2=0, @r3=0, @r4=0;
    
    SELECT case 
    	when Occupation='Doctor' then (@r1:=@r1+1)
            when Occupation='Professor' then (@r2:=@r2+1)
            when Occupation='Singer' then (@r3:=@r3+1)
            when Occupation='Actor' then (@r4:=@r4+1) end as RowNumber,
            case when Occupation='Doctor' then Name end as Doctor,
            case when Occupation='Professor' then Name end as Professor,
            case when Occupation='Singer' then Name end as Singer,
            case when Occupation='Actor' then Name end as Actor
    
    FROM OCCUPATIONS
    

    Step 4:

    Now, Order_by name then Group_By RowNumber.

    Using Min/Max, if there is a name, it will return it, if not, return NULL.

    set @r1=0, @r2=0, @r3=0, @r4=0;
    select min(Doctor), min(Professor), min(Singer), min(Actor)
    from(
      select case when Occupation='Doctor' then (@r1:=@r1+1)
                when Occupation='Professor' then (@r2:=@r2+1)
                when Occupation='Singer' then (@r3:=@r3+1)
                when Occupation='Actor' then (@r4:=@r4+1) end as RowNumber,
        case when Occupation='Doctor' then Name end as Doctor,
        case when Occupation='Professor' then Name end as Professor,
        case when Occupation='Singer' then Name end as Singer,
        case when Occupation='Actor' then Name end as Actor
      from OCCUPATIONS
      order by Name
    	) temp
    group by RowNumber;
    

    **EDIT** I can see many asking why MIN or temp?

    temp - Since I created a temporary table inside the query, I have to give it an alise. It is a good practise.

    Why MIN in the select statement? Since some of us here may not be fimilar with sql, I'll start with where I left so you get the whole picture.

    1. Once you complete step 3, add "ORDER BY Name" (Refer above code on where to add Order by clause). The result will look like this https://imgur.com/aBHUqN6

    What changed? the names in all four columns are sorted as per alphabetical order.

    1. Now, we only want the names and not the NULL values from our virtual table. How can we do that? - There maybe be multiple ways, lets us consider the MIN/MAX (Yes, you can replace MIN with MAX and you will get the same result)

    2. Without GROUP BY clause - When a MIN/MAX is used in a Select statement, it will return The "LOWEST" element from each column (which happened to be the first element because we used ORDER BY, if you use MAX, you will get the last element from each column). It will look like this https://imgur.com/XDZzc4Z That means, you will always get a single row from a table.

    SET @r1=0,@r2=0,@r3=0,@r4=0;
    SELECT MIN(Doctor),MIN(Professor),MIN(Singer),MIN(Actor)
    
    FROM (
    SELECT CASE
        WHEN OCCUPATION = 'Doctor' THEN (@r1:=@r1+1)
        WHEN OCCUPATION = 'Professor' THEN (@r2:=@r2+1)
        WHEN OCCUPATION = 'Singer' THEN (@r3:=@r3+1)
        WHEN OCCUPATION = 'Actor' THEN (@r4:=@r4+1) END AS RowNumber,
        CASE WHEN OCCUPATION = 'Doctor' THEN Name END AS Doctor,
        CASE WHEN OCCUPATION = 'Professor' THEN Name END AS Professor,
        CASE WHEN OCCUPATION = 'Singer' THEN Name END AS Singer,
        CASE WHEN OCCUPATION = 'Actor' THEN Name END AS Actor
    FROM OCCUPATIONS
    ORDER BY Name) as temp
    
    1. With GROUP BY clause - The result set will have one row for EACH group (which is RowNumber in our case).
    • + 0 comments

      Thanks!

    • + 1 comment

      HEY, what does temp do?

      • + 0 comments

        it is just an alias given to the temporary table created because the table has to have an alias

    • + 0 comments

      such a pellucid explanation. Thank you :)

    • + 0 comments

      not work

    • + 0 comments

      Thank you for your explanation. I did not uderstand why we use min/max.Please explain

    • + 0 comments

      Thanks a bunch for this!!

    • + 0 comments

      Can you explain what exactly is happening in step2? What does 'set @' do? I tried running just the code in step 2 but couldn't understand.

    • + 0 comments

      wow! this is the best explanation i got so far.. just a few things why did we use min() and groupby rownumber.

    • + 0 comments

      wow! this is the best explanantion i found so far. just a few queries: why are we using min() and groupby rownumber in the end??

    • + 0 comments

      Awesome explanation! Much appreciated :)

    • + 0 comments

      Thanks for the breakdown, it really helps me to understand each concept.

    • + 1 comment

      hey, can someone explain why we use min/max here? thanks

      • + 0 comments

        min/max because we do not want the NULL elements.

        When you use MIN/MAX in select statement, it will return a single row from the table with the LOWEST/HIGHEST value element from EACH column.

        With GROUP BY clause, it will return the LOWEST/HIGHEST value element from each column and EACH group. Refer to the image attached on my main thread and connect this comment. You will get it.

    • + 0 comments

      Thanks a lot :) crisp explanation

    • + 2 comments

      Can you please explain what is use of "END AS" in line:: case when Occupation='Doctor' then Name end as Doctor

      • + 0 comments

        Each CASE statment when the condition is met returns a value. END AS is used to name column of that return value.

      • + 0 comments

        I confused dat line at start too, thought END AS together meant something LOL, END to close CASE statement and AS to add an alias

    • + 0 comments

      woooh!

    • + 1 comment

      You can improve readability using window functions

      WITH pivot AS (
          SELECT
              ROW_NUMBER() OVER (PARTITION BY occupation ORDER BY name) AS rn,
              IF(occupation='Doctor', name, NULL)     AS doctor,
              IF(occupation='Professor', name, NULL)  AS professor,
              IF(occupation='Singer', name, NULL)     AS singer,
              IF(occupation='Actor', name, NULL)      AS actor
          FROM occupations
      )
      
      SELECT MIN(doctor), MIN(professor), MIN(singer), MIN(actor)
      FROM pivot
      GROUP BY rn;
      
      • + 1 comment

        Thanks for giving code in Oracle, it was super confusing for me to see @r1 in MySql

        • + 0 comments

          You can use those code in MySql too

    • + 0 comments

      Thanks for the explaination, that's great!

    • + 0 comments

      Thank you so much for explaination and posting this :)

    • + 0 comments

      Thanks

    • + 0 comments

      Greate explanation, Thanks

    • + 0 comments

      Brilliant. Thanks !

    • + 0 comments

      Thanks for such a nice explanation

    • + 0 comments

      Thank you so much!!

    • + 0 comments

      Pretty clear, thanks!

    • + 0 comments

      Thankyou so much!

    • + 0 comments

      Hi, your code is giving me an error. Please help

      unknown SET option "@r1=0," select case when Occupation='Doctor' then (@r1:=@r1+1) * ERROR at line 3: ORA-00936: missing expression

    • + 0 comments

      Wonderful explanation!! Thanks!

    • + 0 comments

      Great crack! Thank you btw!!

    • + 0 comments

      Great explaination thank you for writing this!

    • [deleted]
      + 0 comments

      Thanks! Helped a lot

    • + 0 comments

      thanks so much

    • + 1 comment

      Here, can't we use pivot ? If not then WHY?

      • + 1 comment

        just wanted to make it as simple as that with basic sql , u can do wth pivot if u want !

        • + 0 comments

          okay, thankss

    • + 0 comments

      thank you for your explanation raiyanger24, I learn a lot

    • + 1 comment

      WOW!!!

      • + 0 comments

        Thanks

    • + 0 comments

      Excellant Explanation! Opened me to new type of problem solving. Thank you :D

    • + 0 comments

      Amazing! Thanks

    • + 0 comments

      what does the @r1=0 to @r4=0 means?

    • + 0 comments

      Very good explanation

    • + 0 comments

      great, thank you.

    • + 0 comments

      Thanks so much for a very clear explanation!

    • + 0 comments

      Thank you very much for the steps. Learned how to pivot rows and columns using mysql from your post.

    • + 0 comments

      BEST EXPLANATION..THANKS A TON!

    • + 0 comments

      Thanks! for detailed explanation

    • + 0 comments

      One of the most detailed explanation ever! Thanks.

    • + 0 comments

      Thanks for breaking down the problem so nicely that people could understand easily.

    • + 0 comments

      Too good man! Thanks

    • + 0 comments

      thanks! This is so helpful and informative! Great explanation.

    • + 0 comments

      thanks, sql magician!

    • + 0 comments

      Thanks!!Good Work

    • + 0 comments

      Great explaination, i had an idea to do like that but can't find a way to make it, you explained everything perfectly clear. Thank you!

    • + 0 comments

      Thank you for explaining it so beautifully. This is excellent for beginners.

    • + 0 comments

      Thank you so much!. Your explanation is awsome, I culdn't figure the solution out with out your example

    • + 0 comments

      But my output is comig wrong. Please tell me what to do. OUTPUT: Your Output (stdout) Aamina Ashley Christeen Eve

    • + 0 comments

      Thanks for the answer and clear explination

    • + 0 comments

      I'm a beginner and you saved my day, thanks

    • + 0 comments

      Thnx for the qeury

    • + 0 comments

      This is crazy detailed and clear. Thanks a lot!!

    • + 0 comments

      This has got to be the best explained comment in all of hacker rank i have seen yet. Kudos to you for going the extra mile to explain to us mere mortals.

    • + 0 comments

      This is briliant, thanks!

    • + 0 comments

      Really great explanation! Thanks!

    • + 1 comment

      I have some commnet about how to keep track at each row. How does it look when we use :

      ROW_NUMBER() OVER(PARTITION BY(Occupation) ORDER BY(Name))

      This is window function that automatically indexing each row follow our condition, it contain the same mechanism when we use

      set @r1=0 ... case .... @r1 := @r1 + 1

      Since I see that we hasn't nessecery user variable here, I think we can simplify and avoid to use user variable where it really doesn't ineeded

      • + 0 comments

        SELECT MAX(DOCTORS), MAX(PROFESSORS), MAX(SINGERS), MAX(ACTORS) FROM

        ( SELECT ROW_NUMBER() OVER (PARTITION BY OCCUPATION ORDER BY NAME) AS ROWNUMBER,

            CASE WHEN OCCUPATION = "DOCTOR" THEN NAME END AS "DOCTORS",
        
            CASE WHEN OCCUPATION = "PROFESSOR" THEN NAME END AS "PROFESSORS",
        
            CASE WHEN OCCUPATION = "SINGER" THEN NAME END AS "SINGERS",
        
            CASE WHEN OCCUPATION = "ACTOR" THEN NAME END AS "ACTORS"
        

        FROM OCCUPATIONS ) AS SRC GROUP BY SRC.ROWNUMBER ORDER BY SRC.ROWNUMBER;

    • + 0 comments

      Thank you!

    • + 0 comments

      thanks:) It helped me a lot

    • + 4 comments

      Thank you so much, it is so clear and really explains a lot.

      While I have a small doubt about the order by clause. Could anyone explain why the RowNumber that is set in the 'case when' statement will be sorted again? I thought that the ORDER BY clause is operated after the SELECT statement, so should not the RowNumber be set with the rows that name was not sorted yet? Exemplifying from raiyanger24's picture example that - Julia will still be in RowNumber of 1 for Doctor.even after an order by execution Thank you so much guys!

      • + 1 comment

        Did you find an answer to this? I'm confused here as well.

      • + 0 comments

        The spam blocker is getting me because I'm trying to copy and paste the code I used to investigate. I can still share the conclusion though:

        Contrary to what one is taught, it seems not everything in SELECT is executed before ORDER BY. It seems that anytime you derive a column (using CASE, by doing arithmetic, etc.), that column is going to be formed off of the ordered version of the non-derived fields if the field for the ORDER BY clause is non-derived.

    • + 0 comments

      You could've skipped everything upto step 3 with the help of window function.

      SELECT
      	min(Doctor),
      	min(Professor),
      	min(Singer),
      	min(Actor)
      FROM
      	(
      	SELECT
      		ROW_NUMBER() OVER (PARTITION BY OCCUPATION
      	ORDER BY
      		NAME) AS r,
      		CASE
      			WHEN Occupation = 'Doctor' THEN Name
      		END AS Doctor,
      		CASE
      			WHEN Occupation = 'Professor' THEN Name
      		END AS Professor,
      		CASE
      			WHEN Occupation = 'Singer' THEN Name
      		END AS Singer,
      		CASE
      			WHEN Occupation = 'Actor' THEN Name
      		END AS Actor
      	FROM
      		OCCUPATIONS
      ) t
      GROUP BY t.r
      

      Regardless, your comment was very helpful for me.

    • + 1 comment

      Can you explain this SELECT MIN(Doctor),MIN(Professor),MIN(Singer),MIN(Actor) why we are selecting min of all columns?

      • + 0 comments

        If we run the inner subquery, then it would return following result set Subquery Output

        Since we want all the peoples for specific row_number() to appear in the same row, we are using group by. And, when using group by, we can either select the columns in the group by list, or use aggregate function. So, in my case I used MIN, but in this case doing, MAX would have given the same result.

    • + 0 comments

      thanks for the kind explation!

    • + 0 comments

      Thanks a lot, every beautiful and clear explanation. Do you have any youtube channel or blog about SQL or coding or data stuff,.. I wanna subcribe yours:))

    • + 0 comments

      awsome explanation just so up to point thanks a lot

    • + 0 comments

      Adding my voice to the chorus of thanks for this - thank you! It would have taken me a very long time to figure that out alone - I've really learned something from this exercise and your explanation.

    • + 0 comments

      tysm

    • + 0 comments

      Thank you!

    • + 0 comments

      phenomenal answer!

    • + 0 comments

      Very good answer