sqlzoo track join exercise - sql

I've found a great site to practice sql - http://sqlzoo.net. my sql is very weak that is why i want to improve it by working on the exercises online. But i have this one problem that I cannot solve. can you please give me a hand.
3a. Find the songs that appear on more than 2 albums. Include a count of the number of times each shows up.
album(asin, title, artist, price, release, label, rank)
track(album, dsk, posn, song)
my answer is incorrect as i ran the query.
select a.song, count(a.song) from track a, track b
where a.song = b.song
a.album != b.album
group by a.song
having count(a.song) > 2
thanks in advance! :D

I realize this answer may be late but for future reference to anyone taking on this tutorial the answer is as such
SELECT track.song, count(album.title)
FROM album INNER JOIN track ON (album.asin = track.album)
GROUP BY track.song
HAVING count(DISTINCT album.title) > 2
Some things that my help you in your quest for this query is that what to group by is usually specified by the word each. As per the tip presented in the previous answers you want to select by distinct albums, SINCE it mentioned in the database description that album titles would be repeated when the two tables are joined

Your original answer is very close, with the GROUP BY and HAVING clause. What is wrong, is just that you don't need to join the track table against itself.
SELECT song, count(*)
FROM track
GROUP BY song
HAVING count(*) > 2
Another answer here uses COUNT(DISTNCT album), which is necessary only if a song can appear on an album more than once.

If they support nested querys, you can:
Select song, count(*)
from(
select a.song
from track a
group by a.song, a.album
having count(*) > 1
)
group by song
or(best way to write it)if they support this syntax:
select a.song, count(distinct a.album)
from track a
group by a.song
having count(distinct a.album) > 1

Related

Oracle SQL Return Count of Primary key from 2 different columns in the same table

Tables
ARMASTER = Customer Information
ORDERHEAD = Sales order information (Ship to, bill to)
Hey everyone! I'm still quite new to SQL and I do belive I'm picking it up fairly quick. I have been racking my brain on this for a few hours now and have asked around the office and nobody seems to have a solution.
I'm trying to identify how many times a customer account has been used as a SHIP TO location & a BILL TO location.
SELECT ARMASTER.CUSTOMER,
ARMASTER.DIVISION,
ARMASTER.STATUS,
ARMASTER.CUHEAD AS "MASTER",
COUNT (ORDERHEAD.BILLTO) AS "COUNT_BILL",
COUNT (ORDERHEAD.SHIPTO) AS "COUNT_SHIP"
FROM ARMASTER
LEFT OUTER JOIN ORDERHEAD
ON ARMASTER.CUSTOMER = ORDERHEAD.BILLTO
LEFT OUTER JOIN ORDERHEAD
ON ARMASTER.CUSTOMER = ORDERHEAD.SHIPTO
GROUP BY ARMASTER.CUSTOMER,
ARMASTER.DIVISION,
ARMASTER.STATUS,
ARMASTER.CUHEAD
And I'm not even remotley getting what I should be getting. However, when I remove one of my joins the count is exactly what it should be for either 1 or the other of them.
Any guidance would be muchly appreciated! Thank you!
I think it can also work
SELECT CUSTOMER,
DIVISION,
STATUS,
CUHEAD AS "MASTER",
(SELECT COUNT(1) FROM ORDERHEAD WHERE SHIPTO = ARMASTER.CUSTOMER ) AS "COUNT_BILL",
(SELECT COUNT(1) FROM ORDERHEAD WHERE BILLTO = ARMASTER.CUSTOMER ) AS "COUNT_SHIP"
FROM ARMASTER

Composer with same title but different Piece

There are two tables to be used in this question they are
Piece(PNo, CNo, Title, Tune, Opus).
Composer(CNo, Last, First, Born, Died)
I have to List the composer’s first and last names, the titles of these music pieces along with the number of times the composer did that with the music piece title.
I am using Microsoft access
I have tried
SELECT PIECE.TITLE,COMPOSER.FIRST, COMPOSER.LAST, COUNT(*)
FROM PIECE, COMPOSER
GROUP BY PIECE.TITLE
HAVING COUNT(*) > 1
Help with this would be very much appreciated.
You need a join condition between the tables:
SELECT PIECE.TITLE, COMPOSER.FIRST, COMPOSER.LAST, COUNT(*)
FROM PIECE INNER JOIN
COMPOSER
PIECE.CNO = COMPOSER.CNO
GROUP BY PIECE.TITLE, COMPOSER.FIRST, COMPOSER.LAST
HAVING COUNT(*) > 1 ;

Grouping by titles that are the same with the same (and then different) composers

I have two database tables,
PIECE (PNo, CNo, Title, Tune, Opus)
and
COMPOSER (CNO, LAST, FIRST, BORN, DIED)
are the ones I'm using for this query.
I need to Select Titles that are the same and with the same Composer. I need to list the titles and the number of versions of each. The next question requires the same listing if the Composers are different.
I tried:
SELECT TITLE, COUNT(*)
FROM PIECE, COMPOSER
WHERE PIECE.CNo = COMPOSER.CNo
GROUP BY TITLE
HAVING COUNT(*) > 1
ORDER BY COUNT(*);
Something is wrong with that query though. I am using SQLPLUS. Any help is appreciated.
The query for the question before it was to answer this:
"Different music pieces (with different PNo) may have the exact same title, list the titles of these music pieces. List these music titles, along with the number of versions (of music pieces) there are sharing the same title."
I used:
SELECT TITLE, COUNT(*)
FROM PIECE
GROUP BY TITLE
HAVING COUNT(*) > 1
ORDER BY COUNT(*);
Try this:
SELECT TITLE, COUNT(*)
FROM PIECE
GROUP BY TITLE
HAVING COUNT(*) > 1
MINUS
SELECT TITLE, count(*)
FROM PIECE P2
JOIN COMPOSER C2 ON P2.CNO = C2.CNO
GROUP BY TITLE, C2.CNO
HAVING COUNT(*) > 1
We find all titles that occur more then once then subtract the titles that have the same composer for all title versions. If you want more data then just the title, join back to the composers table to get more details for that title. We could also consider windowing functions in Oracle.
try replacing your query like this:
SELECT TITLE, COUNT(*) as Count
FROM PIECE, COMPOSER
WHERE PIECE.CNo = COMPOSER.CNo
GROUP BY TITLE
HAVING COUNT(*) > 1
ORDER BY count;

How do you explicitly show rows which have count(*) equal to 0

The query I'm running in DB2
select yrb_customer.name,
yrb_customer.city,
CASE count(*) WHEN 0 THEN 0 ELSE count(*) END as #UniClubs
from yrb_member, yrb_customer
where yrb_member.cid = yrb_customer.cid and yrb_member.club like '%Club%'
group by yrb_customer.name, yrb_customer.city order by count(*)
Shows me people which are part of clubs which has the word 'Club' in it, and it shows how many such clubs they are part of (#UniClubs) along with their name and City. However for students who are not part of such a club, I would still like for them to show up but just have 0 instead of them being hidden which is what's happening right now. I cannot get this functionality with count(*). Can somebody shed some light? I can explain further if the above is not clear enough.
I'm not familiar with DB2 so I'm taking a stab in the dark, but try this:
select yrb_customer.name,
yrb_customer.city,
CASE WHEN yrb_member.club like '%Club% THEN count(*) ELSE 0 END as #UniClubs
from yrb_member, yrb_customer
where yrb_member.cid = yrb_customer.cid
group by yrb_customer.name, yrb_customer.city order by count(*)
Basically you don't want to filter for %Club% in your WHERE clause because you want ALL rows to come back.
You're going to want a LEFT JOIN:
SELECT yrb_customer.name, yrb_customer.city,
COUNT(yrb_member.club) as clubCount
FROM yrb_customer
LEFT JOIN yrb_member
ON yrb_member.cid = yrb_customer.cid
AND yrb_member.club LIKE '%Club%
GROUP BY yrb_customer.name, yrb_customer.city
ORDER BY clubCount
Also, if the tuple (yrb_customer.name, yrb_customer.city) is unique (or is supposed to be - are you counting all students with the same name as the same person?), you might get better performance out of the following:
SELECT yrb_customer.name, yrb_customer.city,
COALESCE(club.count, 0)
FROM yrb_customer
LEFT JOIN (SELECT cid, COUNT(*) as count
FROM yrb_member
WHERE club LIKE '%Club%
GROUP BY cid) club
ON club.cid = yrb_customer.cid
ORDER BY club.count
The reason that your original results were being hidden was because in your original query, you have an implicit inner join, which of course requires matching rows. The implicit-join syntax (comma-separated FROM clause) is great for inner (regular) joins, but is terrible for left-joins, which is what you really needed. The use of the implicit-join syntax (and certain types of related filtering in the WHERE clause) is considered deprecated.

SQL Server Join with Latest 2 Entries

I know the title of the post is bad but hear me out. A question like this arose the other day at work, and while I found a way around it, the problem still haunts me.
Lets assume Stackoverflow has only 3 tables.
Users ( username )
Comments ( comment, creationdate )
UsersCommentsJoin , this is the join table between the first 2 tables.
Now lets say I want to make a query that would return the all the users with the last 2 most recent comments. So the result set would look like this.
|username| most recent comment | second most recent comment|
How on earth do I go about creating that query ? I solved this problem earlier by simply only returning the most recent comment and not even trying to get the second one, and boy, let me tell you it seemed a WHOLE lot more involved than when I thought with subselects, TOP and other weird DB acrobatics.
Bonus Round Why do some queries which seem easy logically, turn out to be monster queries, at least from my rookie perspective ?
EDIT: I was using an MS SQL server.
You can use a crosstab query pivoting on ROW_NUMBER
WITH UC
AS (SELECT UCJ.userId,
C.comment,
ROW_NUMBER() OVER (PARTITION BY userId
ORDER BY creationdate DESC) RN
FROM UsersCommentsJoin UCJ
JOIN Comments C
ON C.commentId = U.commentId)
SELECT username,
MAX(CASE
WHEN RN = 1 THEN comment
END) AS MostRecent,
MAX(CASE
WHEN RN = 2 THEN comment
END) AS SecondMostRecent
FROM Users U
JOIN UC
ON UC.userId = U.userId
WHERE UC.RN <= 2
GROUP BY UC.userId