User in multiple categories MySQL - php

I have been searching for a good day for a way to search for a user that is in each category AND the next not OR.
user_id
-------
1
2
3
4
table_user_categories
user_id|category_id
-------------
1 |1
1 |2
2 |1
2 |3
So I want to ask MySQL, who is in category 1 AND 2. I have tried the IN(1,2) approach but this, as I understand it is OR not AND giving me the results of user_id 1 and 2 not just 1.
Its also quite important for this to be extensible as it can be as there are about 15 categories, so i'll need to add more into the query the more the user selects in my interface.
Huge apologies for anything I've missed in my post here, always easier to think of these things as opposed to asking.
I just dug out an old version of what I was trying - was just going to post this to compare...
SELECT u.user_id, COUNT(*) AS category_count
FROM table_user_categories AS u
WHERE u.category_id IN (1,2)
GROUP BY u.user_id
HAVING category_count = 2;

If you want to find all the user_ids that have both (or, generally, all) the given categories, you can use aggregation with filtering:
select user_id
from table_user_categories
where category_id in (1, 2)
group by user_id
having count(distinct category_id) = 2;
The having in above clause make sure that only user_id with both category_id 1 and 2 are returned.

Related

MySQL Duplicating Row Results in Table When Searching Across Multiple Tables

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...

Count how many times a value appears in sql query using php

I have created a database and website that will be used by football managers to select their team etc. Once a match has been completed events will be stored in the match_players table. Such events are Goal, Yellow Card, Red Card etc. I have no problem getting this information into php from SQL db.
I need to add up how many times a Goal appears (a '1' is placed in the SQL table) and for what team so that a final score can be displayed. So, for example, if Team A has 1 goal and Team B has 2 then I need to display that. I am trying to count the amount of times that a Goal is registered in the table. Any help will be greatly appreciated.
You can use MYSQL SUM
select SUM(Goal) from match_players where Team="A"
Or you can get the same for all teams by
select Team,SUM(Goal) from match_players group by Team
Why don't you demand this sum to SQL directly?
SELECT SUM(goals)
FROM match_table
WHERE team = 'Barcellona'
This should be much faster also than elaborate all data at "php-level"
If you want this detail for all teams
SELECT team,SUM(goals)
FROM match_table
GROUP BY team
Well if you store a 1 each time a goal is scored, your table looks like this:
TeamID goal
1 1
2 1
1 1
3 1
2 1
2 1
1 1
So you just want a count of how many times a team appears in that table:
select TeamID, count(*) from table group by TeamID
Will give you
TeamID | count(*)
1 | 3
2 | 3
3 | 1

Using a MySQL query with PHP

I am creating a social network in which you can follow someone or be friends with them. The data you are able to see depends on the type of relationship you have with a user. Right now I have two tables to work with. Posts and Relationships.
Posts:
| user_id | post_id | story |
-----------------------------
| 1 | 1 | text. |
-----------------------------
Relationships:
| rel_id | user_1 | user_2| status |
--------------------------------------
| 1 | 1 | 2 | 3 |
--------------------------------------
I also have a users table but I don't think that is important here. SO, basically I want to select all of the posts from users that I am friends with or following. User_2 is always the recipient of the relationship. The numbers 1, 2 and 3 represent the "status" of the relationship. 1 being you are following the recipient, 3 being you are friends, and 4 being you are following the recipient (the only difference is that you also have a pending friend request). I set up a SELECT QUERY but it is not working right.
$query=" SELECT * FROM posts LEFT JOIN relationships ON (posts.user_id=
relationships.user_2 AND relationships.user_1 = $user_id AND relationships.status = 4
OR 3 OR 1)";
It selects all the posts ever, twice. Why is that? I want it to only select the posts where the user posting the post is in a relationship with me, with a status of 1, 3, or 4. What might I be doing wrong? What are other ways to do this?
Thanks in advance!
That's not how OR works. Perhaps you should try IN.
... relationships.status IN (4, 3, 1) ...
As for the duplication, use DISTINCT.
Your OR in the WHERE clause condition is not in the correct syntax. try something like this:
SELECT *
FROM posts a
LEFT JOIN relationships b
ON a.user_id = b.user_2
WHERE b.user_1 = $user_id AND
b.status IN (1,3,4)
I suggest that you use PDO or MYSQLi extensions.
In PDO, it could look like this:
<?php
$stmt = $dbh->prepare("SELECT *
FROM posts a
LEFT JOIN relationships b
ON a.user_id = b.user_2
WHERE b.user_1 = ? AND
b.status IN (1,3,4)");
$stmt->bindParam(1, $user_id);
$stmt->execute();
?>
Remember to always filter your inputs especially it is used querying your database.

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 count does not return 0 if no record found

Although I researched on this topic and came across a few solutions like using JOIN LEFT or subqueries, I am still unable to get the result I want as I am not strong in mySQL. I am more of a web designer trying to use simple php to my website better for a school project.
I am trying to create a web application something similar to a blog. I wanted to count how many comments are there for a post and display the number for my users to see, but if there is no comment for that row, my query will return nothing instead of 0.
This is my query below:
SELECT post.post_id, COUNT(comment)
FROM `comment`, post
WHERE `comment`.post_id = post.post_id
GROUP BY post.post_id
The result:
Record | post_id | COUNT(comment)
1 | 12 | 2
2 | 13 | 1
3 | 15 | 1
4 | 16 | 1
As you can see, post_id 14 has no comments, thus my query returns nothing. What must I do to make my result looks like this?
Record | post_id | COUNT(comment)
1 | 12 | 2
2 | 13 | 1
3 | 14 | 0
4 | 15 | 1
5 | 16 | 1
Also, it would be nice of you guys to give me references or links to understand the concept behind the solution as I want to learn more about php :)
So Actually when you do that (which is what you do, reformulated for the JOIN):
SELECT post.post_id, COUNT(comment)
FROM `comment`
INNER JOIN post ON `comment`.post_id = post.post_id
GROUP BY post.post_id;
You gather only post rows having at least one reference in comment.
If you alter the JOIN type to a LEFT join, this way:
SELECT post.post_id, COUNT(comment)
FROM `comment`
LEFT JOIN post ON `comment`.post_id = post.post_id
GROUP BY post.post_id;
Then the rows from post are all there, and NULL values are inserted for columns of comments if no comments related to this row exists (that's a left join). So if comment is a column from table comment it will be there for each rows of post table, but with a NULL value, after the group by on the post_id column the subset of comments related to this post contains only 1 NULL value, the count should return 0.
select count(NULL);
returns 0.
Now you could use a subquery but that's a really bad idea, subqueries are usually done instead of LEFT JOINS, usually it's a mistake, sometimes it's not, but it's really often a mistake. When you do a left join indexes are used to compare the key values of the 2 tables (the ON clause) and build one final 'temporary' result of rows, mixing values from both tables (and then, or maybe in the same time, the filters from other parts of your queries are applied). When you use a subquery, for each row of the first table a new query is run to get results from the second table (not always, but it's another problem), the cost is reeeaaally bigger for the database engine.
Query the post table and do a subquery for the count on the comments query.
SELECT post.post_id, (SELECT COUNT(comment) FROM `comment` WHERE `comment`.post_id = post.post_id) as comments FROM post
This may get extremely slow with lots or rows so add a limit with a pager when you get to that point.

Categories