Your left outer join will return null if there is no match, which means you still have a row (without HIRE table data) when the results of this join request are Null:
LEFT OUTER JOIN hires ON hires.prod_id = products.prod_id WHERE (hires.hire_end < to_date('21-JAN-13') OR hires.hire_start > to_date('26-JAN-13')) OR hires.prod_id IS NULL
Try adding a selection from the hires table (for example, hire.Hire_Start ) to see this, then switch it to the inner join, and I think your problem will be solved.
OR add a WHERE clause to the full query with something like hire.Hire_Start is not null
EDIT
If you change the original request to:
SELECT hires.Hire_Start, products.prod_id, products.title, products.price, product_types.name, listagg(suppliers.name, ',') WITHIN GROUP(ORDER BY suppliers.name) suppliers FROM products INNER JOIN product_suppliers ON products.prod_id = product_suppluer.prod_id INNER JOIN product_types ON product_types.type_id = products.type_id INNER JOIN suppliers ON product_suppliers.supp_id = suppliers.supp_id LEFT OUTER JOIN hires ON hires.prod_id = products.prod_id WHERE (hires.hire_end < to_date('21-JAN-13') OR hires.hire_start > to_date('26- JAN-13')) OR hires.prod_id IS NULL GROUP BY products.prod_id, products.title, products.price, product_types.name
What is returned in the Hire_Start column?
Then, if you add it to the where clause, you will get the expected result:
SELECT hires.Hire_Start, products.prod_id, products.title, products.price, product_types.name, listagg(suppliers.name, ',') WITHIN GROUP(ORDER BY suppliers.name) suppliers FROM products INNER JOIN product_suppliers ON products.prod_id = product_suppluer.prod_id INNER JOIN product_types ON product_types.type_id = products.type_id INNER JOIN suppliers ON product_suppliers.supp_id = suppliers.supp_id LEFT OUTER JOIN hires ON hires.prod_id = products.prod_id WHERE (hires.hire_end < to_date('21-JAN-13') OR hires.hire_start > to_date('26- JAN-13')) OR hires.prod_id IS NULL WHERE hires.Hire_Start is not null GROUP BY products.prod_id, products.title, products.price, product_types.name
Finally, by completely disabling Outer Join, does this work as expected?
SELECT hires.Hire_Start, products.prod_id, products.title, products.price, product_types.name, listagg(suppliers.name, ',') WITHIN GROUP(ORDER BY suppliers.name) suppliers FROM products INNER JOIN product_suppliers ON products.prod_id = product_suppluer.prod_id INNER JOIN product_types ON product_types.type_id = products.type_id INNER JOIN suppliers ON product_suppliers.supp_id = suppliers.supp_id INNER JOIN hires ON hires.prod_id = products.prod_id WHERE (hires.hire_end < to_date('21-JAN-13') OR hires.hire_start > to_date('26- JAN-13')) GROUP BY products.prod_id, products.title, products.price, product_types.name
And note: this is OR Hires.prod_ID to indicate that if the result does not return hiring information, it is available, in which case you need to write the request more, like the other answer.