Reputation: 23
The code is working but the top (X) TOP PRICE are not fetched accordingly. How do I use Ties with my code ?
Some of the top (x) are ignored.
This is my table
STAFF_NUMBER STAFF_NAME PRICE
------------ ----------------------------------------- ----------
36 Helen Hilfg 330066
52 Octavia Chan 356885
36 Helen Hilfg 176088
4 Heidi Lee 231046
6 Jill Murphy 469844
32 Lily Roy 247549
58 John Roy 309299
This is what I am getting
SQL> SQL> SQL> exec p4(3)
PERSON# NAME
36 Helen Hilfg
52 Octavia Chan
4 Heidi Lee
This is what I suppose to get
SQL> exec p4(3);
PERSON# NAME
--------------------
36 Helen Hilfg
6 Jill Murphy
52 Octavia Chan
Here is my procedure
CREATE OR REPLACE PROCEDURE p3( X NUMBER )
AS
staff_number NUMBER ;
staff_name VARCHAR2(30) ;
CURSOR c1 IS
SELECT staff_number,
staff_name
FROM (SELECT P.peid staff_number,
P.firstname || ' ' || P.lastname staff_name ,
D.price PRICE
FROM Contact C,
Deal D,
Person P,
Staff S
WHERE S.peid = C.peid
AND C.pno = D.pno
AND P.peid = C.peid
AND (SYSDATE - D.day < 365))
WHERE ROWNUM <= X
GROUP BY staff_name , staff_number
ORDER BY SUM( price ) DESC ;
BEGIN
dbms_output.put_line( ' PERSON# ' ||' '||' NAME ' );
FOR R IN c1
LOOP
staff_number := R.staff_number ;
staff_name := R.staff_name ;
dbms_output.put_line( staff_number ||' '|| staff_name ) ;
END LOOP ;
END;
/
The code is working but the top (X) TOP PRICE are not fetched accordingly. How do I use Ties with my code ?
Some of the top (x) are ignored.
Upvotes: 0
Views: 487
Reputation: 146239
Please, look at your query and try to understand what it's doing.
You have an inner query which filters on some criteria. You haven't given us the data, so we can't predict what that result will look like. Let's assume it returns the records you think it's going to.
Then in your outer query you have a WHERE clause which filters on ROWNUM <= X
. This means the query will return three rows, essentially at random, which will then be grouped and sorted on the basis of SUM(PRICE)
.
This is obviously not what you're expecting. But that's because you don't understand how ROWNUM works. It is easy enough to fix: you just need to apply the ROWNUM filter to the grouped and sorted results. Like this:
SELECT * FROM (
SELECT staff_number,
staff_name
FROM (SELECT P.peid staff_number,
P.firstname || ' ' || P.lastname staff_name ,
D.price PRICE
FROM Contact C,
Deal D,
Person P,
Staff S
WHERE S.peid = C.peid
AND C.pno = D.pno
AND P.peid = C.peid
AND (SYSDATE - D.day < 365)
)
GROUP BY staff_name , staff_number
ORDER BY SUM( price ) DESC
)
WHERE ROWNUM <= X
;
Upvotes: 1
Reputation: 2296
First as DCookie suggested, ensure you have enabled output
set serveroutput on
If you dont get the result you are expecting, try breaking down the query until you find where the data is missing e.g. if there are no deals in the last year, you wont get anything back so select just one deal record which meets the criteria and then check the other tables for matching records. Also confirm there is data in each of the tables as if any of them is empty, again the result set will be empty.
e.g.
select pno from deal where (sysdate - day) < 365;
(The assumption is that day is a date field), then select this pno from the contact table
select peid from contact where pno=&pno;
select this peid from person table and if any of those selects come up empty, check example values for the field to confirm the id numbers are actually matching between the tables e.g.
select count(*)
from deal d
where exists (select 1 from contact c where c.pno=d.pno)
select count(*)
from contact c
where exists (select 1 from person p where p.peid=c.peid)
You are joining to the STAFF table but both STAFF and CONTACT have the same peid field and you arent selecting any columns from the STAFF table but you get firstname, lastname and staff number from the person table.
Are there other rows in the person table for people who might be contacts on deals but are not staff (meaning the join to staff is to validate the type) ? if not then maybe the staff table is redundant here.
When you have a complicated query (and they can get really complicated, like a couple of pages of A4 printed out), you have to have a method to breakdown the query to simpler queries that you can validate each step and this leads you to where the error occurs.
Hope that helps.
probably you should use the analytic functions so a query something like
select staff_number, staff_name from (
SELECT P.peid staff_number,
P.firstname || ' ' || P.lastname staff_name ,
D.price PRICE
RANK() OVER (ORDER BY d.price) AS position
FROM Contact C,
Deal D,
Person P,
Staff S
WHERE S.peid = C.peid
AND C.pno = D.pno
AND P.peid = C.peid
AND (SYSDATE - D.day < 365)
) where position < x
Use rank() if you want to skip positions where there are several people with a tied position or dense_rank() for having several records with the same position.
just saw that you need it to sum deals for the same person so might be more like this (untested)
select staff_number, staff_name from (
SELECT P.peid staff_number,
P.firstname || ' ' || P.lastname staff_name ,
sum(D.price) PRICE
RANK() OVER (ORDER BY sum(d.price)) AS position
FROM Contact C,
Deal D,
Person P,
Staff S
WHERE S.peid = C.peid
AND C.pno = D.pno
AND P.peid = C.peid
AND (SYSDATE - D.day < 365)
group by p.peid, p.first_name|' '||p.lastname
) where position < x
Definitely have a look at the analytic functions as rownum just returns the first rows in the query, it doesnt return the full result set and then give you the top N records. You may need to use a partition clause but give it a try and see here for examples of rank.
http://psoug.org/reference/analytic_functions.html
Upvotes: 1
Reputation: 43533
When you say "nothing was output", how did you run the procedure? Did you enable dbms_output? For example, if you ran it in SQL*Plus, did you SET SERVEROUTPUT ON? You should have at least got your header line, assuming the procedure has no compile errors.
Does the query itself run outside of the procedure, in SQL*Plus?
Upvotes: 1