MySql Statement across different rows - php

Im trying to query a wordpress mySQL database where the values pertaining to each user is spread across different rows (only god knows why they did it that way, why didnt they just put all the user information on one row)
For example
ID USER_ID FIELD_ID VALUE
1 1 2 my name is paul smith
2 1 3 books
3 1 4 loggedin
4 1 5 state=busy
5 2 2 my name is big boy
5 2 3 pens
6 2 4 offline
7 2 5 state=idle
here you can see each row has a different meaning based on the FIELD_ID for the same user
FIELD_ID=2 contains the user name
FIELD_ID=3 contains mean what they bought
FIELD_ID=4 means logged in
FIELD_ID=5 is busy or idle
I need to make ONE query that will return all users that are LOGGED IN and STATE=IDLE and bought BOOKS (or bought some other item like pens whatever they want to search for)
so i started off with this php statement
$find="pens";
$q = "SELECT * FROM table
WHERE FIELD_ID='4' AND VALUE='loggedin'
AND FIELD_ID='5' AND VALUE='idle'
AND USER_ID IN
(SELECT USER_ID FROM table WHERE FIELD_ID ='3' AND VALUE LIKE '%$find%')
But i dont think this will work because how can
FIELD_ID = '4' AND VALUE='loggedin' AND FIELD_ID='5' AND VALUE='idle' all at the same time because they are on different rows.
Does anybody know how to make ONE mySQL statement to do it?

you could use a self join
SELECT distinct a.user_id
FROM table a
inner join table b on a.user_id = b.user_id and b.field_id = 5 and b.value='idle'
inner join table c on a.user_id = c.user_id and c.field_id = 4 and c.value = 'loggedin'
where a.field_id=3 and a.value='BOOK'

Related

CodeIgniter query to exclude a subset from results

I'm having some trouble figuring out how to write the proper query after doing a JOIN. I need to get all users in Group 1 while excluding a subset of these results.
Table users:
id name
1 John Smith
2 Joe Blow
3 Mary Jane
Table users_groups:
user_id group_id
1 1
1 3
1 4
2 1
2 4
2 5
3 1
3 6
Everyone in Group 6 will also be in Group 1, however, not everyone in Group 1 will be in Group 6. In other words, Group 6 is a sub-set of Group 1.
I need a query that will give me a list of all users who are in Group 1 (while excluding the users in Group 6). For the example above, I should get two results, John Smith and Joe Blow.
I'm using CodeIgniter v3
Here is my attempt (I removed the cache code for clarity)...
$this->db->from('users');
$this->db->select('
users.id AS `id`,
users.name AS `name`,
users_groups.group_id AS `group_id`
', FALSE);
$this->db->join('users_groups', 'users_groups.user_id = users.id', 'LEFT');
$this->db->group_by('users.email'); // remove duplication caused by JOIN
$this->db->where('users_groups.group_id = 1'); // get all users in Group 1
$this->db->where('users_groups.group_id <> 6'); // ignore all users in Group 6
return $this->db->get()->result_array();
The problem I'm having here is that I always get the full list of users in Group 1. Because the JOIN produces a list of all users and all groups, where the same user is listed multiple times, one entry for every Group that person belongs. My query is removing the Group 6 entries, but this is no good since the same users are also in Group 1.
I just explained why my query is failing, but I still cannot figure out how to achieve success. How do I get the Group 1 users and then remove the subset of users that are in Groups 1 & 6? These users can also be in other Groups, but these should be ignored... I just want to exclude users who are in Groups 1 & 6 from the list of users in Group 1.
Each user in the result:
must be in Group 1
must not be in Group 6
may or may not be in any other Group
Any suggestions appreciated.
You need a "not exists" clause in there as a filter.
And not exists (select 1 from users_groups x where
x.user_id = users_groups.user_id and group_id = 6
Im not familiar with code ignite but im sure this is doable
Thanks to Philip's answer, it's working. This is how to do it within CodeIgniter...
$this->db->where('users_groups.group_id = 1'); // get all users in Group 1
$this->db->where('
NOT EXISTS (
SELECT 1 FROM users_groups x
WHERE x.user_id = users_groups.user_id AND group_id = 6
)
'); // exclude users in Group 6

Improve performance of SQL Query to select ids from different tables in multiple columns

Let us just imagine I have the following table structure
Table: images
id path
1 x
2 x
3 x
4 x
5 x
6 x
7 x
8 x
Table: user
id image imageSmall
1 1 1
2 2 2
3 4 4
Table: books
id image imageSmall
1 5 5
2 6 6
3 8 8
I now want to get the ID of every image used in other tables. I made this query here
SELECT id FROM images WHERE id IN (SELECT image FROM user) OR id IN (SELECT imageSmall FROM user) OR id IN (SELECT image FROM books) OR id IN (SELECT imageSmall FROM books);
The problem I see here, is that, when I have a large amount of data, this query could be very time consuming and not performant at all because of the many IN parts of the query. Is there a way to improve the performance of this query?
I would phrase this using exists rather than in:
SELECT id
FROM images i
WHERE EXISTS (SELECT 1 FROM user u WHERE u.image = i.id) OR
EXiSTS (SELECT 1 FROM user u WHERE u.imageSmall = i.id) OR
EXISTS (SELECT 1 FROM books b WHERE b.image = i.id);
For performance, be sure that you have the following indexes:
create index idx_user_image on user(image);
create index idx_user_imageSmall on user(imageSmall);
create index idx_books_image on books(image);
Use joins instead of that many select in selects, and DISTINCT to return unique values:
SELECT DISTINCT(i.id) FROM images i
INNER JOIN `user` u
INNER JOIN `books` b
WHERE b.image=i.id OR b.imageSmall=i.id OR u.image=i.id OR u.imageSmall=i.id

PDO and prepared statements on dynamic sized queries

I am developing a small gaming website for college fest where users attend few contests and based on their ranks in result table, points are updated in their user table. Then the result table is truncated for the next event. The schemas are as follows:
user
-------------------------------------------------------------
user_id | name | college | points |
-------------------------------------------------------------
result
---------------------------
user_id | score
---------------------------
Now, the first 3 students are given 100 points, next 15 given 50 points and others are given 10 points each.
Now, I am having problem in developing queries because I don't know how many users will attempt the contest, so I have to append that many ? in the query. Secondly, I also need to put ) at the end.
My queries are like
$query_top3=update user set points =points+100 where id in(?,?,?);
$query_next5=update user set points = points +50 where id in(?,?,?,?,?);
$query_others=update user set points=points+50 where id in (?,?...........,?);
How can I prepare those queries dynamically? Or, is there any better approach?
EDIT
Though its similar to this question,but in my scenario I have 3 different dynamic queries.
If I understand correctly your requirements you can rank results and update users table (adding points) all in one query
UPDATE users u JOIN
(
SELECT user_id,
(
SELECT 1 + COUNT(*)
FROM result
WHERE score >= r.score
AND user_id <> r.user_id
) rank
FROM result r
) q
ON u.user_id = q.user_id
SET points = points +
CASE
WHEN q.rank BETWEEN 1 AND 3 THEN 100
WHEN q.rank BETWEEN 4 AND 18 THEN 50
ELSE 10
END;
It totally dynamic based on the contents in of result table. You no longer need to deal with each user_id individually.
Here is SQLFiddle demo

Select records from table1 depending on table2

I am trying to build a project where you can like other people's pictures, and when the other person likes your picture too, you have a match. Like the Tinder app if you know.
Now, I fetch 1 photo like so:
SELECT id, picture_path, profile_picture, username
FROM tusers
WHERE profile_picture IS NOT NULL
AND settings LIKE '1,%'
AND sex = :sex
AND last_visit BETWEEN CURDATE() - INTERVAL 21 DAY AND CURDATE()
AND dob BETWEEN :dob - INTERVAL 5 YEAR AND :dob2 + INTERVAL 5 YEAR
LIMIT 1
However, if you've already LIKED or PASSED someone's photo, I don't want to show it to you again. I am not sure how to do this part yet (right now, I have alreadyLiked() and alreadyPassed() functions and I am only doing a header("Location") redirect if they return true, but that will fail when you have liked/passed all the photos).
I have another table with these columns: id, user1_id, user2_id, liked, passed, matched
When you like or pass a picture, a 1 is inserted in the corresponding column.
user1_id is your ID. user2_id is the other person's ID.
Knowing the above information, what kind of query (or logic) would you use to make sure that you only show the right people (that you haven't liked or passed already) ?
suppose you have 2 tables
usr
id username
1 a
2 b
3 c
4 d
liked
id user1 user2 liked
1 1 4 1
2 1 3 1
assuming your id is 1 , from table liked it seems you have liked c,d . since 1(a) is your own id you need only b as output, your query goes as below
SELECT *
FROM usr
WHERE id NOT
IN (
SELECT user2
FROM liked
WHERE user1 =1
)
and id!=1
assuming 1 will come from session
You can use mysql join to get data from one table based on the another
In the upper case you can have join on the first tables id with the other tables user1_id, user2_id putting where clause on the liked, passed, matched
To know more about mysql joins
Try this as join is much better than a inner query suggested by ersumit $loggedINuser_id='2';//take from session $sql="SELECT tu.id, tu.picture_path, tu.profile_picture, tu.username FROM tusers tu LEFT JOIN secondtable st ON tu.id=st.user2_id WHERE tu.profile_picture IS NOT NULL AND tu.settings LIKE '1,%' AND tu.sex = :sex AND tu.last_visit BETWEEN CURDATE() - INTERVAL 21 DAY AND CURDATE() AND tu.dob BETWEEN :dob - INTERVAL 5 YEAR AND :dob2 + INTERVAL 5 YEAR AND st.user1_id != '".$loggedINuser_id."' LIMIT 1";

Twitter-like following system

I am working on a twitter clone in PHP for school, and I have one major problem. I cannot find a way to implement a follower system. There is a table for users, and I want to add a field that holds the ids of all of the users that each user follows.
Should I separate the ids with commas and then split them apart in PHP? And then I need to select all of the tweets from the tweets table that were tweeted by any of the users followers. Is there an SQL command that I can use? Something similar to
SELECT *
FROM tweets
WHERE author='$followeduser'"
but where $followeduser is multiple ids.
Have a USER_MASTER table like this
USER_ID (int)
USER_NAME(varchar(50))
Create a table called USER_FOLLOWERS like this
USER_FOLLOWER_ID // Auto increment-Primary Key for this record
USER_ID (int) // foriegn key to UserId column in USER_MASTER table
FOLLOWER_ID (int) // foriegn key to UserId column in USER_MASTER table
Store the UserId in the first column and store the UserId of the User who follows this user in the Follower_ID column.
So your data will look like this
USER_ID USER_NAME
--------------------------------------
1 SCOTT
2 JARED
3 MARC
4 ERIC
USER_FOLLOWER_ID USER_ID FOLLOWER_ID
--------------------------------------
1 1 2
2 1 3
3 1 4
4 2 1
So this means , The User Scott has 3 followers, Jared, Marc and Eric. User JARED HAS one Follower, that is SCOTT
To get the list of Followers for a user(ex : Scott (ID=1)) , you can do a Join between these 2 tables
SELECT U. USER_ID, U.USER_NAME From USER_MASTER U
INNER JOIN USER_FOLLOWERS UF ON U.USER_ID=UF.FOLLOWER_ID
WHERE UF.USER_ID=1 // 1 is the ID of SCott
Make a join table.
Putting all IDs in a list is not the normalized way and can lead to many many issues.
Have a relations table where you have one column called user and second that is following. So if user 1 is following user 3 and 5, then you would have an entree where user = 1 following = 3 and user = 1 following = 5 (use whatever ID's you want). You also have your Tweets Table where you store all tweets. Youre going to want to make a query that joins the two tables

Categories