how to get the counter column based on another column? - sql

I have a table with the info about buildings, a table about expenses, a table about users and a table that does the billing.
In the billing table, I need to have a counter that counts different users inside a building.
I tried to do this with the ROW_NUMBER() but I can't get the desired result.
This is my query so far:
SELECT r.id, r.building_id AS zID,z.name AS zName,
r.user_id AS kID, k.Name AS kName,
expence_id AS uID,u.name AS uName,u.price AS uPrice,
IIF(u.unique=1,u.price,k.kvadratura * u.price) AS Balance,
r.year,r.month,
ROW_NUMBER() OVER(Partition by r.user_id ORDER BY r.id) AS Counter
FROM Bill r
INNER JOIN Expences u ON r.usluga_id = u.id
INNER JOIN Building z ON r.zgrada_id = z.id
INNER JOIN User k ON r.korisnik_id = k.id
WHERE r.building_id =7
This is my output:
What I would want to get is this:
For every user inside a building, counter+1.

You should use DENSE_RANK instead of ROW_NUMBER.
SELECT
r.id, r.building_id AS zID,z.name AS zName,
r.user_id AS kID, k.Name AS kName,
expence_id AS uID,u.name AS uName,u.price AS uPrice,
IIF(u.unique=1,u.price,k.kvadratura * u.price) AS Balance,
r.year,r.month,
DENSE_RANK() OVER(Partition by r.building_id ORDER BY r.user_id) AS Counter
FROM
Bill r
INNER JOIN Expences u ON r.usluga_id = u.id
INNER JOIN Building z ON r.zgrada_id = z.id
INNER JOIN User k ON r.korisnik_id = k.id
WHERE r.building_id = 7

Try to add expence_id to partition.
SELECT r.id, r.building_id AS zID,z.name AS zName,
r.user_id AS kID, k.Name AS kName,
expence_id AS uID,u.name AS uName,u.price AS uPrice,
IIF(u.unique=1,u.price,k.kvadratura * u.price) AS Balance,
r.year,r.month,
ROW_NUMBER() OVER(Partition by r.user_id, expence_id ORDER BY r.id) AS Counter
FROM Bill r
INNER JOIN Expences u ON r.usluga_id = u.id
INNER JOIN Building z ON r.zgrada_id = z.id
INNER JOIN User k ON r.korisnik_id = k.id
WHERE r.building_id =7

Related

SELECT * and SELECT COUNT(*) in one query

My SQL query looks like this
SELECT *
FROM categories AS c
LEFT JOIN LATERAL (SELECT i.*
FROM influencer_profiles AS i
WHERE c.id = i.category_id
ORDER BY i.updated_at
LIMIT 2) AS i ON 1 = 1
INNER JOIN users AS u ON i.user_id = u.id
But I also want to count each influencer_profile for category to display how many influencer_profiles in each categories. How can I use COUNT(*) with selecting all columns?
SELECT *
FROM categories AS c
LEFT JOIN LATERAL (SELECT COUNT(*)
FROM influencer_profiles AS i
WHERE c.id = i.category_id
ORDER BY i.updated_at
LIMIT 2) AS i ON 1 = 1
INNER JOIN users AS u ON i.user_id = u.id
This code doesn't work.
Perhaps you just want a window function. I note that you are using left join in one place and the inner join is undoing it.
So, I am thinking:
SELECT c.*, i.*, u.*,
COUNT(*) OVER (PARTITION BY c.id) as category_cnt
FROM categories c LEFT JOIN LATERAL
(SELECT i.*
FROM influencer_profiles AS i
WHERE c.id = i.category_id
ORDER BY i.updated_at
LIMIT 2
) i
ON 1=1 LEFT JOIN
users u
ON i.user_id = u.id;

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)

Query , joining, SQL server example (Concert) with a couple of related tables

I dont know who to return what I wrote before, apologise. vowejin firnefk rneqkln qrecjinrelqkjnr klwencirowejncienfvenciernicnreinc ikrenicernircniwncikwnkwjnkcjwnkjnckjncwkjnwckjnweknckejnckwjnckjnwekcjnwekjnckwjenckjwenkcjnwekjnckwenckwjenklwneocnwocnowencoejnkjwencojnwekojcnwekjcnkwejnckejcnkwejnckjwenkcjnwkjcnwkn:)
Using TOP:
SELECT TOP 1
PID, NAME, AGE
FROM (
SELECT
p.*, h.HID
FROM Performer p
INNER JOIN Concert c
ON c.PID = p.PID
INNER JOIN Hall h
ON h.HID = c.HID
INNER JOIN Tickets t
ON t.CID = c.CID
GROUP BY p.PID, p.NAME, p.AGE, h.HID, h.CAPACITY
HAVING COUNT(t.TID) = h.CAPACITY
) t
GROUP BY PID, NAME, AGE
ORDER BY COUNT(*) DESC
This should return expected result
;with Cte1 AS (
select C.CID, P.Name AS PerformerName, H.Name AS HallName, H.Capacity, H.HID
from #Performer P
inner join #Concert C on C.PID = P.PID
inner join #Hall H on H.HID = C.HID
)
, Cte2 AS (
select C.CID, H.HID, COUNT(*) SellCount
from #Concert C
inner join #Hall H on H.HID = C.HID
inner join #Tickets T on T.CID = C.CID
group by C.CID, H.HID
)
select Cte1.CID, Cte1.PerformerName, Cte1.HallName, Cte2.SellCount
from Cte1 inner join Cte2 on Cte2.CID = Cte1.CID AND Cte2.HID = Cte1.HID
where Cte1.Capacity = Cte2.SellCount

How to find the second largest value within certain row?

I have two tables, movies(id, name, year, rating) and movies_genres(movie_id, genre), I want to find the id of all second top rated movies within each genre(not global), but when I wrote this
select MG.genre, M.id
from movies_genres MG inner join movies M on MG.movie_id = M.id
where M.rating =
(select max(rating) from
(select rating from movies M2 inner join movies_genres MG2 on M2.id = MG2.movie_id where MG2.genre = MG.genre)
where rating <
(select max(rating) from
(select rating from movies M3 inner join movies_genres MG3 on M3.id = MG3.movie_id where MG3.genre = MG.genre)))
order by MG.genre;
I got an error, it said that the MG.genre in Line 5 is a invalid identifier.
If you are using a database other than mysql you can use row_number window function to get the second highest rated movie for each genre.
select MG.genre, M.id
from movies_genres MG
inner join movies M on MG.movie_id = M.id
inner join (select m.*,mg.*,
row_number() over(partition by mg.genre order by m.rating desc) as rn
from movies m inner join movies_genres mg on mg.movie_id = M.id) x
on x.id = m.id and mg.genre = x.genre
where x.rn = 2;
You don't have to make a reference to the outer genre, only to the next select level like this:
Select MG.genre, M.id
From movies_genres MG, movies M
Where M.id = MG.movie_id
And M.rating = (Select max(rating)
From movies M2, movies_genres MG2
Where M2.id = MG2.movie_id
And MG2.genre = MG.genre
And rating < (Select max(rating)
From movies M3, movies_genres MG3
Where M3.id = MG3.movie_id
And MG3.genre = MG2.genre)
)
order by MG.genre;
Edited: oopsie, I've missed one reference to genre: And MG2.genre = MG.genre. Just added.
How does it work? The most inner select returns the max rating of the ask genre MG2. The middle select returns the max rating of asked genre MG, which is lower than the max of most inner select. The outer select list all movie ids (and genre) with this exact rating.

Third Table inner join

I retrieve datas with inner join with two tables.This is the sql:
SELECT mc.user_id, mc.id AS movie_comment_id, mc.add_date,
mc.movie_id, mc.comment, m.id, m.name
FROM movie_comment AS mc
INNER JOIN movie AS m ON m.id = mc.movie_id
WHERE movie_id = 1500
AND stat = 'onayli'
ORDER BY mc.add_date DESC
LIMIT 10
What i want is that retriving also usernames from user table.I wrote this sql but does not work
SELECT u.id, u.username, mc.user_id, mc.id AS movie_comment_id, mc.add_date,
mc.movie_id, mc.comment, m.id, m.name
FROM movie_comment AS mc
INNER JOIN movie AS m ON m.id = mc.movie_id
ON mc.user_id = u.id
WHERE movie_id = 1500
AND stat = 'onayli'
ORDER BY mc.add_date DESC
LIMIT 10
How can i also retrieve usernames ?
You need to specify INNER JOIN at the start of each inner join.
select u.ID ,u.USERNAME,mc.USER_ID,mc.ID as Movie_Comment_ID,mc.ADD_DATE,mc.MOVIE_ID,mc.COMMENT,m.ID,m.NAME
from MOVIE_COMMENT as mc
INNER Join MOVIE as m ON m.ID=mc.MOVIE_ID
INNER JOIN [USER] u ON mc.USER_ID = u.ID
WHERE MOVIE_ID = 1500 and STAT='onayli' ORDER BY mc.ADD_DATE DESC LIMIT 10
select u.ID ,u.USERNAME,mc.USER_ID,mc.ID as Movie_Comment_ID,mc.ADD_DATE,mc.MOVIE_ID,mc.COMMENT,m.ID,m.NAME
from MOVIE_COMMENT as mc
INNER Join MOVIE as m ON m.ID=mc.MOVIE_ID
INNER JOIN usertable as u ON mc.USER_ID = u.ID
WHERE MOVIE_ID = 1500 and STAT='onayli' ORDER BY mc.ADD_DATE DESC LIMIT 10
SELECT u.ID,
u.USERNAME,
mc.USER_ID,
mc.ID as Movie_Comment_ID,
mc.ADD_DATE,
mc.MOVIE_ID,
mc.COMMENT,
m.ID,
m.NAME
FROM MOVIE_COMMENT as mc
INNER JOIN MOVIE as m ON m.ID = mc.MOVIE_ID
INNER JOIN [User] u ON u.ID = mc.USER_ID
WHERE MOVIE_ID = 1500 and STAT='onayli' ORDER BY mc.ADD_DATE DESC LIMIT 10