MySQL Duplicating Row Results in Table When Searching Across Multiple Tables - php

I have three tables in a mySQL db one for users, one for colours and one for the linking of the users to the colours
Table 1 users
==============
ID | Name
--------------
1 | John
2 | Jayne
3 | Fred
Table 2 colours
==============
ID | Colour
--------------
1 | Blue
2 | Red
3 | Yellow
Table 3 link
==============
ID | Name | Colour
--------------
1 | 1 | 1
2 | 1 | 2
3 | 2 | 1
4 | 3 | 2
5 | 3 | 3
As you can see, some users have more than one favourite colour (yeah, i know, how annoying).
At the moment, I can show them in a table, with their favourite colour(s) in a column.
BUT, I want to be able to filter the table results by colour.
I can do it no problem with having a filter of just one colour, BUT the problem comes along with two colours.
If I want to see which user has selected for example Blue AND Red, I get a result of zero.
How can I get this result, without creating a search which results in each row being dedicated to a colour and then in turn showing the same user twice (one for red one for blue).
I hope this makes sense
THANKS IN ADVANCE
EDIT
An example query I have used is
SELECT * FROM users, colours, link WHERE users.id = link.name AND link.colour = colours.id
Alternatively to show for specific colour
SELECT * FROM users, colours, link WHERE users.id = link.name AND link.colour = colours.id AND link.colour = 1
But for double filter which shows duplicates
SELECT * FROM users, colours, link WHERE users.id = link.name AND link.colour = colours.id AND link.colour = 1 OR link.colour = 2

If that looks right here is the code:
SELECT Name FROM users
WHERE ID IN (SELECT DISTINCT(Name) AS Name
FROM link L
WHERE 2 IN (SELECT Colour FROM link L2 WHERE L.Name = L2.Name)
AND 1 IN (SELECT Colour FROM link L2 WHERE L.Name = L2.Name))
And now let me try to explain what L and L2 are... First sorry for my English I'll do my best to make a sense for you...
We make subquery on the same table here so we need to use alias for the table. Alias we use to give temporary name table or column which will be used only for that query.
Example for alias is when we select some column from table (Price and Quantity) and let's say we want to calculate Price * quantity and SELECT that column as total (total will be the name of that column in table which we return after we execute the query). Column name total well be give alias. we crate alias like:
SELECT Price, Quantity, (Price * Quantity) AS **total**
FROM t1...
That will return table with three column Price, Quantity, Total... if we don't use this AS total the name of that column will be Price * Quantity...
So here we use L and L2 just to know which column Name is from which part of SELECT query. If we wouldn't use alias in subquery
SELECT Colour FROM link L2 WHERE L.Name = L2.Name
we would have problem because subquery which locks like this:
SELECT Colour FROM link WHERE Name = Name
Doesn't make a a lot of sense, isn't it?
So basically we temporary rename table in this query because we need to know which column from which table we compere whit other one, in other way database will have a problem what to select...
I hope this make a sense for you. If you have any further question fill free to ask I will do my best to try to explain it to you.
I hope i didn't make it more complicated than it is...
GL!
EDIT
Hi there again, i worked something and and i figured out that your question probably have better answer than the first i give you... Hope it's not too late!
SELECT u.Name
FROM users u
INNER JOIN link L
ON u.ID = L.Name
INNER JOIN link l2
ON L.Name = L2.Name
WHERE L.Colour = 2 AND L2.Colour = 1
Look SQL Fiddle for that...

Related

Combining multiple mysql queries into one result

I'm using php my get results from a mysql table. I want to run multiple conditional statements to return a list of unique results. let's say I have a table about houses on my street and my table looks like this:
House Number | Attribute | Value
-------------------------------
23 | Colour | White
23 | Stories | 2
24 | Stories | 1
25 | Colour | Blue
Notice house number 23 appears twice How would I word a mysql query to return all houses that are white AND have two stories? in this case, it would return just one result - 23.
I hear what you're saying - why don't i just make 'colour' and 'stories' the column names. well, the reason is because in my example, a house can have two different colours: two different values for the same attribute name. A house could have two rows, one where attribute is colour and value is white, and another where attribute is also colour but the value is purple. As long as a house has a row with colour:white AND a row with stories:2 it will return positive in the query and get included in the result
Now, once solution would be to run two different queries: one query that matches white houses and returns an array, and a second query that matches houses with two stories and returns an array, then I can use php to compare the two arrays and see what entries appear in both arrays, pull them out and put them into a final array. But this involves calling two mysql queries. Is there a way of combining the queries on the mysql end?
You want a self-join:
SELECT
A.`House Number` AS House
FROM
Houses AS A
INNER JOIN Houses AS B ON A.`House Number`=B.`House Number`
WHERE
A.Attribute='Colour' AND A.Value='White'
AND B.Attribute='Stories' AND B.Value='2'
You can nest your SELECT statements like this:
SELECT DISTINCT (`House_Number`) AS `House_Number`
FROM `table`
WHERE `House_Number`
IN (
SELECT DISTINCT (`House_Number`) AS `House_Number`
FROM `table`
WHERE `Attribute` = 'Colour'
AND `Value` = 'White'
)
AND `Attribute` = 'Stories'
AND `Value` = '2';
Edit:
Not quite as pretty as using an INNER JOIN, but still effective.
To build upon the INNER JOIN method #Eugen posted while I was typing up my original response, you may consider including DISTINCT, like this:
SELECT DISTINCT(A.`House_Number`) AS `House_Number`
FROM `table` AS A
INNER JOIN `table` AS B ON A.`House_Number` = B.`House_Number`
WHERE A.Attribute = 'Colour'
AND A.Value = 'White'
AND B.Attribute = 'Stories'
AND B.Value = '2'
The reason being that in case the same attribute were to be recorded twice, say like this:
House Number | Attribute | Value
-------------------------------
23 | Colour | White
23 | Colour | White
23 | Stories | 2
24 | Stories | 1
25 | Colour | Blue
...then you would wind up with "23" being returned twice, unless you used DISTINCT
Try this
select id from table
where Attribute='Colour' and Value='White'
and id in (select id from table where Attribute='Stories' and Value='2')

Select many relational ID in one shot(MYSQL)

so we have:
table users
id name password parent_id
the first user have the id 1, and others have the parent_id 1, so I select all the users that have the parent_id == 1 - they are the childs of the user with 1, okay its all right, but now i need to select the users that have the parent_id of the selected before users with they id, if they exists of course
user with id 1
/ | \
/ | \
/ | \
users with parent_id 1
user id 2 user id 3 id user 4
| | |
| | |
| | |
and here is the same, I need to select all the users that have the parent_id 2, 3, 4 for each of those user, its is something like a pyramide(triangle) from the top to the bottom
So the question is how can i make a query that will select it in one shot, not in many queries by extracting the id and then make other query - its not good i think
do you have an idea??
Here is a question, that covers your problem:
Is it possible to query a tree structure table in MySQL in a single query, to any depth?
Query below works only for finding children and grand-children of a single user and is a product of misunderstanding the question!
You could try joining user table on itself twice.
SELECT * FROM users as up
JOIN users as u on up.id=u.parent_id
JOIN users as uc on u.id=uc.parent_id
WHERE up.id={$grandParentUserId}
Aliases: up = user's parent, u = user, us = user's child.
Definitely not a pretty solution, but it's a single request.
I see you are using CI. You can have a look at this answer. Somewhat related to your question. You can select the users with NULL parent ID first and then populate their children
https://stackoverflow.com/a/9937130/876117

MySQL: Joining two tables / Read all data from specific row in table B if specific field in table A is not empty

http://i.stack.imgur.com/ZRH9c.jpg (Please see Example Image of Database Structure)
Hi all,
I'm trying to search for words in two tables that Start with a specific Letter and I don't know how to do the proper join.
If there is NOT given a voc_id in "user_vocabulary" I want to take the word from user_vocabulary but if there is a voc_id I want to read all data from "system_vocabulary" WHERE user_vocabulary.voc_id=system.vocabulary.id .
This I use to just read one table (just for your information):
SELECT * FROM user_vocabulary WHERE word LIKE '$user_input%' ORDER BY word ASC
I've found some more or less similar posts but seem not to be able to convert those to this issue.
Any help is much appreciated.
cheers
Tom
You'll want values taken from user_vocabulary.word and system_vocabulary.word to end up in the same column in the output. You can do this with the IF function:
SELECT
uv.id,
IF(uv.voc_id = 0,uv.word,sv.word) AS WORD
FROM user_vocabulary uv
LEFT JOIN system_vocabulary sv
ON (uv.voc_id = sv.id)
HAVING word LIKE '%user_input%'
+------+-------+
| id | word |
+------+-------+
| 1 | hat |
| 2 | home |
| 3 | hello |
+------+-------+
3 rows in set (0.00 sec)
Try this
SELECT *
FROM user_vocabulary
left join system_vocabulary
on system_vocabulary.voc_id = user_vocabulary.id
WHERE user_vocabulary.word LIKE '%$user_input%' or system_vocabulary.word like '%$user_input%'
ORDER BY word ASC
EDITED
The other way
SELECT *
FROM user_vocabulary as uv
, system_vocabulary as sv
WHERE uv.word LIKE '%$user_input%'
or sv.word like '%$user_input%'
This should work according to your requirements:
SELECT user_vocabulary.id,
COALESCE(system_vocabulary.word, user_vocabulary.word) word
FROM user_vocabulary
LEFT JOIN system_vocabulary
ON system_vocabulary.id = voc_id AND voc_id <> 0

PHP MySQL Select ID from one table and information from another table

I have two tables, one table is called queuelist and the other is call info. In the queuelist table it just lists different IDs. I am trying to get the 'clientID' from that table and match it with the 'ID' in the other table that contains all of the info and display it back on the page. Here is how the tables look:
Table - queuelist
ID | clientID
-------------
1 | 589
2 | 254
3 | 486
Table - info
ID | Name | Phone
--------------------
256 | Bob | 5551231234
486 | Jack | 5551231234
589 | Jill | 5551231234
This is what they call joining tables, you should use a query like this:
SELECT i.ID, i.Name, i.Phone FROM `queuelist` AS q
LEFT JOIN `info` AS i ON (
q.clientID = i.ID
);
I'm using aliases for shorter notation in the above query (queuelist becomes q and info becomes i) and then set the join condition (the bit between the ON()) to be the clientID from the queuelist table should match the ID in the info table.
Also see http://dev.mysql.com/doc/refman/5.0/en/join.html for more details.
You need to use an inner join
select * from queuelist as ql inner join info as i on ql.clientID = i.ID
Though you might want to replace * with specific field names e.g
select ql.clientID, i.fieldname FROM....
Well, I see no difficulty in this using a JOIN.
SELECT * FROM queuelist JOIN info ON clientID = info.ID WHERE queuelist.ID = 2
"Where" would be another option.
SELECT Name, Phone FROM queuelist,info WHERE clientID = ID
Assuming you want only name and phone

Retrieving "likes" tied to users from a database

I'm new to database structure. I'm trying to create an app that allows users to like certain entries, but I want to be able to tie likes to users so that I can change the visuals before/after the like action.
I think from research that I should have an 'entries' and 'users' table and then have a 'likes' table that ties the two to each other.
The only thing I'm unsure of is, when getting and displaying the contents... how would I write the queries? If I query for all the entries I need, do I then go back and individually query each to see if it has a like tied to it for the current user? That seems like it might be a costly operation. Is there a more efficient way?
Hope that makes sense,
Thanks.
I think you have the right database design in mind. As far as queries are concerned, assume tables as such:
Users
ID | Name
1 | Bob
2 | Sally
Entries
ID | Name
1 | Red
2 | Blue
3 | Yellow
Likes
UserID | EntryID
1 | 1
1 | 2
2 | 2
2 | 3
So we can say Bob likes Red and Blue while Sally likes Blue and Yellow. So a query to retrieve all entries, plus an indicator of what Bob likes would be:
SELECT
e.ID,
e.Name,
l.UserID
FROM Entries e LEFT JOIN Likes l ON l.EntryID = e.ID
WHERE l.UserID = 1 -- Bob's User ID
ORDER BY e.Name
This would return
ID | Name | UserID
2 | Blue | 1
1 | Red | NULL
3 | Yellow | 1
The UserID column indicates if Bob likes the entry or not - a NULL is No and a value is Yes.
Assuming you have a table Entries with a column entity_id (and whatever else you store about the entity) and a second table UserLikes that contains the columns user_id and entity_id, you would do the following:
SELECT Entries.col1, Entries.col1 . . ., UserLikes.user_id
FROM Entries LEFT OUTER JOIN UserLikes ON
Entries.entity_id = UserLikes.entity_id
WHERE UserLikes.user_id = :user_id
AND Entity.col_whatever = :whatever
In this example, Entries.col1, Entries.col2 . . . is the list of columns you want to get back about the Entries. The :user_id is a parameter that contains the id of the user you're currently trying to display Entries for. And the last line is standing in for whatever limitations you want to put on the Entries are returned.
This query will give you a row for each Entry you searched for. You can check the value the returned column user_id. If it's NULL then it was not liked by the user, if it contains the user's id, it was liked by the user.
I think u can retrieve the entries and query the likes table at the same time to get if the current user likes the entry performing a stored procedure. So u can control the value of the set of data returned by the query for example returning one colum for the entry text and one boolean column to evaluates the current user likes... In this way you will at least one parameter for the stored procedure to indicate who is the current user
I hope this idea help u...

Categories