I have such tables:
How to, with just SQL select all the comments, for tracks with the genre of 'xxx'?
Well you could do that in two way first:
SELECT commmentId, content, date
FROM comments
WHERE trackId IN (SELECT trackId
FROM tracks
WHERE genreId = xxx);
Or:
SELECT c.commentId, c.content, c.date, t.genreId
FROM comments c
INNER JOIN tracks t
ON c.trackId = t.trackId
WHERE t.genreId = xxx;
And I didn't understand very well if you want to select comments by genreId or by genre name (if you want to do that by name than you should extend this a little bit) but this is the logic you should fallow...
Related
I have the following SQL Database structure:
Users are the registered users. Maps are like circuits or race tracks. When a user is driving a time a new time record will be created including the userId, mapId and the time needed to finish the racetrack.
I wish to create a view where all the users personal bests on all maps are listed.
I tried creating the view like this:
CREATE VIEW map_pb AS
SELECT MID, UID, TID
FROM times
WHERE score IN (SELECT MIN(score) FROM times)
ORDER BY registered
This does not lead to the wished result.
Thank you for your help!
I hope that you have 'times' table created as the above diagram and 'score' column in the table that you use to measure the best record.
(MIN(score) is the best record).
You can simply create a view to have the personal best records using sub-queries like this.
CREATE VIEW map_pb AS
SELECT a.MID, a.UID, a.TID
FROM times a
INNER JOIN (
SELECT TID, UID, MIN(score) score
FROM times
GROUP BY UID
) b ON a.UID = b.UID AND a.score= b.score
-- if you have 'registered' column in the 'times' table to order the result
ORDER BY registered
I hope this may work.
You probably need to use a query that will first return the minimum score for each user on each map. Something like this:
SELECT UID,
MID,
MIN(score) AS best_time
FROM times
GROUP BY UID, MID
Note: I used MIN(score) as this is what is shown in your example query, but perhaps it should be MIN(time) instead?
Then just use the subquery JOINed to your other tables to get the output:
SELECT *
FROM (
SELECT UID,
MID,
MIN(score) AS best_time
FROM times
GROUP BY UID, MID
) a
INNER JOIN users u ON u.UID = a.UID
INNER JOIN maps m ON m.MID = a.MID
Of course, replace SELECT * with the columns you actually want.
Note: code untested but does give an idea as to a solution.
Start with a subquery to determine each user's minimum score on each map
SELECT UID, TID, MIN(time) time
FROM times
GROUP BY UID, TID
Then join that subquery into a main query.
SELECT times.UID, times.TID,
mintimes.time
FROM times
JOIN (
) mintimes ON times.TID = mintimes.TID
AND times.UID = mintimes.UID
AND times.time = mintimes.time
JOIN maps ON times.MID = maps.MID
JOIN users ON times.UID = users.UID
This query pattern uses a GROUP BY function to find the outlying (MIN in this case) value for each combination. It then uses that subquery to find the detail record for each outlying value.
I have two MySQL Tables. In this abstract example I will use these to explain my issue:
Persons(person_id, name);
Competition(competition_id, first, second, third);
First, second and third refer to person_id and I want to get the names in this order. If I use
SELECT name
FROM Persons
, Competition
WHERE person_id = first
OR person_id second
OR person_id = third;
the names are sorted by their table order (usually the same order like sorted by primary key). How can I order them right?
Edit:
I need to enter a competition_id and want to get a table with three name lines in the right order
I think you just need multiple joins:
SELECT c.*, p1.name, p2.name, p3.name
FROM Competition c LEFT JOIN
Persons p1
ON p1.person_id = c.first LEFT JOIN
Persons p2
ON p2.person_id = c.second LEFT JOIN
Persons p3
ON p3.person_id = c.third;
This puts the names for a given row in competition in the same row. That seems like a sensible thing to do.
EDIT:
If you want the first matching name, you can use COALESCE():
SELECT c.*, COALESCE(p1.name, p2.name, p3.name)
The solution is, a seperate table is required.
Persons(person_id, name);
Mapper(pk_mapper_id, fk_competition_id, fk_person_id, rang)
Competition(competition_id);
Here I can order by rang.
Using one table, I am trying to run a query that matches a userid to a course.
The goal is to see the courses that the userid is not in,
So far I can display the usid's that are not in all the courses, but now I want to display the courses that they are not in
SELECT usid, course, COUNT(*)
FROM COURSE_COMMENTS
WHERE course in (1,2,3,4,5,6,7,8)
GROUP BY usid
HAVING COUNT(*) < 8
Also, neither usid, nor course are primary so they can show up multiple times.
any ideas?
If you have a courses table, you can do something like this:
select u.usid, c.course
from (select distinct course from courses where course in (1,2,3,4,5,6,7,8)) c cross join
(select distinct usid from course_comments) u left join
course_comments cc
on cc.course = c.course and cc.usid = u.usid
where cc.course is null;
i have 3 tables audios,videos,images
they all have dateadded and uid
i want to select all (select *) from these tables where uid=1 and order all the results by dateadded, very confused what the query would be like?
if tha tables hold the same information you can use union, e.g.:
select name, date_added
from(
select video_name as name,date_added, uid
from videos
union all
select audio_name as name,date_added, uid
from audios
union all
select image_name as name,date_added, uid
from images
) u
where uid = 1
order by date_added
If the 3 table has 1 same field like groupID or something like that you can use left join or inner join depending on what output would you want to have.
using left join:
select * from videos v left join audios a on v.groupID = a.groupID
left join images i on v.groupID = i.groupID
note:
just change the word "left" to "inner" if you want to use the other type of join.
It doesn't have to have the same field name "groupID". But it is necessary to have a common functionality or it represents something which is related to each other.
Links:
here are some links that may help you
http://www.w3schools.com/sql/sql_join.asp
http://www.codinghorror.com/blog/2007/10/a-visual-explanation-of-sql-joins.html
enjoy coding..:)
I have three tables as follows:
Contact, Custom_Field, Custom_Field_Value.
Each contact can have one Custom_Field_Value record for each Custom_Field. So there is a 1:many relationship between Contact and Custom_Field_Value but it isn't quite that simple.
Everything works fine - except for one edge case where I need to select Contacts that have a particular Custom_Field not set (i.e. no corresponding Custom_Field_Value record exists linking to the Contact and the Custom_Field). This is surprisingly difficult. I can't just use the normal "left join and look for NULL" approach because they may have a different custom field - but not the one I am looking for. I need to say "Where Custom_Field_ID=10" but I can't because the thing I'm looking for does not exist.
My line of thinking was heading in this direction, but I'm just tying myself in knots now:
Select ID, First_Name, Last_Name, CF_ID From
(
(Select Contact.ID, First_Name, Last_Name, Custom_Field_Value.ID as CFV_ID, Custom_Field_Value.CustomFieldID as CF_ID, TextValue
From Contact Inner Join Custom_Field_Value on Contact.ID = Custom_Field_Value.ContactID
Where Custom_Field_Value.CustomFieldID=23 Order By Contact.ID)
UNION
(Select Contact.ID, First_Name, Last_Name, Custom_Field_Value.ID as CFV_ID, Custom_Field_Value.CustomFieldID as CF_ID, TextValue
From Contact LEFT Join Custom_Field_Value on Contact.ID = Custom_Field_Value.ContactID
Order by Contact.ID)
) as A
Group BY `ID`, CF_ID ASC
I don't want to create blank records for every possibility because there could be millions of records and every time someone adds a custom field, the database would have to insert millions of corresponding blank records.
It would be really great if we could do this:
Select ID From thingy
EXCLUDE
Select * From thingy Where x = true
This is a nasty one, but I know there'll be someone out there who will love it:)
Okay, I think I have a better understanding now. I was trying to pull it off without a subquery, but I'm not sure if I can.
Can you try
Select Contact.ID, First_Name, Last_Name, Custom_Field_Value.ID as CFV_ID, Custom_Field_Value.CustomFieldID as CF_ID, TextValue
From Contact LEFT Join Custom_Field_Value on Contact.ID = Custom_Field_Value.ContactID
WHERE NOT EXISTS(SELECT * FROM Custom_Field_Value cfv2 WHERE cfv2.ContactID = Contact.ID AND cfv2.CustomFieldID=23)
Order by Contact.ID
The NOT EXISTS subquery should only return rows where the contact has no value for that field.
This is the crazy SQL I ended up with - created dynamically by users. Just publishing it in case its any use to anyone. (Any tips on optimisation are very welcome!):
The problem is that not only do I have to select missing dynamic records, I also have to join together Left Join queries into one result.
SELECT * FROM (
(SELECT * FROM Contact
WHERE (...some dynamic stuff...)
)
UNION All
(SELECT Contact.* FROM Contact Inner Join Contact_Campaign_Link ON Contact.ID=Contact_Campaign_Link.Contact_ID
WHERE ((Campaign_ID=31))
)
UNION All
(SELECT * FROM Contact
WHERE (CustomerID=3)
AND (NOT EXISTS
(SELECT * FROM Custom_Field_Value cfv2
WHERE (cfv2.ContactID = Contact.ID)
AND (cfv2.CustomFieldID =27) )) ORDER BY Contact.ID)
) As tbl
GROUP BY tbl.ID HAVING COUNT(*)=3 Order by ID