0

While I know the title isn't very specific and I apologise, I need help with a syntax issue I'm having with SQL, and as I'm not entirely sure as to the part of the syntax thats wrong, I can't be much more specific.

I'm using Oracle SQL Developer, if that helps.

    SELECT DISTINCT pet.PET_NAME,
    CASE
      WHEN dog.PET_PET_NUMBER = pet.PET_NUMBER THEN 'Dog'
      WHEN cat.PET_PET_NUMBER = pet.PET_NUMBER THEN 'Cat'
      ELSE  ''
    END AS "Pet Type",
    SUM(res.RESERVATION_START_DATE - res.RESERVATION_END_DATE) AS "Days Stayed"
    FROM HVK_PET pet, HVK_DOG dog, HVK_CAT cat, HVK_RESERVATION res, HVK_PET_RESERVATION petRes
    WHERE (pet.PET_NUMBER = dog.PET_PET_NUMBER
    OR pet.PET_NUMBER = cat.PET_PET_NUMBER)
    AND res.RESERVATION_NUMBER = petRes.RES_RESERVATION_NUMBER  
    AND petRes.PET_PET_NUMBER = pet.PET_NUMBER
    GROUP BY pet.PET_NAME, dog.pet_pet_number, cat.pet_pet_number;

Is my complete code, the top 7 lines are underlined yellow with the suggestion to add CASE, to my group by statement. I'm not the greatest at SQL, so if it's glaring obvious don't hesitate to call me out on it.

Duncan McKirdy
  • 141
  • 1
  • 12

4 Answers4

0
SELECT pet.PET_NAME,
       CASE
          WHEN dog.PET_PET_NUMBER = pet.PET_NUMBER THEN 'Dog'
          WHEN cat.PET_PET_NUMBER = pet.PET_NUMBER THEN 'Cat'
          ELSE  ''
      END AS "Pet Type",
      SUM(res.RESERVATION_START_DATE - res.RESERVATION_END_DATE) AS "Days Stayed"
    FROM HVK_PET pet, HVK_DOG dog, HVK_CAT cat, HVK_RESERVATION res, HVK_PET_RESERVATION petRes
    WHERE (pet.PET_NUMBER = dog.PET_PET_NUMBER OR pet.PET_NUMBER = cat.PET_PET_NUMBER)
      AND res.RESERVATION_NUMBER = petRes.RES_RESERVATION_NUMBER  
      AND petRes.PET_PET_NUMBER = pet.PET_NUMBER
    GROUP BY pet.PET_NAME, 
             CASE
              WHEN dog.PET_PET_NUMBER = pet.PET_NUMBER THEN 'Dog'
              WHEN cat.PET_PET_NUMBER = pet.PET_NUMBER THEN 'Cat'
              ELSE  ''
            END;

Grouping by dog.pet_pet_number, cat.pet_pet_number doesn't work because your CASE in the select transforms the result in such a way that it doesn't fit GROUP BY.

I suppose you don't need DISTINCT as this keyword is applied to the all expressions in the select list and it doesn't make sense to have it in your case (there is already no dublicates as you're grouping)

Multisync
  • 8,657
  • 1
  • 16
  • 20
0

There are two ways :

1.

 GROUP BY pet.PET_NAME,
          CASE
             WHEN dog.PET_PET_NUMBER = pet.PET_NUMBER THEN 'Dog'
             WHEN cat.PET_PET_NUMBER = pet.PET_NUMBER THEN 'Cat'
             ELSE  ''
          END;
  1. Use INLINE view.

A similar question here How do I use Group By based on a Case statement in Oracle?

Community
  • 1
  • 1
Lalit Kumar B
  • 47,486
  • 13
  • 97
  • 124
0

First, you do not need select distinct. This construct is almost never needed with a group by.

The problem with your case statement, as written, is that it mentions three columns, but only two are in the group by. This missing column is pet.PET_NUMBER. You can add this to the group by, but there are simpler ways to write your query.

The key is to fix the join syntax and not use implicit joins:

SELECT pet.PET_NAME,
       MAX(CASE WHEN dog.PET_PET_NUMBER IS NOT NULL THEN 'Dog' ELSE 'CAT' END) AS "Pet Type",
       SUM(res.RESERVATION_START_DATE - res.RESERVATION_END_DATE) AS "Days Stayed"
FROM HVK_PET pet JOIN
     HVK_PET_RESERVATION petRes
     ON petRes.PET_PET_NUMBER = pet.PET_NUMBER JOIN
     HVK_RESERVATION res
     ON res.RESERVATION_NUMBER = petRes.RES_RESERVATION_NUMBER LEFT JOIN
     HVK_DOG dog
     ON pet.PET_NUMBER = dog.PET_PET_NUMBER LEFT JOIN
     HVK_CAT cat
     ON pet.PET_NUMBER = cat.PET_PET_NUMBER
GROUP BY pet.PET_PET_NUMBER, pet.PET_NAME;

The left joins bring in additional columns, not rows so you'll have "dog" columns and "cat" columns. These can readily be used in logic in the SELECT. Under the assumption that a given pet is either a dog or cat but never both, the query just uses MAX() instead of including additional columns in the group by.

Removing the or from the join condition should improve performance.

If you are learning SQL, learn proper ANSI style join syntax. A simple rule: never use commas in the from clause.

Gordon Linoff
  • 1,242,037
  • 58
  • 646
  • 786
0

Just another answer along for the ride and readability. Starting with your pet and joining to the dog or cat table via LEFT-JOIN, should only be found in one of the tables. If you had other pets allowed to stay (birds, reptiles, etc) you could just add more "LEFT JOIN"s to those tables too and adjust the case/when clause.

So, the case/when. If if finds a dog's pet number match, great you are done as "Dog". If not, it falls through to try "Cat"... if not, you have your else (or any other pet types in the future).

I have added the pet_number for clarification which is also part of your group by... What if you have more than one pet named "Lightning" (fast dog or cat, each with distinct pet numbers), no ambiguity.

Also, for the group by, I am doing it on the main pet's pet number column. It does not matter if it finds it in the dog or cat table... it is the number that is distinct regardless of which table it is found in.

Lastly, removed the distinct. Since you are grouping by each pet number/name, and doing an aggregate sum, there would not be any duplicates based on the resulting pet-type...

SELECT 
      pet.PET_NAME,
      pet.PET_NUMBER,
      CASE WHEN dog.PET_PET_NUMBER IS NOT NULL THEN 'Dog'
           WHEN cat.PET_PET_NUMBER IS NOT NULL THEN 'Cat'
           ELSE  '' END AS "Pet Type",
      SUM(res.RESERVATION_START_DATE - res.RESERVATION_END_DATE) AS "Days Stayed"
   FROM 
      HVK_PET pet
         LEFT JOIN HVK_DOG dog
            ON pet.PET_NUMBER = dog.PET_PET_NUMBER
         LEFT JOIN HVK_CAT cat
            ON pet.PET_NUMBER = cat.PET_PET_NUMBER
         JOIN HVK_PET_RESERVATION petRes
            ON pet.PET_NUMBER = petRes.PET_PET_NUMBER 
            JOIN HVK_RESERVATION res
               ON petRes.RES_RESERVATION_NUMBER = res.RESERVATION_NUMBER
   GROUP BY 
      pet.PET_NAME, 
      pet.PET_NUMBER;

However, if Oracle chokes saying that not all columns are part of an aggregate for the group by because you are not grouping by the pet type... and the pet type won't change for the specific pet number, you can just change that to a

MAX( case/when ) as PetType

(Finally, I HATE trying to have columns with embedded spaces. Can cause issues you may not expect, especially if you forget to "quote" them.)

DRapp
  • 47,638
  • 12
  • 72
  • 142