Join Query on multiple rows to search in - php

Currently I am working on a Wordpress site, and I would like it to be possible to search for users on their first and last name on a part of my site.
Wordpress makes use of a meta table to store any 'extra' data for a user. And the first and last name are some of those meta fields.
Now I am trying to create a query which gets me a result which returns me a user matching the first and last name, the only problem is that there is a meta row for last name and another one for first-name, they both do have a reference to the same user_id. Only I don't know how I can create the query correctly.
When I have this query
SELECT U.id FROM wp_users AS U, wp_usermeta as US
WHERE U.id=US.user_id
AND (US.meta_key='first_name' AND US.meta_value='MyFirstName')
It does return the user I am looking for, however when I try this
SELECT U.id FROM wp_users AS U, wp_usermeta as US
WHERE U.id=US.user_id
AND (US.meta_key='first_name' AND US.meta_value='MyFirstName')
AND (US.meta_key='last_name' AND US.meta_value='Dijkstra')
I get no results at all, could someone help me?
In case someone is interested in the database structure, here ( http://cl.ly/6rGx ) is the users table and here ( http://cl.ly/6rts ) is the users_meta table.
Thanks in advance

You can't join one row to two other rows of another table at the same time, so you need to join the other table twice, once for first name and once for last name. Like this:
SELECT U.id
FROM wp_users AS U
inner join wp_usermeta as UMF on U.id = UMF.user_id
inner join wp_usermeta as UML on U.id = UML.user_id
WHERE UMF.meta_key = 'first_name'
AND UMF.meta_value = 'MyFirstName'
AND UML.meta_key = 'last_name'
AND UML.meta_value = 'Dijkstra'

You need to join twice, with different conditions for each. The conditions can be in the WHERE clause as RedFilter suggested, but I prefer compound conditionals in the JOIN clause for readability.
SELECT U.id
FROM wp_users U
join wp_usermeta f on U.id = f.id
and f.meta_key='first_name'
and f.meta_value='MyFirstName'
join wp_usermeta l on U.id = l.id
and l.meta_key='last_name'
and l.meta_value='Dijkstra'
A slightly different version with the keys in the join and the requested values in the where clause:
SELECT U.id
FROM wp_users U
join wp_usermeta f on U.id = f.id and f.meta_key='first_name'
join wp_usermeta l on U.id = l.id and l.meta_key='last_name'
where f.meta_value='MyFirstName' and l.meta_value='Dijkstra'

Consider the logic by re-writing the order of the ANDs (no, parens don't make a difference).
US.meta_key='first_name' AND US.meta_key='last_name' AND
US.meta_value='MyFirstName' AND US.meta_value='Dijkstra'
See the problem? This condition will never be true, because neither US.meta_key nor US.meta_value will never be two values. You need to use an OR, not and AND.
EDIT
A query like this would give you the desired results:
SELECT U.id FROM wp_users AS U, wp_usermeta as US
WHERE U.id=US.user_id AND (
(US.meta_key='first_name' AND US.meta_value='MyFirstName')
OR (US.meta_key='last_name' AND US.meta_value='Dijkstra'))

Related

Limit LEFT JOIN results to 1 with flexible where clause

my query looks like that:
SELECT
count(users.id)
FROM users
LEFT JOIN mail_sender_jobs_actions ON mail_sender_jobs_actions.userID = users.id
LEFT JOIN table2 ON table2.userID = users.id
LEFT JOIN table3 ON table3.userID = users.id
WHERE {$flexibleWhereClause}
Now, the mail_sender_jobs_actions table CAN (doesnt need to return anything) return multiple entries. I dont want to group the results but still limit the returns of mail_sender_jobs_actions to 1 so I dont get duplicates... Otherwise the count wouldnt work properly.
Scraped the whole web and found nothing working for me as I want to keep the where clause flexible. Any solution?
EDIT
so to explain the situation. We have a table with users (users). We have a table with actions (mail_seder_jobs_actions). We have other tables related to that query which are not relevant (table1, table2, table3)
If a user does an action, an entry is being created in the actions table.
The where clause is flexible, meaning it is possible that somebody wants to only show users with a specific action.
It is also possible that an action is not relevant to the user, so this entry gets ignored.
With where criteria you have there is no point using left join, since the where criteria applies to the table on the right hand side, effectively turning the left join into an inner join.
Apparently yo do not use any columns from the right hand side table, so instead of using joins, I would use an exists subquery.
SELECT
1 as count,
users.email
FROM users
WHERE EXISTS (SELECT 1
FROM mail_sender_jobs_actions
WHERE mail_sender_jobs_actions.userID = users.id
AND mail_sender_jobs_actions.type = '1'
AND mail_sender_jobs_actions.jobID = '106'
AND {$flexibleWhereClause})
However, there is little point in having the count() because it will always return 1. If you want to count how many records each user has in the mail_sender_jobs_actions table, then you have to use left join, group by, and move the where criteria into the join condition:
SELECT
count(mail_sender_jobs_actions.userID),
users.email
FROM users
LEFT JOIN mail_sender_jobs_actions ON mail_sender_jobs_actions.userID = users.id
AND mail_sender_jobs_actions.type = '1'
AND mail_sender_jobs_actions.jobID = '106'
AND {$flexibleWhereClause}
GROUP BY users.email

query user group hide search results

Hi I am trying to change some code so that users with certain group id do not show in search results.
at the moment the code is
$query = 'SELECT distinct b.'.$db->nameQuote('id')
.' FROM '.$db->nameQuote('#__users').' b';
I am trying to add something like the following but cannot get it to work.
select * from '.$db->quoteName('#__users').' where id not in (select user_id from #__user_usergroup_map where group_id = 8)
Any help would be appreciated.
Thanks.
This how you can try
select * from users u
where
not exists
(
select 1
from user_group ug
where
u.id = ug.iduser
AND ug.group_id = 8
)
You need change the table name and field name in the above query as your need.
DEMO
There are three ways of doing that.
Method 1: Join
Join usergroup_map table and then, select all rows that have different group_id that way:
SELECT <comma separated fields> from USERS u
LEFT JOIN USERGROUPS ug ON u.user_id = ug.user_id
WHERE ug.group_id != :group_id
GROUP BY u.user_id
And then -> bind any number to :group_id.
Please keep in mind that above statement will return users that are assigned to :group_id only if they are in another groups as well. (one to many relation).
Method 2: Subselect
Already suggested by other users.
Method 3: Join & Subselect
The 3rd, and the last option is to use sub-query within join statement, which tends to be the fastest solution in terms of optimalization. Of course, query times may be different depending on the engine you are working with, but it's worth giving a try.
SELECT <comma separated fields>
FROM USERS u
INNER JOIN (
SELECT g.user_id
FROM USERGROUPS g
WHERE g.group_id != :group_id
) ug ON ug.user_id = u.user_id
--
In this answer, I assume that you have properly configured database with foreign keys.

php/mysql join syntax

I have the userids of people who have joined a group in one table but not their names thatlie in another table. So I think I need to do a join. I'm starting with groupid that describes the grouop.
Table 1, groupmem has groupid and userid for the members.
Table 2, users has userid and username
The users table has every user. The groupmem only has some who have joined groups.
SQL statement should be something like following but can't get it to work.
select users.name
FROM users,groupmem
LEFT JOIN users
on groupmem.userid=users.userid
WHERE groupmem.groupid = 22
22 being some value..
Thinking maybe where clause is in wrong place or I am using wrong type of join but or not using on correctly but, in any case, can't get it to work. Thx for any suggestions:
Try:
SELECT u.username
FROM `users` u
LEFT JOIN `groupmem` g
ON u.userid = g.userid
WHERE g.groupid = 22
This should do the trick:
SELECT users.name
FROM groupmem
LEFT JOIN users ON groupmem.userid = users.userid
WHERE groupmem.groupid = 22
Your query seems to be quite right - assuming I guessed your table-structure right.

MySql If Record Exists Inside Select Query

Creating a forum-type site and I have 3 tables, one for storing user information (users), one for the original post (threads), and one for an upvote system like SO has (votes).
The votes table has 3 columns, id, userid, and threadid. When a user upvotes a thread, a record is inserted into the votes table. When I query for the thread I want to know if the user has upvoted for it, essentially if a record exists in the votes table with the correct userid and threadid. I can do this in two queries, but I think there has to be a way to get everything in one.
My query currently:
"SELECT t.id, t.title, t.content u.id AS uid, u.username
FROM threads t, users u
WHERE t.id = '".$userid."'
AND t.author = '".$userid."'"
In case you need a better idea, the following will query the desired results ONLY if the user has upvoted. I need the query to still return if the record in the votes table doesn't exist (possibly return a vote value as null?).
"SELECT t.id, t.title, t.content u.id
AS uid, u.username v.id
FROM threads t, users u, votes v
WHERE t.id = '".$threadid."'
AND t.author = '".$userid."'
AND v.threadid = t.id
AND v.userid = '".$userid."'"
Also I taught myself (and am still learning) mysql and database design so if there's a better method/approach such as joining tables, please let me know. Thanks.
Your second query is doing inner joins, which would only return records that appear on both sides of the join. You'd want to do a left/right outer join on the votes table instead, so that you'd still get user+thread records even if there's no matching vote record.
SELECT t.id, t.title, t.content, u.id, u.username, v.id
FROM threads AS t
INNER JOIN users AS u ON t.userid = u.id
LEFT JOIN votes AS v ON (v.userid = u.id and t.id = v.threadid)
WHERE (u.id = $userid) AND (t.id = $threadid)
just guessing at this, but should be enough to get you started.

User/Subscriber sql query

I'm creating a table that shows all the registered users to which the current user has not yet subscribed to. But once he has subscribed someone, I need to filter that list to exclude those.
Let's say the theres a table called subscribed which lists the User and to whom he is subscribed to.
|UserId||SubscriberID|
Its easy to make it into multiple queries, but I've been unsuccessfully trying to make it into one query, to save an extra loop of MySQL calls.
Here's What I have so far:
SELECT u.UserID, FullName, UserName from users u
LEFT JOIN subscribed t ON
((u.UserName LIKE '%$search%' OR
u.Email LIKE '%$search%') AND
({$_SESSION['ID']} = t.UserID
AND t.FollowerID != u.UserID)
)
I know the last part of the query is wrong, since I only compare if the UserID and the FollowerID don't match for one particular row, not the entire table.
To find a list of results in table A that are not in table B, you have two options. Either use the NOT IN syntax, or LEFT JOIN and look where the PK field in the B table is NULL.
NOT IN example:
SELECT a.id FROM a WHERE a.id NOT IN (SELECT b.id FROM b)
LEFT JOIN example:
SELECT a.id
FROM a
LEFT JOIN b ON (a.id = b.id)
WHERE (b.id IS NULL)

Categories