desperate with complicated join query (mysql & php) - php

okay, i'm setting up a multi-user chat system.
i have a messages table, that holds all the messages - simplified:
messages:
id,
content,
thread_id
then i have a threads table:
messages_threads:
id,
participantlist_id
then i have a participantlist table:
participantlist:
list_id,
name
and i have a participantlist_links table:
participantlist_links:
list_id,
participant_id
now i'd like to find out the thread id from a list (array) of participants, i came up with this:
$threadid_sqlquery = "
SELECT messages_threads.id FROM messages_threads
JOIN participantlist_links
ON messages_threads.participantlist_id = participantlist_links.list_id";
foreach($participants_array as &$participant_id){
$maxid_sqlquery .= "
AND participantlist_links.participant_id='".$participant_id."'";
}
but now: i'm looking for the thread_id of a chat between users 1 and 2 - there is a multi-user chat with users 1,2,3 and a chat with users 1,2,3,4 i get a result of three rows, but i only want the one where only users 1 and 2 are participants.
is there any way to query for that?

SELECT mt.id
FROM (
SELECT list_id
FROM participantlist_links pll
WHERE participant_id IN (1, 2)
GROUP BY
list_id
HAVING COUNT(*) = 2
) q
JOIN message_threads mt
ON mt.participantlist_id = q.list_id
WHERE NOT EXISTS
(
SELECT NULL
FROM participantlist_links pll
WHERE pll.list_id = q.list_id
AND pll.participant_id NOT IN (1, 2)
)
Create the following indexes:
participantlist_links (participant_id, list_id) -- unique
participantlist_links (list_id)

Related

How to retrieve data with 3 tables in mysql?

I am having 2 tables :
1.internal_employee_master
id employee_name unique_id
1 Noah ABCD
2 Liam ABCD
3 William ABCD
4 Benjamin ABCD
5 Jacob EFGH
2.external_employee_master
id name unique_id
1 Elijah ABCD
2 Ethan ABCD
3 Alexander EFGH
I am using UNION query to get both tables data into single table and display this data into html table.
select id
, employee_name
, unique_id
from internal_employee_master
where unique_id = 'ABCD'
union
select id
, employee_name
, unique_id
from external_employee_master
where unique_id = 'ABCD'
I want to store payslips of both employees into single table.
I have one table payslips with emp_id and emp_type columns.
I am storing data into payslips data like:
id pay_slip emp_id emp_type
1 Noah_payslip.pdf 1 internal
2 Liam_payslip.pdf 2 internal
3 Lia_payslip.pdf 1 External
as you can see in above table i am storing emp_id and emp_type of
both the tables in single columns each.
Now, i dont undestand how to split data of internal employee and
external employee from pay_slip table and show data in html table.
Currently, i am writing below sql joins to get employee_names of
internal and external employee tables but it doesnt work for me.
$id = $_GET['id];
SELECT ps.id,ps.pdf,ps.emp_id,ps.emp_type,external_employee.name as comemp,
internal_employee.comp_empl_name as comemp
FROM pay_slip as ps
INNER JOIN internal_employee_master as internal_employee ON internal_employee.comp_trad_id = ps.trade_id
INNER JOIN external_employee_master as external_employee ON external_employee.trad_id = ps.trade_id
where ps.is_deleted = 1 AND ps.id = '".$id."'"
Please help me to join query to get name and employee_name with respect to emp_type form pay_slip table.
How about using UNION again?
SELECT
ps.id,
ps.pdf,
ps.emp_id,
ps.emp_type,
external_employee.name AS comemp,
internal_employee.comp_empl_name AS comemp
FROM
pay_slip AS ps
INNER JOIN
internal_employee_master AS internal_employee ON internal_employee.comp_trad_id = ps.trade_id
WHERE
ps.is_deleted = 1 AND ps.id = '".$id."'
AND ps.type = 'internal'
UNION ALL
SELECT
ps.id,
ps.pdf,
ps.emp_id,
ps.emp_type,
external_employee.name AS comemp,
internal_employee.comp_empl_name AS comemp
FROM
pay_slip AS ps
INNER JOIN
external_employee_master AS external_employee ON external_employee.trad_id = ps.trade_id
WHERE
ps.is_deleted = 1 AND ps.id = '".$id."'
AND ps.type = 'external'
You could try this
SELECT ps.id, ps.pay_slip, ps.emp_type, COALESCE(i.employee_name, e.name) AS name
FROM payslips ps
LEFT JOIN internal_employee_master i ON i.id = ps.emp_id AND ps.emp_type = 'internal'
LEFT JOIN external_employee_master e ON e.id = ps.emp_id AND ps.emp_type = 'External'
AND ps.id = :ID
You can see this in action here http://sqlfiddle.com/#!9/53a195/7/0
I would mention that there are a number of issues in your included tables and queries. For example, irregular column names between tables (name vs. employee_name), you've missed the is_deleted column from your example schema, and you have capitalised and non-capitalised values in the emp_type column which is confusing.

get all rows having common parents

id parent_id child_id
1 1 1
2 2 2
3 2 2
4 1 1
I have a table from which i need to get the common values from data when i query it with id... for eg if id=2 and id=3 then return
id parent_id
2 2
3 2
i have tried this after hunting a lot through various examples :
SELECT ta.user_id,ta.interest_parent_id,ta.interest_child_id
FROM user_interest ta
WHERE ta.user_id=2 AND
(SELECT COUNT(*) FROM user_interest tb
WHERE ta.interest_parent_id=tb.interest_parent_id
AND tb.user_id=3 )>1
but it responds with only:
id parent_id
2 2
any help :( im using a mysql database with php/codeigniter to do the scripting
You can give it a try:
SELECT
tOne.id,
tOne.parent_id
FROM
(
SELECT
*
FROM user_interest A
WHERE A.id IN (2,3)
) tOne
INNER JOIN
(
SELECT
*
FROM user_interest A
WHERE A.id IN (2,3)
) tTwo
ON tOne.parent_id = tTwo.parent_id
AND tOne.id <> tTwo.id
ORDER BY tOne.parent_id;
SQL FIDDLE DEMO
Any suggestion towards optimization of the query is welcome.
EDIT: SQL FIDDLE
You can make a sub SELECT:
SELECT * FROM table WHERE Name IN (SELECT Name FROM table GROUP BY Name HAVING count(*) > 1)

Suggestion SQL query

Basically what i am trying to do is to suggest people based on common interests.
I have a table of Users.
I have a table of Interested_People where UserID + InterestID is stored.
I have a table of Contactlist where people who are added with each other is stored.
What I want is to only output people who are not your friends.
I searched a lot in internet but couldn't find something like so.
Although I created a query but it is very slow. Now I Kindly request you guys if you can edit my query a bit and make it much more bandwidth & time efficient.
SELECT *
FROM users
WHERE id IN(SELECT userid
FROM interested_people
WHERE interested_in IN(SELECT interested_in
FROM interested_people
WHERE userid = [userid])
AND id NOT IN(SELECT user1 AS my_friends_userid
FROM contactlist f
WHERE f.user2 = [userid]
AND accepted = 1
UNION
SELECT user2 AS my_friends_userid
FROM contactlist f
WHERE f.user1 = [userid]
AND accepted = 1))
AND id != [userid]
ORDER BY Rand ()
LIMIT 0, 10;
This query actually does the job but it takes very long about 16 sec in my local machine. and that's not what I want. I want a fast and reliable one.
Thanks in advance!
Subqueries in WHERE clauses are often slow in MySQL; at least slower than comparable JOINs.
SELECT others.*
FROM interested_people AS userI
INNER JOIN interested_people AS othersI
ON userI.interestid = othersI.interestid
AND userI.userid <> othersI.userid
INNER JOIN users AS others ON othersI.user_id = others.userid
LEFT JOIN contactlist AS cl
ON userI.userid = cl.user1
AND others.userid = cl.user2
AND cl.accepted = 1
WHERE userI.userid = [userid]
AND cl.accepted IS NULL
ORDER BY RAND()
LIMIT 0, 10;
Note: intuition makes me wonder if contactlist might be better as a where subquery.
The AND cl.accepted IS NULL ends up processed after the JOINs, resulting in allowing only results that did NOT have a match in contactlist.
If you want to enhance things a bit further:
SELECT others.*, COUNT(1) AS interestsCount
...
GROUP BY others.userid
ORDER BY interestsCount DESC, RAND()
LIMIT 0,10;
This would give you a random selection of the people that share the most interests in common.
First, looking at your interested-in query and assuming the "userID"
you are testing with is = 1. Sounds like you are trying to get one level
away from those user 1 is also interested in...
SELECT userid FROM interested_people
WHERE interested_in IN
( SELECT interested_in FROM interested_people
WHERE userid = [userid] )
Sample Data for Interested_People
userID Interested_In
1 5
1 7
1 8
2 3
2 5
2 7
7 1
7 2
7 5
8 3
In this case, the innermost returns interested_in values of 5, 7, 8.
Then, getting all users who are interested in 5, 7 and 8 would return 2 and 7.
(but since both users 2 and 7 are interested in 5, the 2 ID would be returned TWICE
thus a possible duplicate join later on. I would do distinct. This same
result could be done with the following query which you could sample times with...
SELECT distinct ip2.userid
from
interested_people ip
join interested_people ip2
ON ip.interested_in = ip2.interested_in
where
userid = [parmUserID]
Now, you need to exclude from this list all your contacts already accepted.
You could then left-join TWO TIMES for the from/to contact and ensure NULL
indicating not one of the contacts... Then join again to user table to
get the user details.
SELECT
u.*
from
users u
JOIN
( SELECT distinct
ip2.userid
from
interested_people ip
join interested_people ip2
ON ip.interested_in = ip2.interested_in
left join contactList cl1
ON ip2.userid = cl1.user1
AND cl1.accepted = 1
left join contactList cl2
ON ip2.userid = cl2.user2
AND cl2.accepted = 1
where
ip.userid = [parmUserID]
AND NOT ip2.userID = [parmUserID] ) PreQuery
ON u.id = PreQuery.userID
order by
RAND()
limit
0, 10
I would have two indexes on your contactList table to optimize both left-joins... with user1 and user2 in primary position... Similarly for the interested_people table.
table index
contactList ( user1, accepted )
contactList ( user2, accepted )
interested_people ( userid, interested_in )
interested_people ( interested_in, userid )
I would expect your user table is already indexed on the ID as primary key.
I think this will give you the same results but perform a lot better:
SELECT * FROM Users u
INNER JOIN interested_people i
ON u.id = i.userid
WHERE NOT EXISTS
(SELECT * FROM contacts WHERE user1 = [userid] or user2 = [userid] and accepted=1)
AND id != [userid]
ORDER BY Rand()
LIMIT 0, 10
Skip the ORDER BY clause if that is at all reasonable. That will be the most expensive part
The select and join clauses give you the users who are interested in connecting and the WHERE NOT EXISTS is a performant way to exclude those contacts already listed.

How to count records in MySQL and merge results in PHP

I have a table which stores clients like this:
id name
-- ----
1 John
2 Jane
...
I also have another table which stores links created by clients:
id client_id link created
-- --------- ---- -----------
1 1 ... 2015-02-01
2 1 ... 2015-02-26
3 1 ... 2015-03-01
4 2 ... 2015-03-01
5 2 ... 2015-03-02
6 2 ... 2015-03-02
I need to find how many links a client has created today, this month and during all the time. I also need their name in the result, so I'll be able to craete a HTML table to display the statistics. I thought I can code as less as possible like this:
$today = $this->db->query("SELECT COUNT(*) as today, c.id as client_id, c.name FROM `links` l JOIN `clients` c ON l.client_id = c.id WHERE DATE(l.created) = CURDATE() GROUP BY c.id");
$this_month = $this->db->query("SELECT COUNT(*) as this_month, c.id as client_id, c.name FROM `links` l JOIN `clients` c ON l.client_id = c.id WHERE YEAR(l.created) = YEAR(NOW()) AND MONTH(l.created) = MONTH(NOW()) GROUP BY c.id");
$yet = $this->db->query("SELECT COUNT(*) as yet, c.id as client_id, c.name FROM `links` l JOIN `clients` c ON l.client_id = c.id WHERE GROUP BY c.id");
And then merge them in PHP as I asked HERE before, like this:
$result = array_replace_recursive($today, $this_month, $yet);
So I'll be able to loop into the result and print my HTML table.
But there are logical problems here. Everything works fine, but the result in a month is a wrong number, forexample the whole created links of one person is 1 but it shows 4 in the monthly counter! I also tried to use RIGHT JOIN in SQL query to get all clients, so array_replace_recursive in PHP could work fine as I think it doesn't work properly at the moment, but no success and got wrong results again.
Can anyone show me a way to make the job done?
This query should do it for today
$query_today="
SELECT name, id AS user_id, (
SELECT COUNT( * )
FROM links
WHERE client_id = user_id AND created = '2015-03-02'
) AS alllinks
FROM clients"
adjust the WHERE clause in the subquery for months and all
$query_month="
SELECT name, id AS user_id, (
SELECT COUNT( * )
FROM links
WHERE client_id = user_id AND created like '2015-03%'
) AS alllinks
FROM clients"
$query_all="
SELECT name, id AS user_id, (
SELECT COUNT( * )
FROM links
WHERE client_id = user_id
) AS alllinks
FROM clients"

MySQL Joining two rows, two tables, with the same fields

Hi Im new to MySQL and PHP, and this is my first post.. So please bear with me.
I am trying to add two tables and two rows from one table
friends
member_ID | friend_ID | status
and a user table
member_ID | username
What I am trying to do is combine both tables for a friend request, friends.member_ID is the user.member_ID sending the request, friends.member_ID, is the user.member_ID that is being requested, status is when they accept the request it will turn 0 to 1 which will make the relationship true.
so far, I have this for my query to display all these fields to show who has requested this person as a friend
SELECT users.member_ID, friends.member_ID, friends.friend_ID, friends.status
FROM `users` , `friends`
WHERE friends.status=0
AND users.member_ID = friends.member_ID
AND friends.member_ID = users.member_ID
AND users.member_ID = 6 (this will be $_SESSION[member_ID] when I add it to php)
I understand you can use an alias but I am a bit confused
Please help, my assignment is due tomorrow, and there is still so much to do.
Thanks
try this with join
SELECT users.member_ID, friends.member_ID, friends.friend_ID, friends.status
FROM `users`
INNER JOIN `friends`
ON users.member_ID = friends.member_ID
WHERE friends.status=0
AND users.member_ID = 6
Column alias - use AS(/as) after column name
users.member_ID as uId, friends.member_ID as fId
Table alias - define after table name
users u , friends f
If using table aliases, you can use them when selecting your column names
u.member_ID as uId, f.member_ID as fId
http://dev.mysql.com/doc/refman/4.1/en/problems-with-alias.html
SELECT u.member_ID as uId, f.member_ID as fId, f.friend_ID as ffId, f.status as fStatus
FROM `users` u
INNER JOIN `friends` f
ON u.member_ID = f.member_ID
WHERE f.status=0
AND u.member_ID = 6
Aliases are useful when you are selecting 2 or more columns with the same name from multiple tables - users.member_ID, friends.member_ID. Instead of using an ambiguous $row['member_ID'] or having to use $row[0]/$row[1], you can use $row['uID']/$row['fID']

Categories