I would like to pull up a catalog of games, but I also want to know if a game is in a SPECIFIC member's (current member in session) list of games already. This information is stored in a table called gameslist, which is a joiner table that joines members and games gameslists(id,memberid,gameid,rank)
SELECT DISTINCT *, gameslists.memberid
FROM games
INNER JOIN platforms ON games.platformid = platforms.id
INNER JOIN titles ON games.titleid = titles.id
INNER JOIN genres ON games.genreid = genres.id
LEFT OUTER JOIN gameslists ON games.id = gameslists.gameid
WHERE platforms.id = 1
ORDER BY games.releasedate DESC
LIMIT 8
PROBLEM if a game is in the list of two members, it shows up twice, if it's in
three lists, shows up three times, etc... the result is that I can tell if the game is in a current user's list, but the catalog display screws up by showing the same game twice (since it was found twice in gameslists)
http://i82.photobucket.com/albums/j277/melhusseini/Capture2.png
How can I fix this?
EDIT: The primary display criteria for the query should be determined by the catalog parameters (genre, release, date, etc...) not if the game is already in a member's list or not... the purpose of that part is to display an add/remove button based on that status
In your outer join condition put the memberid of the specific member of interest.
LEFT OUTER JOIN gameslists ON
games.id = gameslists.gameid and gameslists.memberid = 1
You can then test gameslists.memberid if it is null then the game was not in their list.
e.g.
case when gameslists.memberid is null then 0 else 1 end as InMembersList
Related
I have a table that maps User and Feature. Basically what features are enabled for each user. The table is |userId|featureId| with one(user) to many(feature) relationship.
I would like to create a query that takes a list of userIds and returns the list of userIds that are missing a specific feature.
Meaning I need to make sure that every id has a specific featureId.
userId featureId
1 A
1 B
2 A
3 C
4 D
3 A
So in this example, I'll get the list of ids (1, 2, 3, 4) and a featureId A and the query will return one row with userId 4 since it's the only userId with the feature A enabled.
To find a list of users that don't have feature X I would left join to the list of users that has that feature and return the ones not there. Like this:
SELECT *
FROM table_you_did_not_name as base
LEFT JOIN (
SELECT DISTINCT userID
FROM table_you_did_not_name
WHERE feature = 'X'
) as sub ON base.userID = sub.userID
WHERE sub.userID is null
I think I may have answered a different question: this doesn't address your data; but I'm unsure how you determine it is user 4 you want returned. as each user is missing some of the features the others have. Perhaps we just need to add a where clause below for the specific feature(A) in your example?
Think of data in terms of sets
You need
a set of data for all users (User or something)
a set of data for all features (feature)
and what features a user has (User_Feature)
Then you need to
Generate a set of every feature to every users (cross join)
Identify which of those the user has identified. (left join in user_feature)
and then only keep those where no feature has been identified (where no record in user_feature)
One method: This basically says return the features for each user that exist in a feature list, but have not been associated to a user.
SELECT U.userID, F.FeatureID as FeatureIDMissing
FROM USER U
CROSS JOIN FEATURE F
LEFT JOIN UserFeature UF
on U.UserID = UF.UserID
and F.FeatureID = UF.FeatureID
WHERE UF.UserID is null
-- and F.FeatureID = 'A' --maybe add this?
Alternate method: (combine two steps (2,3) by simply excluding those features which already exist for the user.
In english this says, return all the features for each user for which a user has not been associated
SELECT U.userID, F.FeatureID as FeatureIDMissing
FROM USER U
CROSS JOIN FEATURE F
WHERE not exists (SELECT *
FROM userFeature UF
WHERE U.UserID = UF.UserID
and F.FeatureID = UF.FeatureID)
--and F.FeatureID = 'A' --maybe add this?
Either answer should return the same results. It's a matter of preference database and performance .. Look at the execution plans to help decide which is best for you and your data.
Now maybe you mean you give a list of userID's you want to generate a unique set of features for all those users, and then return users w/o those features. If so instead of a cross join to feature you just need to use (Select distinct FeatureID from userFeatures where UserID IN ('yourListHere') this will generate a unique set of features for those users and identify which users are missing certain features shared with that set of users.
So...
SELECT U.userID, F.FeatureID as FeatureIDMissing
FROM USER U
CROSS JOIN (SELECT distinct FeatureID
FROM userFeatures
WHERE UserID IN ('yourListHere')F
LEFT JOIN UserFeature UF
on U.UserID = UF.UserID
and F.FeatureID = UF.FeatureID
WHERE UF.UserID is null
-- and F.FeatureID = 'A' --maybe add this?
as an example.
Hello guys this my first Q in stackoverflow so i'll be clear with you i'm very new to php so take it easy on me .
right so what am trying to do is i have 5 tables where's the relation have already been set
and i'm trying to show the related categorys and platforms using the game id note that the category has a table on it own and so as the platform then there's two other tables which have the game id and the cat id together and same as for the platform and the game and the field i have in the games table are:
id-->for the game id
name-->for the name of the game
details and image.
and in the game_cat:
g_id and cat_id
then thers the table for the category which has the name and id
and the same for the platform . these are my tables which i'm trying to select from
enter image description here
and my sql is:
SELECT games.*,
game_cat.*,
category.*
FROM games,
game_cat,
category
WHERE games.id='game_cat.g_id'
AND game_cat.g_id='game_cat.cat_id'
AND game_cat.cat_id='category.id'
but it doesn't work on phpmyadmin sql so I've done some research and there's something called join in sql which i'm not familiar with.
any help is appreciated.
Don't use single quotes for column name (when need use eventually backtics)
Use inner join if you have alway columns match (otherwise you left join ) and you can use alias for a compact query
(i have added also the last two tables ...hope the related columns name are right)
SELECT g.*,gc.*,c.* , gp.*, p.*
FROM games g
INNER JOIN game_cat gc on g.id = gc.g_id
INNER JOIN category c on gc.cat_id=c.id
INNER JOIN game_platform gp on g.id = gp.g_id
INNER JOIN platform p on gp.paltform_id=p.id
You need to JOIN between the tables based on the foreign-key relationship between them (if you don't know what this is, go read up on it!). Something like this (I don't know what columns represent the foreign keys, so making this up):
SELECT games.*,
game_cat.*,
category.*
FROM games g
INNER JOIN game_cat gc on (g.game_id = gc.g_id)
INNER JOIN category c on (gc.cat_id = c.cat_id)
WHERE games.id='game_cat.g_id'
AND game_cat.g_id='game_cat.cat_id'
AND game_cat.cat_id='category.id';
This looks like a standard implementation of a many-to-many relationship between games and category - would that be correct?
I have 4 tables which need to be joined. They are:
Contractors
Crews
Skill_type
Location
I also need to be able to count the number of contractors in each crew.
I have created some SQL (MySql) which does the job nicely:
Select contractors.crew_id as contractors_crew_id,
auburntree.crews.crew_name, count(*) as members, skill_type.skill,
location.location_name
FROM contractors
JOIN auburntree.crews on contractors.crew_id=crews.id
JOIN skill_type on skill_type.skill_id = crews.skill_id
JOIN location on location.id = crews.location_id
GROUP BY contractors.crew_id ;
The contractors table contains a foreign key reference to which crew they are assigned to. Hence the column "contractors_crew_id"
I get a nice result, as you can see in this screen capture image:
https://drive.google.com/file/d/0B5elaUk7GlRoS0JWblE3ZzFXY0E/view?usp=sharing
Problem Defined:
I need to define an empty crew first before I add contractors/members. I will give it a name, a skill and a location. I might define an empty crew several days in advance. Currently an empty crew does not show up in my results.
I want to see:
contractors_crew_id = Null, crew_name, skill_type, Location, members 0
I have tried using RIGHT OUTER JOIN on my tables and I still do not see empty crew. LEFT OUTER JOIN does not work either.
contractors_crew_id will be Null at that point, as no contractors have been assigned yet.
I Hope this makes, sense - sorry it is a bit long and complicated. I have tried really hard to explain in.
Many Thanks !!
Because you are actually focussing on information about crews, and not contractors, I would suggest to start by querying the crews table (in the FROM part of your query) and then join the other tables.
Using a LEFT JOIN on the contractors table should then give you the desired result. Since crews is now the "left" table in the query, the result will include all rows from crews, even when there is no corresponding contractor. This answer explains it very well.
This query works for me on test tables based on your examples:
SELECT
contractors.crew,
crews.crew,
COUNT(contractors.id) as members,
skills.skill,
locations.location
FROM crews
JOIN skills ON crews.skill = skills.id
JOIN locations ON crews.location = locations.id
LEFT JOIN contractors ON contractors.crew = crews.id
GROUP BY contractors.crew, crews.id;
To see for yourself, try this SQL Fiddle.
Try this, instead:
Select contractors.crew_id as contractors_crew_id, crews.crew_name, count(*) as members, skill_type.skill, location.location_name
FROM crews
LEFT OUTER JOIN contractors on contractors.crew_id=crews.id
LEFT OUTER JOIN skill_type on skill_type.skill_id = crews.skill_id
LEFT OUTER JOIN location on location.id = crews.location_id
GROUP BY contractors.crew_id ;
That should pull all crews, regardless of whether or not they have contractors assigned. The way you wrote your original query starts by looking at your contractors and then pulling in any crews they might be assigned to. Crews is clearly your focal table here, so you should be joining the rest of your tables to it, rather than to the contractors table.
Trying to get a tricky mysql select statement working - and I need some help to cool off my burning noggin...and I have a feeling one of you MYSQL heroes out there will look at this and reel it off.
Goal: List a given user's songs NOT in a given category.
Three tables: :
table 1: song, many fields with assigned UserID, and unique SongID
table 2: category, 3+ fields, with assigned UserID and unique CatID
table 3: linker, one-to-many for listing songs in one or more categories. 3 fields, unique id (index), SongID, CatID
The following gets me close - but does not list a user's songs that aren't assigned to any other category at all OR are a already assigned to a another category (I think thanks to !=).
SELECT DISTINCT song.SongName, song.UserID, song.SongID FROM song
JOIN linker ON song.SongID = linker.SongID
WHERE linker.CatID != 155 AND song.UserID =2
Then, I tried this,
SELECT DISTINCT song.SongName, song.UserID, song.SongID FROM song
LEFT JOIN linker ON song.SongID = linker.SongID
WHERE (linker.SongID IS NULL OR linker.CatID != 155) AND song.UserID =2
Closer but not working (still thanks to != including songs already assigned).
I was thinking I can get away without invoking table 2, since it merely adds and defines categories for a given user. Alternatively, I'm thinking of getting all the user's songs, and then unsetting array values with a given CatID - but this doesn't seem like it should be necessary? I feel like I'm missing something simple? Table structure is not sacred at this point if it absolutely needs to change. Thanks to any who share their thoughts.
Try this (I am used to MSSQL so if my syntax is off, appologies in advance):
SELECT s.SongName, s.UserID, s.SongID
FROM song s
LEFT JOIN linker l on s.SongID = l.SongID AND l.CatID = 155
WHERE s.UserID = 2
AND l.ID is null
SELECT DISTINCT song.SongName, song.UserID, song.SongID
FROM song
LEFT JOIN linker
ON song.SongID = linker.SongID
and linker.CatID != 155
AND song.UserID = 2
I have two tables: projects and user_licenses.
I'd like to grab the entire list of projects from the database, as well as the user's current license state. The licenses table has a user ID field which I check against a $_SESSION variable for the value. The thing is, they might not have a license, or a non-logged in visitor may want to see the projects list. My question is this: How can I get the data from the left table always display, but only grab data for that row from the right table when certain conditions are met?
The query I have at the moment is this:
SELECT Projects.*,
UserLicenses.*
FROM Projects
LEFT JOIN UserLicenses ON Projects.id = UserLicenses.project_id
WHERE UserLicenses.user_id = 12
ORDER BY name ASC
Add any extra conditions to the on clause of the left join. They will only affect the joined table.
SELECT Projects.*,
UserLicenses.*
FROM Projects
LEFT JOIN UserLicenses
ON Projects.id = UserLicenses.project_id
and UserLicenses.user_id = 12
and UserLicences.Question = '6*7'
and UserLicences.Answer = 42
ORDER BY name ASC
This will return projects without matching licenses.
Move the UserLicenses condition away from WHERE, and up to the JOIN condition. By having it in the WHERE part, you will never see those "left" rows because they are filtered away.
You can also probably use WHERE (UserLicenses.user_id = 12 OR UserLicenses.user_id IS NULL)
Don't do that. Just move it to the join condition like this:
LEFT JOIN UserLicenses ON
(Projects.id = UserLicenses.project_id AND UserLicenses.user_id = 12)
You can use LEFT JOIN
If its conditions match then values show otherwise null value shows.