Complex sql select - sql

I can't figure out how to make this sql select statement...Here are my tables :
I opened the tables concerned by the request
So basically I want to select the number of albums for each interpret.
I just can't figure it out... I am currently thinking that I need to do my first select on album like :
select interpret.no_interpret, count(*)
from album
.
.
.
group by interpret.no_interpret;
and there work from this but I don't know where to go next.

I may be missing something, but I'm not seeing the direct relation from your song table to the album...
I would first start by getting the link_interpret_song table joined to the song table and get count of distinct albums. However, I didn't see what appears to be a "No_Album" column in the field list of the song table. I can only guess it IS in there associated to the particular album. I did see media, but to me, that would be like a TYPE of media (digital, download, vinyl, CD) vs the actual ID Key apparent to the album table.
That said, I am thinking there IS such a "No_Album" column in the SONG table.
select
LIS.No_Interpret,
COUNT( DISTINCT S.No_Album )
from
Link_Interpret_Song LIS
JOIN Song S
on LIS.No_Song = S.No_Song
group by
LIS.No_Interpret;
Now, that said, if you want the interpret details, take the above results and join that to the interpret table. I've done both distinct album count and total # of songs just as an example of count() vs count(distinct) context... such as
select
PreCounts.No_Interpret,
PreCounts.DistinctAlbums,
PreCounts.ActualSongs,
I.Name_Interpret,
I.First_Name,
I.Stage_Name
from
( select
LIS.No_Interpret,
COUNT( DISTINCT S.No_Album ) as DistinctAlbums,
COUNT(*) as ActualSongs
from
Link_Interpret_Song LIS
JOIN Song S
on LIS.No_Song = S.No_Song
group by
LIS.No_Interpret ) as PreCounts
JOIN Interpret I
ON PreCounts.No_Interpret = I.No_Interpret

The question is ambiguous since there isn't a clear indication of how the tables are related. Given assumptions about these relations, your query will likely take on something similar to the following form:
SELECT COUNT(distinct a.no_album) from album a, interpret i, song s
where i.no_song=s.no_song
and a.no_album=s.no_album GROUP BY i.no_interpret

Related

SQL query for finding the movies that users haven't watched

Let, these are the two tables
I've used except keyword to get the desired output
Now, my case is that there are two tables having:
All the user-related data is available (user_id, email, contact...) User_id is of importance for us.
User_id and the movie name that a particular user watches ( multiple records can be there for each user ) Basically this table is created when any user watches a movie that is available.
I don't have the list of available movies, so let us assume that all the movies have been covered by some or the other user in table 2. By using a distinct keyword will give all the movies available.
I need to get a query that gives the output like the user id and the movies that the particular user hasn't watched. Is there a way to get the output without using "PLSQL", "except", "anti join", or "exists" keyword on SQL
SELECT DISTINCT
"tabl1"."type",
"tabl2"."user_id"
FROM
"tabl2"
RIGHT JOIN
"tabl1" ON "tabl1"."userid" = "tabl2"."user_id"
WHERE
"tabl1"."type" NOT IN (SELECT DISTINCT "type"
FROM "tabl1"
LEFT JOIN "tabl2" ON "tabl1"."userid" = "tabl2"."user_id"
WHERE "tabl2"."user_id" IN (SELECT DISTINCT "user_id"
FROM "tabl2"))
I've tried using the join operation but it doesn't give any result and end up having NULL only.
I'm stuck on how to get the required output.
Is there a way to get a similar output like this without using the functions described above.
This looks like the opposite of a many-to-many relationship because one user maybe not watch many movies and one movie not watch by many users.
why you do retrieve it as movies not watch by the particular user.
select movie_name from Movie_table where movie_name not in( select movie_name from userMovieTable where user_id =: user_id)
You want to join user and movie on the condition that the pair is not in the watched table:
with movies as (select distinct movie from watched)
select *
from users u
join movies m on (u.userid, m.movie) not in (select userid, movie from watched)
order by u.userid, m.movie;

Understanding summary of inner query

Problem understanding subquery
I do not understand this example from www.sqlitetutorial.net/sqlite-subquery :
Only one number is returned by the inner query: 1422138358
But the average of this number is different:
So why is the average of 1422138358 not 1422138358? The two queries are not independent? If I remove "ORDER BY albumid" the result is the same:
Example data:
http://www.sqlitetutorial.net/sqlite-sample-database/
Edit: Ok, there is probably some integer overflow going on as the columns are integer, but I still don't understand why the example take the average of a single number?
Very possibly that it was a mistake
1)
From the text you can see that they wanted to 'sum the size of an album' and you`re querying Tracks table, which supposedly have an album_ID column
2)
You cannot use ORDER BY if you`re using only aggregation column
such as
select SUM(bytes)
from Tracks
Order by albumID
because it has nothing to order it by from.
Also note that you cannot use order by in subqueries
Finally what was missing here was this remaining of the query :
Select AVG(album.size) as [avg(album.size)]
from (
select albumID,SUM(bytes) as size
from Tracks
GROUP BY albumID
) as album
You can learn more about subqueries here
And if you want to play around with these, heres the code that you can replicate and use it for further exercies on that website:
CREATE TABLE tracks (AlbumID int,bytes int)
CREATE TABLE albums (AlbumID int, title nvarchar(50))
insert into Tracks values (1,2),(2,10),(3,15)
Select AVG(album.size) as [avg(album.size)]
from (
select AlbumID,SUM(bytes) as size
from tracks
GROUP BY albumID
) as album
Hope it helps

SQL nested subqueries

I have a schema "Album" for a music database.
This schema includes attributes: Name, Artist, Rating and Year.
I'm trying to create a query that will allow me to get the names of all albums which have a higher rating than every previous album by the same person. I need to check every tuple in my database and compare tuples where artists are the same, and where the year of one album is greater than the year of another, and also compare rating.
I've tried a few different things all using different strategies. My current attempt is a nested query:
SELECT A1.Title
FROM Album A1
WHERE A1.Title NOT IN (SELECT A2.Title
FROM Album A2
WHERE A1.Artist = A2.Artist, A1.Year > A2.Year, A1.Rating > A2.Rating);
This obviously doesn't work (hence my question) - where am I going wrong? I thought a correlated query (like this one) checks every tuple in the table against the subquery? Any clearance on how I could do this query is appreciated. I'm pretty novice at SQL.
I would use window functions:
select a.*
from (select a.*,
max(a.rating) over (partition by a.artist
order by a.year
range between unbounded preceding and 1 preceding
) as prev_max_rating
from album a
) a
where rating > prev_max_rating;
(after replacing the commas by ANDs) The NOT EXISTS(...) is similar to NOT IN(...), but behaves nicer if NULLs are involved.
SELECT A1.Title
FROM Album A1
-- There should not exist an older album with a higher rating
-- (for the same artist)
WHERE NOT EXISTS (SELECT *
FROM Album A2
WHERE A2.Artist = A1.Artist
AND A2.Year < A1.Year
AND A2.Rating > A1.Rating -- Note: the sign is flipped, compared to the query in the question
);

Select query from three tables SQL

The database is Oracle XE .
Let me explain the scenario first ,
Two tables Movie and UserInfo are in a relationship many to many using the junction table Rating.
Rating ( MovieID (FK) , UserName(FK) , Rating)
MovieID and UserName are both respectively the primary keys in the respected tables.
What I am trying to do is make a select statement to select the MovieNames from the Movie table where UserName is not equal to the given input. As the MoveID was the FK, but I need to retrieve MovieName if the movie is not already been rated by the GIVEN user, so I guess I may need to make a rather complex joining operation - which I can't figure out or maybe joining two or more different query using where.
Thanks in advance and please if possible give an explanation about the solution.
This seems like a classic usecase for the not exists operator:
SELECT *
FROM movie m
WHERE NOT EXISTS (SELECT *
FROM rating r
WHERE r.movideid = m.moveid AND
r.username = 'given username here')

correlated query to update a table based on a select

I have these tables Genre and Songs. There is obviously many to many relationship btw them, as one genre can have (obviously) have many songs and one song may belong to many genre (say there is a song xyz, it belong to rap, it can also belong to hip-hop). I have this table GenreSongs which acts as a many to many relationship map btw these two, as it contains GenreID and SongID column. So, what I am supposed to do this, add a column to this Genre table named SongsCount which will contain the number of songs in this genre. I can alter table to add a column, also create a query that will give the count of song,
SELECT GenreID, Count(SongID) FROM GenreSongs GROUP BY GenreID
Now, this gives us what we require, the number of songs per genre, but how can I use this query to update the column I made (SongsCount). One way is that run this query and see the results, and then manually update that column, but I am sure everyone will agree that's not a programmtic way to do it.
I came to think I would require to create a query with a subquery, that would get the value of GenreID from outer query and then count of its value from inner query (correlated query) but I can't make any. Can any one please help me make this?
The question of how to approach this depends on the size of your data and how frequently it is updated. Here are some scenarios.
If your songs are updated quite frequently and your tables are quite large, then you might want to have a column in Genre with the count, and update the column using a trigger on the Songs table.
Alternatively, you could build an index on the GenreSong table on Genre. Then the following query:
select count(*)
from GenreSong gs
where genre = <whatever>
should run quite fast.
If your songs are updated infrequently or in a batch (say nightly or weekly), then you can update the song count as part of the batch. Your query might look like:
update Genre
set SongCnt = cnt
from (select Genre, count(*) as cnt from GenreCount gc group by Genre) gc
where Genre.genre = gc.Genre
And yet another possibility is that you don't need to store the value at all. You can make it part of a view/query that does the calculation on the fly.
Relational databases are quite flexible, and there is often more than one way to do things. The right approach depends very much on what you are trying to accomplish.
Making a table named SongsCount is just plainly bad design (redundant data and update overhead). Instead use this query for single results:
SELECT ID, ..., (SELECT Count(*) FROM GenreSongs WHERE GenreID = X) AS SongsCount FROM Genre WHERE ID = X
And this for multiple results (much more efficient):
SELECT ID, ..., SongsCount FROM (SELECT GenreID, Count(*) AS SongsCount FROM GenreSongs GROUP BY GenreID) AS sub RIGHT JOIN Genre AS g ON sub.GenreID = g.ID