OraQA

Oracle Question and Answer

  • Do you have a solution to a problem? Do you have an unanswered question? Login and share it with the Oracle community. More...

Oracle News


Entries RSS feed

Comments RSS feed

How to solve the Zebra Puzzle in SQL

July 5th, 2010 By newkid

From Wikipedia http://en.wikipedia.org/wiki/Zebra_Puzzle:

The Zebra Puzzle is a well-known logic puzzle. It is often called Einstein’s Puzzle or Einstein’s Riddle because it is said to have been invented by Albert Einstein as a boy. Some claim that Einstein said “only 2 percent of the world’s population can solve it.” It is also sometimes attributed to Lewis Carroll.

However, there is no known evidence for Einstein’s or Carroll’s authorship; and the original puzzle mentions brands of cigarette, such as Kools, that did not exist during Carroll’s lifetime or Einstein’s boyhood.

There are several versions of this puzzle, below is one of them:

The British lives in the red house.
The Swede keeps dogs as pets.
The Dane drinks tea.
The green house is on the left of the white house.
The green homeowner drinks coffee.
The man who smokes Pall Mall keeps birds.
The owner of the yellow house smokes Dunhill.
The man living in the center house drinks milk.
The Norwegian lives in the first house.
The man who smokes Blend lives next to the one who keeps cats.
The man who keeps the horse lives next to the man who smokes Dunhill.
The man who smokes Bluemaster drinks beer.
The German smokes Prince.
The Norwegian lives next to the blue house.
The man who smokes Blend has a neighbor who drinks water.

Question: Who owns the fish?

SQL solution:

WITH comb as (  ----- Permutations of number 1-5. they can be interpreted as other properties, and the position of number in string p means room number
         SELECT REPLACE(SYS_CONNECT_BY_PATH(rn,'\'),'\') AS p
           FROM (SELECT ROWNUM rn FROM DUAL CONNECT BY ROWNUM<=5)
          WHERE LEVEL=5
          CONNECT BY NOCYCLE LEVEL<=5 AND rn<>PRIOR rn
          )
     ,nationality AS (
       SELECT INSTR(p,'1') AS Englishman
             ,INSTR(p,'2') AS Swede      
             ,INSTR(p,'3') AS Dane       
             ,INSTR(p,'4') AS Norwegian  
             ,INSTR(p,'5') AS German     
        FROM comb
      )
    ,house AS (
       SELECT INSTR(p,'1') AS red   
             ,INSTR(p,'2') AS white 
             ,INSTR(p,'3') AS green 
             ,INSTR(p,'4') AS yellow
             ,INSTR(p,'5') AS blue  
        FROM comb
     )
    ,beverages AS (
       SELECT INSTR(p,'1') AS tea   
             ,INSTR(p,'2') AS coffee
             ,INSTR(p,'3') AS milk  
             ,INSTR(p,'4') AS beer  
             ,INSTR(p,'5') AS water 
        FROM comb
     )
    ,cigarettes AS (
       SELECT INSTR(p,'1') AS pall_mall  
             ,INSTR(p,'2') AS dunhill    
             ,INSTR(p,'3') AS blends     
             ,INSTR(p,'4') AS blue_master
             ,INSTR(p,'5') AS prince     
        FROM comb
        )
    ,pets AS (
       SELECT INSTR(p,'1') AS dog  
             ,INSTR(p,'2') AS bird 
             ,INSTR(p,'3') AS cat  
             ,INSTR(p,'4') AS horse
             ,INSTR(p,'5') AS fish 
        FROM comb
        )
    ,res AS (
       SELECT *
         FROM nationality
             ,house
             ,beverages
             ,cigarettes
             ,pets           
       WHERE  Englishman     = red   ---- join condition: different properties appear in the same room number, or number of next room
              AND  Swede     = dog
              AND  Dane      = tea
              AND  green     = white -1
              AND  green     = coffee
              AND  pall_mall = bird
              AND  yellow    = dunhill
              AND  milk      = 3  
              AND  Norwegian = 1
              AND  ABS(blends - cat)    =1
              AND  ABS(dunhill - horse) =1
              AND  blue_master = beer
              AND  German    = prince
              AND  blue      = 2
              AND  ABS(blends - water)  =1
       )
SELECT room_num
      ,DECODE(room_num,Englishman,'Englishman',Swede   ,'Swede'  ,Dane  ,'Dane'  ,Norwegian  ,'Norwegian'  ,German,'German') as nationality    
      ,DECODE(room_num,red       ,'red'       ,white   ,'white'  ,green ,'green' ,yellow     ,'yellow'     ,blue  ,'blue'  ) as house          
      ,DECODE(room_num,pall_mall ,'pall mall' ,dunhill ,'dunhill',blends,'blends',blue_master,'blue master',prince,'prince') as beverages      
      ,DECODE(room_num,tea       ,'tea'       ,coffee  ,'coffee' ,milk  ,'milk'  ,beer       ,'beer'       ,water ,'water' ) as cigarettes     
      ,DECODE(room_num,dog       ,'dog'       ,bird    ,'bird'   ,cat   ,'cat'   ,horse      ,'horse'      ,fish  ,'fish'  ) as pets           
  FROM res,(SELECT ROWNUM room_num FROM DUAL CONNECT BY ROWNUM<=5)
ORDER BY room_num;
 
Output:
  ROOM_NUM NATIONALIT HOUSE  BEVERAGES   CIGARE PETS
---------- ---------- ------ ----------- ------ -----
         1 Norwegian  yellow dunhill     water  cat
         2 Dane       blue   blends      tea    horse
         3 Englishman red    pall mall   milk   bird
         4 German     green  prince      coffee fish
         5 Swede      white  blue master beer   dog

Leave a Reply

You must be logged in to post a comment.

RSS feed for comments on this question