Reputation: 15
Program must display the 10 dogs with the most Tricks learned in that m0nth: OUTPUT Dog Name, ID NO and NO of tricks learned in that particular month based on (P_month), when I comment out the ORDER BY clause it runs but then when I enter a paramater eg. 'april' it says: ORA -1722'invalid number'
create or replace
PROCEDURE DOGS (P_MONTH IN VARCHAR2) IS
CURSOR CUR_DOGS (CP_MONTH VARCHAR2) IS
SELECT DR.DOG_NAME, TR.DOG_ID
FROM DOG DR, TRICK TR
WHERE TRIM(INITCAP(TO_CHAR(TR.DATE_OF_TRICK, 'month'))) = TRIM(INITCAP(TO_CHAR(CP_MONTH, 'month')))
AND DR.DOG_ID = TR.DOG_ID
ORDER BY COUNT (TR.DOG_ID) DESC;
REC_DOGS CUR_DOGS%ROWTYPE;
V_NO_TRICKS NUMBER;
BEGIN
DBMS_OUTPUT.PUT_LINE ('DOG NAME' || ' ' || 'ID NO' || ' ' || 'NO OF TRICKS');
OPEN CUR_DOGS (P_month);
LOOP
FETCH CUR_DOGS INTO REC_DOGS;
EXIT WHEN (CUR_DOGS%ROWCOUNT > 10) OR (CUR_DOGS%NOTFOUND);
SELECT COUNT(TRICK_NO)INTO V_NO_TRICKS FROM TRICK WHERE DOG_ID = REC_DOGS.DOG_ID;
DBMS_OUTPUT.PUT_LINE (REC_DOGS.DOG_NAME ||' '||REC_DOGS.DOG_ID ||' '|| V_NO_TRICKS);
END LOOP;
CLOSE CUR_DOGS;
END;
Upvotes: 0
Views: 164
Reputation: 64969
The reason you get an invalid-number error is in this part of your query:
TRIM(INITCAP(TO_CHAR(CP_MONTH, 'month')))
Cursor parameter cp_month
is already a VARCHAR2
, so there's no need to convert it using TO_CHAR
. Replace this with
TRIM(INITCAP(CP_MONTH))
The reason you get a not a single-group group function
error is that you are using an aggregate function (COUNT
) incorrectly.
You can use COUNT
to count the number of rows in a table, e.g. SELECT COUNT(*) FROM some_table
. This returns a single row with the number of rows in the table some_table
. But what if you write something like SELECT some_column, COUNT(*) FROM some_table
? Oracle still has to return a single row, but it doesn't know what value to return for some_column
because there may be more than one row. Which row would be correct?
You have to tell Oracle to calculate one count per dog, rather than one count overall. You do this by specifying a GROUP BY
clause. This lists all the columns to group by.
Going back to our previous example, we could write
SELECT some_column, COUNT(*) FROM some_table GROUP BY some_column
This returns one row for each distinct value of the some_column
column, along with the number of times each value occurred.
When using GROUP BY
, you need to group by all columns that you are selecting. In your case, this is DR.DOG_NAME
and TR.DOG_ID
. You may be tempted to just group by TR.DOG_ID
since the name of the dog is determined by its ID (presumably a primary key). However, Oracle won't let you do this.
So, your cursor query should look like the following:
CURSOR CUR_DOGS (CP_MONTH VARCHAR2) IS
SELECT DR.DOG_NAME, TR.DOG_ID
FROM DOG DR, TRICK TR
WHERE TRIM(INITCAP(TO_CHAR(TR.DATE_OF_TRICK, 'month'))) = TRIM(INITCAP(CP_MONTH))
AND DR.DOG_ID = TR.DOG_ID
GROUP BY DR.DOG_NAME, TR.DOG_ID -- Add this line
ORDER BY COUNT (TR.DOG_ID) DESC;
You could simplify your procedure further. By adding the COUNT
to the SELECT
list, you can then read the counts out of the cursor and not bother using the V_NO_TRICKS
variable.
CURSOR CUR_DOGS (CP_MONTH VARCHAR2) IS
SELECT DR.DOG_NAME, TR.DOG_ID, COUNT (TR.DOG_ID) AS TRICK_COUNT
FROM DOG DR, TRICK TR
-- ... rest of query as before
-- ... later on ...
DBMS_OUTPUT.PUT_LINE (REC_DOGS.DOG_NAME ||' '||REC_DOGS.DOG_ID ||' '|| REC_DOGS.TRICK_COUNT);
Upvotes: 1