Working on joining several tables to obtain a desired result - oracle-sqldeveloper

Need to join several tables which shows each customer and total_value of orders placed by it. Report the customer no and name for the customer and the total_value for the customer who placed the highest of orders. So far I have:
select customer.customer_num, customer.customer_name, price as total_value
from customer, orders, order_line, part
where customer.customer_num = orders.customer_num
and orders.order_num = order_line.order_num
and order_line.part_num = part.part_num;
This narrows it down, but now I need to answer the initial question, report on which customer had the greatest sum of price found in the part table.
I just cannot figure out where to place this syntax?
customer.customer_num > sum(part.price)
after joining the four tables.

select customer.customer_num, customer.customer_name, price as total_value
from customer
join order on
customer.customer_num = orders.customer_num
join order_line on
orders.order_num = order_line.order_num
join part on
order_line.part_num = part.part_num where customer.customer_num >sum(part.price);

Related

postgresql left join but dont fetch if matching condition found

I have a bit of a complicated scenario. I have two tables, employee and agency. An employee may or may not have an agency, but if an employee has an agency I want the select clause to check another condition on the agency, but if the employee does not have an agency its fine I want to fetch the employee. I'm not sure how to write the select statement for this. This is what I have come up with so far
select * from employee e left join
agency a on a.id = e.agencyID and a.valid = true;
However the problem with this is that it fetches both employees without agencies which is fine, but it also fetches employees with agencies where a.valid = false. The only option I can think of is to do an union but I'm looking for something more simpler.
A UNION could actually be the solution that performs best, but you can write the query without UNION like this:
select *
from employee e
left join agency a
on a.id = e.agencyID
where coalesce(a.valid, true);
That will accept agencies where valid IS NULL, that is, result rows where the agency part was substituted with NULLs by the outer join.
You want except the condition that both table match(agency.id = employee.agencyID) and also agency.id is false. The following query will express the condition.
SELECT
e.*,
a.*
FROM
employee e
LEFT JOIN agency a ON a.id = e.agencyID
WHERE
NOT EXISTS (
SELECT
1
FROM
agency
WHERE
a.id = e.agencyID
AND a.valid IS FALSE)
ORDER BY
e.id;

Show the subjects per StudentNo and the count of number of subjects per student

Error: Cannot perform an aggregate function on an expression containing an aggregate or a subquery.
SELECT Subject, StudentNo, SUM(COUNT(DISTINCT Subject)) AS NumOfSubjectPerStudent
FROM Subjects AS S
INNER JOIN STUDENTS AS ST ON S.ID = ST.ID
WHERE S.ID = ST.ID
GROUP BY ST.StudentNo, S.Subject
ORDER BY ST.StudentNo DESC
I think you're almost there but without knowing the structure of the Students and Subjects tables, I can only assume it should be something like this:
SELECT ST.StudentNo, S.Subject, SUM(COUNT(DISTINCT S.Subject)) AS NumOfSubjectPerStudent
FROM Subjects AS S
INNER JOIN STUDENTS AS ST ON S.StudentId = ST.ID
GROUP BY ST.StudentNo, S.Subject
ORDER BY ST.StudentNo DESC
This assumption is based on the Subjects table having a StudentId field that links to the Students Id field.
I also am assuming that the Subjets Id field is the unique identifier/primary key for that Subject and shouldn't be used to JOIN against the Subjects ID field.
If I am wrong with my assumptions, then can you please clarify the columns in each table, and also provide an example of data in each table to better make sense of how to help you.

COALESCE TSQL with a join tsql

I have a requirement to pick up data that is in more than one place and I have some form of recognition if using the coalesce function. Basically I am looking to coalesce the join itself but looking online its seems as if i can only do this on the fields.
So we have a Products and Suppliers table, we also have these as a temp table so in total 4 tables (products, tempproducts, suppliers, tempsuppliers). In the suppliers and products table is where we store our products and suppliers and their temptables we store any new suppliers/products. We also have a tempsupplierproduct which joins new suppliers to new products. However we can end in a situation where a new supplier has an existing product so the new supplier will be in the tempsuppliers table and its product is in the products table NOT the tempproducts as it is not new, we will also have a new tempsupplierproduct to join the two up.
So i want a query which looks in the tempsupplierproducts table and then gets basic information about the supplier and products. To do this i am using a coalesce.
SELECT DISTINCT SP.*, COALESCE(P.Product, PD.Product) 'Product', COALESCE(S.Supplier, SU.Supplier) 'Supplier'
FROM tempsupplierproduct SP
LEFT JOIN tempProduct P ON SP.ProductCode = P.Code
LEFT JOIN Products PD ON SP.ProductCode = PD.Code
LEFT JOIN tempSupplier S ON SP.SupplierCode = S.Code
LEFT JOIN Suppliers SU ON SP.SupplierCode = SU.Code
Now while this works, something at the back of my head tells me it is not entirely right, ideally i want if data is not in table A then join to table B. I have seen maybe coalescing inside the join itself but I am unsure how to do this
LEFT JOIN Suppliers Su ON SP.SupplierCode = COALESCE(S.Code, SU.Code)
maybe away, but I am confused by this, all it is saying is use code in temptable if not there then use supplier code. So what would this mean if we have a code in the temptable, will this try to join on it, if so then this is incorrect also.
Any help is appreciated
You can union the two suppliers tables together and then join them in one go like this. I'm assuming that there are no duplicates between the two tables in this case but with a bit of extra work that could be resolved as well.
WITH AllSuppliers AS
(
SELECT Code, Supplier FROM Suppliers
UNION ALL
SELECT Code, Supplier FROM tempSupplier
)
SELECT DISTINCT SP.*, COALESCE(P.Product, PD.Product) 'Product', S.Supplier
FROM tempsupplierproduct SP
LEFT JOIN tempProduct P ON SP.ProductCode = P.Code
LEFT JOIN Products PD ON SP.ProductCode = PD.Code
LEFT JOIN AllSuppliers S ON SP.SupplierCode = S.Code
If you need to handle duplicates in the two suppliers tables then an approach like this should work, essentially we rank the duplicates and then pick the highest ranked result. For two tables you could use a full outer join between the two but this approach will scale to any number of tables.
WITH AllSuppliers AS
(
SELECT Code, Supplier, 1 AS TablePriority FROM Suppliers
UNION ALL
SELECT Code, Supplier, 2 AS TablePriority FROM tempSupplier
),
SuppliersRanked AS
(
SELECT Code, Supplier,
ROW_NUMBER() OVER (PARTITION BY Code ORDER BY TablePriority) AS RowPriority
FROM AllSuppliers
)
SELECT DISTINCT SP.*, COALESCE(P.Product, PD.Product) 'Product', S.Supplier
FROM tempsupplierproduct SP
LEFT JOIN tempProduct P ON SP.ProductCode = P.Code
LEFT JOIN Products PD ON SP.ProductCode = PD.Code
LEFT JOIN SuppliersRanked S ON SP.SupplierCode = S.Code
AND RowPriority = 1
You can absolutely join on a coalesced field. Here is a snippet from one of my production views:
LEFT JOIN [Portal].tblHelpdeskresource supplier ON PO.fld_str_SupplierID = supplier.fld_str_SupplierID
-- Job type a
LEFT JOIN [Portal].tblHelpDeskFault HDF ON PO.fld_int_HelpdeskFaultID = HDF.fld_int_ID
-- Job Type b
LEFT JOIN [Portal].tblProjectHeader PH ON PO.fld_int_ProjectHeaderID = PH.fld_int_ID
LEFT JOIN [Portal].tblPPMScheduleLine PSL ON PH.fld_int_PPMScheduleRef = PSL.fld_int_ID
-- Managers (used to be separate for a & b type, now converged)
LEFT JOIN [Portal].uvw_HelpDeskSiteManagers PSM ON COALESCE(PSL.fld_int_StoreID,HDF.fld_int_StoreID) = PSM.PortalSiteId
LEFT JOIN [Portal].tblHelpdeskResource PHDR ON PSM.PortalResourceId = PHDR.fld_int_ID

Using Count Function and Percentage of Count Total in One Select Statement

I have three data tables Employees, Departments, and Locations.
I want to show the total number of employees in each state and what percentage of the employees are located in that each state. The Employees table and the Departments table have one identical column called Department_ID, and the Departments table and the Locations table have one identical column called Location_ID. Here's what I wrote for my code:
select l.state_province e.count(*) as "Employees in State",
e.count(*)*100/sum(e.count(*)) over ()
from employees e
full outer join departments d on e.department_id = d.department_id
full outer join locations l on l.location_id = d.location_id
order by l.state_province;
However, the error "from keyword not found where expected" shows up when I run the code. How do I fix it?
You need group by. And regular joins should be fine:
select l.state_province, count(*) as "Employees in State",
count(*) * 100/sum(count(*)) over ()
from employees e join
departments d
on e.department_id = d.department_id join
locations l
on l.location_id = d.location_id
group by l.state_province
order by l.state_province;

postgresql query with join and limit

I have a table Gift. Gift's can have many gift_images via a table association. I am trying to return a LIMITED # gifts with a certain privacy level that have at least one gift_images association.
In essence, I want to return the: gift entry with its FIRST associated gift_image (gift_image should be sorted by a position value it has, with position 1 being the FIRST). Gifts without a gift_image associated should be ignored.
This is what I have, but it's definitely not working.
SELECT gifts.* FROM gifts LEFT JOIN gift_images ON gifts.id = gift_images.gift_id WHERE gifts.privacy = 2 ORDER BY gift_images.position ASC LIMIT 10
Any help?
If you want to ignore gifts without images, you should use an INNER JOIN instead of the LEFT JOIN. In addition, for the query to be meaningful, you should select some field from gift_images in addition to fields from gift.
If all gifts that have gift images have an image for which position = 1, this query should do:
SELECT gifts.*, gift_images.*
FROM gifts
INNER JOIN gift_images
ON gifts.id = gift_images.gift_id
WHERE gifts.privacy = 2
AND gift_images.position = 1
LIMIT 10
Otherwise, you could try
SELECT gifts.*, gift_images.*
FROM gifts
INNER JOIN (SELECT gift_id, MIN(position) AS min_position
FROM gift_images
GROUP BY gift_id) AS positions
ON positions.gift_id = gifts.id
INNER JOIN gift_images
ON gift_images.gift_id = gifts.id
AND gift_images.position = positions.min_position