SQL: get attributes from nested query - sql

How can I return d.title or u.name in the outer SELECT clause?
SELECT c.id, c.name
FROM components c
INNER JOIN publications p
ON c.id = p.component_id
AND p.document_id IN
(SELECT d.id FROM documents d WHERE user_id IN
(SELECT u.id FROM users u WHERE u.brand_id IN (39, 41)
)
)
I get this error when I throw d.title in the top line:
missing FROM-clause entry for table "d" LINE 1
The package I'm using needs these values returned on the top line to make any use out of them in the result.
Structure
A User has many Documents, and Publications is the join table between Documents and Components.

Use below query -
SELECT c.id, c.name, d.title, u.name
FROM components c
INNER JOIN publications p ON c.id = p.component_id
INNER JOIN documents d ON d.id = p.document_id
INNER JOIN users u ON d.user_id = u.id
AND u.brand_id IN (39, 41)
Hope this helps.

Related

Get null records in SQL

I have the next query:
SELECT c.name as clientName, p.id as projectId, p.name as projectName, p.rate, u.name as userName, sum(w.duration) as workedHours
FROM Project p, User u, Worklog w, Client c
WHERE w.user_id = u.id AND w.project_id = p.id AND p.client_id = c.id
GROUP BY p.id, u.id
that returns the projects, clients, hourly rate and worked hours.
How should be changed to return also the projects where workedHours is equal with 0?
Because this query returns just the records where workedHours is not 0.
Thank you for your time.
The problem is that no row in worklog can be joined, and that your condition in the WHERE clause removes any row without worklog associated.
Solution 1 : Using a LEFT JOIN
Using a left join instead would solve your problem.
SELECT c.name as clientName, p.id as projectId, p.name as projectName, p.rate, u.name as userName, coalesce(sum(w.duration), 0) as workedHours
FROM Project p, User u, Client c
LEFT JOIN Worklog w ON w.project_id = p.id AND w.user_id = u.id
WHERE p.client_id = c.id
GROUP BY p.id, u.id
By the way your query is suspicious in other aspects. For example c.name is in the SELECT clause but not in the GROUP BY clause. I take it that you use MySQL which is the only RDBMS I'm aware of which allows such queries. You maybe should consider adding the retrieved columns in the GROUP BY clause.
Solution 2 : Using only ANSI JOINs
As underscore_d points out, you may want to avoid old-style joins completely, and preferable use the following query :
SELECT
c.name as clientName,
p.id as projectId,
p.name as projectName,
p.rate,
u.name as userName,
coalesce(sum(w.duration), 0) as workedHours
FROM Project p
CROSS JOIN User u
INNER JOIN Client c ON p.client_id = c.id
LEFT JOIN Worklog w ON w.project_id = p.id AND w.user_id = u.id
GROUP BY c.name, p.id, p.name, p.rate, u.id, u.name
Solution 3 - Using a subquery
Another solution is to use a subquery, which would allow you to remove the GROUP BY clause completely and get a more manageable query if you ever need to retrieve more information. I personally don't like long lists of columns in a GROUP BY clause.
SELECT
c.name as clientName,
p.id as projectId,
p.name as projectName,
p.rate,
u.name as userName,
(SELECT SUM(duration) FROM Worklog WHERE project_id = c.id AND user_id = u.id) as workedHours
FROM Project p
CROSS JOIN User u
INNER JOIN Client c ON p.client_id = p.id
You should use standard ANSI joins and use LEFT JOIN on worklog table and ultimately you have to use LEFT JOIN on the user table as follows:
SELECT C.NAME AS CLIENTNAME,
P.ID AS PROJECTID,
P.NAME AS PROJECTNAME,
P.RATE,
U.NAME AS USERNAME,
SUM(W.DURATION) AS WORKEDHOURS
FROM PROJECT P
JOIN CLIENT C
ON P.CLIENT_ID = C.ID
LEFT JOIN WORKLOG W
ON W.PROJECT_ID = P.ID
LEFT JOIN USER U
ON W.USER_ID = U.ID
GROUP BY P.ID,
U.ID;

SQL to HiveQL conversion

I have this SQL query and I am trying to convert it so that it can be run on HiveQL 2.1.1.
SELECT p.id FROM page p, comments c, users u,
WHERE c.commentid= p.id
AND u.id = p.creatorid
AND u.upvotes IN (
SELECT MAX(upvotes)
FROM users u WHERE u.date > p.date
)
AND EXISTS (
SELECT 1 FROM links l WHERE l.relid > p.id
)
This does not work on Hive QL, as it has more than 1 SubQuery (which is not supported)
EXISTS or IN replacements from SQL to Hive SQL are done like this:
WHERE A.aid IN (SELECT bid FROM B...)
can be replaced by:
A LEFT SEMI JOIN B ON aid=bid
But I can`t come up with a way to do this with the additional MAX() function.
Use standard join syntax instead of comma separated :
SELECT p.id
FROM page p INNER JOIN
comments c
ON c.commentid= p.id INNER JOIN
users u
ON u.id = p.creatorid INNER JOIN
links l
ON l.relid > p.id
WHERE u.upvotes IN (SELECT MAX(upvotes)
FROM users u
WHERE u.date > p.date
);
I am not sure what the upvotes logic is supposed to be doing. The links logic is easy to handle. Hive may handle this:
SELECT p.id
FROM page p JOIN
comments c
ON c.commentid = p.id JOIN
users u
ON u.id = p.creatorid CROSS JOIN
(SELECT MAX(l.relid) as max_relid
FROM links l
) l
WHERE l.max_relid > p.id AND
u.upvotes IN (SELECT MAX(upvotes)
FROM users u
WHERE u.date > p.date
);

SQL Get Only Most Recent Record for A User [duplicate]

This question already has answers here:
Get top 1 row of each group
(19 answers)
Closed 4 years ago.
I have a situation where I need to write a sql query to get all of the most recent responses for a student in a classroom. I basically want to show just their most recent response, not all of their responses. I have the query to get all of the responses and order them, however I can't figure out the part where it only grabs that user's most recent record.
Below is the query I have to this point. You can see from the sample data in the image it is pulling back all responses. What I basically want is either just the most recent for a particular student OR possibly just showing the max attempt for a particular Lesson/Page number combo. I have tried playing around with partition and group bys but I haven't found the right combination yet.
SELECT U.UserName, C.Name AS 'ClassroomName', U.FirstName, U.LastName, L.Name AS 'LessonName', P.PageNumber, R.Attempt, R.Created
FROM Responses R
INNER JOIN ClassroomUsers CU ON CU.UserId = R.UserId
INNER JOIN Classrooms C ON C.Id = CU.ClassroomId
INNER JOIN Questions Q ON Q.Id = R.QuestionId
INNER JOIN Pages P ON P.Id = Q.PageId
INNER JOIN Lessons L ON L.Id = P.LessonId
INNER JOIN AspNetUsers U ON U.Id = CU.UserId
WHERE CU.ClassroomId IN (
SELECT CU.ClassroomId
FROM ClassroomUsers CU
WHERE CU.UserId = #UserId
)
ORDER BY R.Created DESC
My favorite way of doing this is using Row_Number() which will number each row based upon the criteria you set - In your case, you'd partition by U.UserName since you want one row returned for each user and order by R.Created DESC to get the latest one.
That being the case, you'd only want to get back the rows that have RN=1, so you query that out as follows:
WITH cte AS
(
SELECT
ROW_NUMBER() OVER(PARTITION BY U.UserName ORDER BY R.Created DESC) AS RN
,U.UserName, C.Name AS 'ClassroomName', U.FirstName, U.LastName, L.Name AS 'LessonName', P.PageNumber, R.Attempt, R.Created
FROM Responses R
INNER JOIN ClassroomUsers CU ON CU.UserId = R.UserId
INNER JOIN Classrooms C ON C.Id = CU.ClassroomId
INNER JOIN Questions Q ON Q.Id = R.QuestionId
INNER JOIN Pages P ON P.Id = Q.PageId
INNER JOIN Lessons L ON L.Id = P.LessonId
INNER JOIN AspNetUsers U ON U.Id = CU.UserId
WHERE CU.ClassroomId IN (
SELECT CU.ClassroomId
FROM ClassroomUsers CU
WHERE CU.UserId = #UserId
)
)
SELECT * FROM cte WHERE RN = 1
Hope that makes sense / helps!!
Just another option is using the WITH TIES clause.
Example
SELECT top 1 with ties
U.UserName
, C.Name AS 'ClassroomName'
, U.FirstName
, U.LastName
, L.Name AS 'LessonName'
, P.PageNumber
, R.Attempt
, R.Created
FROM Responses R
INNER JOIN ClassroomUsers CU ON CU.UserId = R.UserId
INNER JOIN Classrooms C ON C.Id = CU.ClassroomId
INNER JOIN Questions Q ON Q.Id = R.QuestionId
INNER JOIN Pages P ON P.Id = Q.PageId
INNER JOIN Lessons L ON L.Id = P.LessonId
INNER JOIN AspNetUsers U ON U.Id = CU.UserId
WHERE CU.ClassroomId IN (
SELECT CU.ClassroomId
FROM ClassroomUsers CU
WHERE CU.UserId = #UserId
)
Order By ROW_NUMBER() OVER(PARTITION BY U.UserName ORDER BY R.Created DESC)

Creating a stored procedure with many-to-many relationship giving proper response

I'm trying to create a Stored Procedure for my school project which uses Model First.
I wanted to make a SP for returning av list of games with most orders, as a 'top list' so to speak, but can't figure it out after searching for similiar threads. The parameter #antal should return the range of distinct results to give back. So let's say I send in 5 it should return 5 Products, and 3 should return 3 products and so forth...
Since I am new to this, I'm stuck. The code so far is:
use SpelAffarenDatabas
go
create procedure [dbo].[GetTopListGames]
(
#antal int
)
as
select distinct top (6) p.Id, p.Name, p.Orders, k.Name, g.Name from ProduktSet as p
left join ConsoleProduct as kp
on p.Id = kp.Product_Id
left join ConsoleSet as k
on kp.Console_Id = k.Id
left join ProductGenre as pg
on p.Id = pg.Product_Id
left join GenreSet as g
on pg.Genre_Id = g.Id
group by p.Id, p.Name, p.Orders, k.Name, g.Name
So how do I go about getting a proper response that gives me a proper response, whic I guess would be of distinct entities?
select distinct top (#antal) p.Id, p.Name, p.Orders, k.Name, g.Name from ProduktSet as p
left join ConsoleProduct as kp
on p.Id = kp.Product_Id
left join ConsoleSet as k
on kp.Console_Id = k.Id
left join ProductGenre as pg
on p.Id = pg.Product_Id
left join GenreSet as g
on pg.Genre_Id = g.Id
group by p.Id, p.Name, p.Orders, k.Name, g.Name
order by p.Orders Desc

Join query equivalent to Not IN clause (SQL Server 2008)

I have a query with a not in clause like this:
select *
FROM COMPANY c
where c.company_id not In (SELECT SenderId
FROM CrossRef)
and c.id not in (select company_id
FROM USER)
I am wondering if there is a way to re-write that query using a left join in SQL Server 2008.
I tried the following one but it's not giving the correct result
select c.id, c.company_id
from COMPANY c
left join CrossRef cr on c.company_id != cr.senderid, COMPANY c1
left join USER u on c1.id != u.company_id
SELECT *
FROM Company C
LEFT JOIN CrossRef R ON R.SenderID = C.CompanyID
LEFT JOIN [User] U ON U.company_id = C.id
WHERE R.SenderID IS NULL
AND U.company_id IS NULL