Multi Join using subquery - postgresql

Im trying to join multiple tables and add in a Subquery. There maybe an easier way if so please let me know.
SELECT DISTINCT(first_name), last_name, title, description, release_year,rating
FROM film_actor
INNER JOIN actor
ON film_actor.actor_id = actor.actor_id
INNER JOIN film
ON film_actor.film_id = film.film_id;
WHERE rental_rate > (SELECT AVG(rental_rate) FROM film)

Related

Can't solve this SQL query

I have a difficulty dealing with a SQL query. I use PostgreSQL.
The query says: Show the customers that have done at least an order that contains products from 3 different categories. The result will be 2 columns, CustomerID, and the amount of orders. I have written this code but I don't think it's correct.
select SalesOrderHeader.CustomerID,
count(SalesOrderHeader.SalesOrderID) AS amount_of_orders
from SalesOrderHeader
inner join SalesOrderDetail on
(SalesOrderHeader.SalesOrderID=SalesOrderDetail.SalesOrderID)
inner join Product on
(SalesOrderDetail.ProductID=Product.ProductID)
where SalesOrderDetail.SalesOrderDetailID in
(select DISTINCT count(ProductCategoryID)
from Product
group by ProductCategoryID
having count(DISTINCT ProductCategoryID)>=3)
group by SalesOrderHeader.CustomerID;
Here are the database tables needed for the query:
where SalesOrderDetail.SalesOrderDetailID in
(select DISTINCT count(ProductCategoryID)
Is never going to give you a result as an ID (SalesOrderDetailID) will never logically match a COUNT (count(ProductCategoryID)).
This should get you the output I think you want.
SELECT soh.CustomerID, COUNT(soh.SalesOrderID) AS amount_of_orders
FROM SalesOrderHeader soh
INNER JOIN SalesOrderDetail sod ON soh.SalesOrderID = sod.SalesOrderID
INNER JOIN Product p ON sod.ProductID = p.ProductID
HAVING COUNT(DISTINCT p.ProductCategoryID) >= 3
GROUP BY soh.CustomerID
Try this :
select CustomerID,count(*) as amount_of_order from
SalesOrder join
(
select SalesOrderID,count(distinct ProductCategoryID) CategoryCount
from SalesOrderDetail JOIN Product using (ProductId)
group by 1
) CatCount using (SalesOrderId)
group by 1
having bool_or(CategoryCount>=3) -- At least on CategoryCount>=3

nesting joins right to left in postgres

I have a big query, but it all boils down to this:
SELECT * FROM user
LEFT JOIN tableA ON tableA.user_id = user.id
JOIN tableB ON tableB.a_id = tableA.id
Now, I get too few results. If the combination of user with (tableA x tableB) does not exist, I still want the user. So with syntax error, what I want is something like this:
SELECT * FROM user
LEFT JOIN (tableA ON tableA.user_id = user.id
JOIN tableB ON tableB.a_id = tableA.id)
is that possible, perhaps without RIGHT JOINS?
Of course, I don't want to change the second JOIN to LEFT JOIN, because that would give too many results.
You can try this:
SELECT * FROM user
LEFT JOIN (SELECT * FROM tableA
JOIN tableB ON tableB.a_id = tableA.id) t
ON t.user_id = user.id
You will need to select distinct columns in subquery here if any exists.

Avoid nested loop in PostgreSQL

See query below
Select count(*) FROM
(Select distinct Student_ID, Name, Student_Age, CourseID from student) a1
JOIN
(Select distinct CourseID, CourseName, TeacherID from courses) a2
ON a1.CourseID=a2.CourseID
JOIN
(Select distinct TeacherID, TeacherName, Teacher_Age from teachers) a3
ON a2.TeacherID=a3.TeacherID
The subqueries must be used for deduping purpose.
This query run fine in PostgreSQL. However, if I add a condition between the student and teacher table, according to the execution plan, Postgres will wrongly nested loop join the student and teach tables which have no direct relationship. For example:
Select count(*) FROM
(Select distinct Student_ID, Name, Student_Age, CourseID from student) a1
JOIN
(Select distinct CourseID, CourseName, TeacherID from courses) a2
ON a1.CourseID=a2.CourseID
JOIN
(Select distinct TeacherID, TeacherName, Teacher_Age from teachers) a3 ON
a2.TeacherID=a3.TeacherID
WHERE Teacher_Age>=Student_Age
This query will take forever to run. However, if I replace the subqueries with the tables, it'll run very fast. Without using temp tables to store the deduping result, is there a way to to avoid the nested loop in this situation?
Thank you for your help.
You're making the database perform a lot of unnecessary work to accomplish your goal. Instead of doing 3 different SELECT DISTINCT sub-queries all joined together, try joining the base tables directly to each other and let it handle the DISTINCT part only once. If your tables have proper indexes on the ID fields, this should run rather quick.
SELECT COUNT(1)
FROM (
SELECT DISTINCT s.Student_ID, c.CourseID, t.TeacherID
FROM student s
JOIN courses c ON s.CourseID = c.CourseID
JOIN teachers t ON c.TeacherID = t.TeacherID
WHERE t.Teacher_Age >= s.StudentAge
) a

Join tables query in SQL Server 2012

I have two tables like below:
TableA --> categoryId(pk), categoryParentId, catName
TableB --> empId(pk), categoryId, empName, empDesignation
I want to get all catName with respective categoryId from TableA where categoryId=2 of TableB is equal to categoryParentId=2 of TableA. Please help.
Result:
1002 SE
1003 MD
Something like this?
SELECT DISTINCT catName FROM TABLEA WHERE categoryParentId IN (SELECT DISTINCT categoryID from TABLEB);
I hope this query will fulfill your need
SELECT TABLEA.CATNAME AS CATEGORY
from TABLEB INNER JOIN TABLEA
ON TABLEA.CATEGORYPARENTID = TABLEB.CATEGORYID
Solution with INNER JOIN:
select TableA.catName
from TableA
inner join TableB on TableA.categoryParentId = TableB.categoryId
Using INNER JOIN is the recommended way to use for joining tables (as opposed to SELECT ... FROM TableA, TableB ...)
See:
INNER JOIN ON vs WHERE clause
(this question was actually about MySql, but the answers say that it's the same for SQL Server)
Difference in INNER join and cartesian join in SQL Server
Answering your comment (I assume that you wanted the categoryId from TableA):
select TableA.catName, TableA.categoryId
from TableA
inner join TableB on TableA.categoryParentId = TableB.categoryId
where TableB.categoryId = 2
another method...
SELECT
catname
from
tablea a INNER JOIN
tableb b ON
a.categoryParentID = b.categoryID
group by
catname
This should do the trick
SELECT tableA.catName
FROM tableA, tableB
WHERE tableB.categoryId = table1.categoryParentId
AND tableB.categoryId = 2;
If you want the unique catNames, you can use
SELECT distinct tableA.catName
FROM tableA, tableB
WHERE tableB.categoryId = table1.categoryParentId
AND tableB.categoryId = 2;

MS Access INNER JOIN most recent entry

I'm having some trouble trying to get Microsoft Access 2007 to accept my SQL query but it keeps throwing syntax errors at me that don't help me correct the problem.
I have two tables, let's call them Customers and Orders for ease.
I need some customer details, but also a few details from the most recent order. I currently have a query like this:
SELECT c.ID, c.Name, c.Address, o.ID, o.Date, o.TotalPrice
FROM Customers c
INNER JOIN Orders o
ON c.ID = o.CustomerID
AND o.ID = (SELECT TOP 1 ID FROM Orders WHERE CustomerID = c.ID ORDER BY Date DESC)
To me, it appears valid, but Access keeps throwing 'syntax error's at me and when I hit OK, it selects a piece of the SQL text that doesn't even relate to it.
If I take the extra SELECT clause out it works but is obviously not what I need.
Any ideas?
You cannot use AND in that way in MS Access, change it to WHERE. In addition, you have two reserved words in your column (field) names - Name, Date. These should be enclosed in square brackets when not prefixed by a table name or alias, or better, renamed.
SELECT c.ID, c.Name, c.Address, o.ID, o.Date, o.TotalPrice
FROM Customers c
INNER JOIN Orders o
ON c.ID = o.CustomerID
WHERE o.ID = (
SELECT TOP 1 ID FROM Orders
WHERE CustomerID = c.ID ORDER BY [Date] DESC)
I worked out how to do it in Microsoft Access. You INNER JOIN on a pre-sorted sub-query. That way you don't have to do multiple ON conditions which aren't supported.
SELECT c.ID, c.Name, c.Address, o.OrderNo, o.OrderDate, o.TotalPrice
FROM Customers c
INNER JOIN (SELECT * FROM Orders ORDER BY OrderDate DESC) o
ON c.ID = o.CustomerID
How efficient this is another story, but it works...