I have two tables:
table1:
id email
1 john#gmail.com
2 doe#gmail.com
table2:
userid key value
1 firstname john
1 phone 112233
2 firstname doe
2 phone 223344
This is mysql query without condition:
SELECT a.*,
b.*,
GROUP_CONCAT(b.key),
GROUP_CONCAT(b.value)
FROM table1 a
LEFT JOIN table2 b ON a.id = b.userid
This is result:
array(
[id] => 1
[email] => john#gmail.com
[userid] => 1
[key] => firstname,phone
[value] => john,112233
)
array(
[id] => 2
[email] => doe#gmail.com
[userid] => 2
[key] => firstname,phone
[value] => doe,223344
)
This is mysql query with condition:
SELECT a.*,
b.*,
GROUP_CONCAT(b.key),
GROUP_CONCAT(b.value)
FROM table1 a
LEFT JOIN table2 b ON a.id = b.userid
WHERE b.key = "firstname"
AND b.value LIKE '%jo%'
And this is result:
array(
[id] => 1
[email] => john#gmail.com
[userid] => 1
[key] => firstname
[value] => john
)
But I want this:
array(
[id] => 1
[email] => john#gmail.com
[userid] => 1
[key] => firstname,phone
[value] => john,112233
)
There any way to do this? thank for any help!
Your queries are lacking the GROUP BY clause to get a row per user. Then use a HAVING clause to make sure the aggregated row includes a firstname '%jo%':
SELECT a.*,
GROUP_CONCAT(b.key),
GROUP_CONCAT(b.value)
FROM table1 a
LEFT JOIN table2 b ON a.id = b.userid
GROUP BY a.id
HAVING sum(b.key = 'firstname'
AND b.value LIKE '%jo%') > 0;
true results in 1, false in 0 in MySQL. So checking whether the sum is greater than zero means checking whether the condition is true at least once.
Related
I have query like this,
SELECT * FROM users ORDER BY score
So, the result is like this.
Array
(
[0] => stdClass Object
(
[userid] => 3
[user] => John Doe
[score] => 50
)
[1] => stdClass Object
(
[userid] => 1
[user] => Mae Smith
[score] => 38
)
[2] => stdClass Object
(
[userid] => 2
[user] => Mark Sam
[score] => 26
)
)
But, I want to add a rank using find_in_set query. So the result might be like this. So that the user can view their ranks when they login to their account.
Array
(
[0] => stdClass Object
(
[userid] => 3
[user] => John Doe
[score] => 50
[rank] => 1
)
[1] => stdClass Object
(
[userid] => 1
[user] => Mae Smith
[score] => 38
[rank] => 2
)
[2] => stdClass Object
(
[userid] => 2
[user] => Mark Sam
[score] => 26
[rank] => 3
)
)
I tried this one.
$listOfUser = array();
foreach($users as $user) {
$listOfUser[] = $user->userid;
}
And used another query
$userid = 2 // => id of loggedin user
SELECT *, find_in_set($userid, $listOfUser) as rank FROM users where userid=$userid ORDER BY score
So, I got this result
Array
(
[1] => stdClass Object
(
[userid] => 2
[user] => Mark Sam
[score] => 26
[rank] => 3
)
)
Which is somehow correct. But, is there another way of querying that result using only one SQL query and without using foreach loop?
Something like this.
$userid = 2 // => id of loggedin user
SELECT *, find_in_set($userid, (SELECT * FROM users ORDER BY score)) as rank FROM users where userid=$userid ORDER BY score
But I got this error Subquery returns more than 1 row
If You don't insist on using find_in_set, you can get result with simple join. You ask for list of users (p) and for each user you ask, how many users have better score than him or her (c):
SELECT p.userid, COUNT(c.userid) AS rank
FROM users AS p
LEFT JOIN users AS c ON c.score > p.score
GROUP BY p.userid
This works even if you add other conditions, like WHERE p.userid = 123.
If more users have the same score, the ranks would look like 0,1,2,2,2,5,6.
In your query, you can add counter, like this:
set #n:=0;
SELECT #i := #i + 1 AS rank, * FROM users ORDER BY score
The rank here is relative to the score distribution across all users. I believe you should try something originally proposed in this answer:
SELECT users.*,
#rownum := #rownum + 1 as rank
FROM users
CROSS JOIN (select #rownum := 0) r
ORDER BY score DESC
What it does is basically order all users by score, and assign each of them an incremental value "rank". So the top scorer would have a rank of 1, the second scorer would have a rank of 2 etc.
Keep in mind that this solution is not "fair" - each user will have a different rank, even if all users have the same score. If you try to rank users as they do in sports (if two top competitors have the same score, they both take 1st place, and the next best competitor takes 3rd place, not second), you should think of a different solution.
I have two tables
Meetings:
m_id ProjectName
1 Test
2 Test2
Meeting_next:
id fk_m_id Meetingdate status
1 1 9-1-2018 0
1 1 10-1-2018 0
1 1 13-1-2018 1
I want to join this two tables when I left join it I will get duplicate value
Expected output
Array
(
[0] => Array
(
[m_id] => 1
[ProjectName] => test
[meetingDate] =>13-1-2018
)
[1] => Array
(
[m_id] => 2
[ProjectName] => test2
[meetingDate] =>
)
)
I tried -
select * from meetings left join meeting_next on meetings.m_id= meeting_next.fk_m_id where meeting_next.status=1 order by m_id desc
myOutput:
Array
(
[0] => Array
(
[m_id] => 1
[ProjectName] => test
[meetingDate] =>13-1-2018
) )
Bad luck I got only first Project name. I need second too. Please help me. Any help would be appreciated.
Your WHERE condition filters the number of rows to only the row of the first project.
If you want to show both projects, even if there are no meetings with status 1, you need to move the condition to the join condition:
select *
from meetings
left join meeting_next
on meetings.m_id= meeting_next.fk_m_id
and meeting_next.status=1
order by m_id desc
Now you will get all rows from meetings with only the matching entries from meeting_next.
I have 3 mysql tables from where I am trying to fetch data
Table: list
list_id | name | description
-------------------------------------
1234 | name1 | sample description1
1235 | name2 | sample description2
Table: list_to_category
id | list_id | category_id
--------------------------------
1 | 1234 | 1
2 | 1234 | 2
3 | 1234 | 3
4 | 1235 | 2
5 | 1235 | 3
And table: category
id | title | parent_id
--------------------------------
1 | Category 1 | 0
2 | Category 2 | 0
3 | Category 3 | 0
And from PHP SQL query I want to fetch data like below
1. name1 - category 1, category 2, category 3
2. name2 - category 2, category 3
I tried below query
SELECT list.name, category.title FROM list
LEFT JOIN list_to_category
ON list.id = list_to_category.list_id
LEFT JOIN category
ON list_to_category.id = category.id
This gives me only single category name assigned to a list like this
1. name1 - category 1
2. name2 - category 2
Is it possible in single query?
You can use GROUP_CONCAT for this:
select
l.list_id,
l.name,
group_concat(distinct c.title) categories
from list l
left join list_to_category lc
on l.list_id = lc.list_id
left join category c
on lc.category_id = c.id
group by l.list_id
You can try this solution.
select l.list_id, l.name, (select group_concat(c.title) from list_to_category ltc JOIN category c ON c.id=ltc.category_id where ltc.list_id=l.id) from list l
Hope this will help you!!!
Use GROUP_CONCAT for group by "name" to fetch result :
SELECT L.name, GROUP_CONCAT(C.title) as title FROM list L
LEFT outer JOIN list_to_category LC ON L.list_id = LC.list_id
LEFT outer JOIN category C ON LC.category_id = C.id
group by L.name
Use GROUP_CONCAT for group by "list_id" for same name of list to fetch result :
SELECT L.name, GROUP_CONCAT(C.title) as title FROM list L
LEFT outer JOIN list_to_category LC ON L.list_id = LC.list_id
LEFT outer JOIN category C ON LC.category_id = C.id
group by L.list_id
It should be apparent from the code below that I'm no PHP coder. However, this should get the idea across. You can also use javascript/css to handle the transformation, which means things can be even more dynamic...
Oh, and I changed some table/column names - because I like it better that way...
<?php
require('path/to/connection/statements'); // $con
$query = "
SELECT l.list_id
, l.name
, l.description
, c.category_id
, c.title
, c.parent_id
FROM list l
JOIN list_category lc
ON lc.list_id = l.list_id
JOIN category c
ON c.category_id = lc.category_id
ORDER
BY l.list_id
, c.category_id;
";
$result = mysqli_query($con,$query);
$my_array = array();
while($row = mysqli_fetch_assoc($result)){
$my_array[] = $row;
}
$new_array = array();
foreach ($my_array as $row)
{
$new_array[$row['list_id']][$row['name']][$row['description']][] = $row['title'];
}
print_r($new_array);
?>
This will turn an array like this:
Array
(
[0] => Array
(
[list_id] => 1234
[name] => name1
[description] => sample description1
[category_id] => 1
[title] => Category 1
[parent_id] => 0
)
[1] => Array
(
[list_id] => 1234
[name] => name1
[description] => sample description1
[category_id] => 2
[title] => Category 2
[parent_id] => 0
)
[2] => Array
(
[list_id] => 1234
[name] => name1
[description] => sample description1
[category_id] => 3
[title] => Category 3
[parent_id] => 0
)
[3] => Array
(
[list_id] => 1235
[name] => name2
[description] => sample description2
[category_id] => 2
[title] => Category 2
[parent_id] => 0
)
[4] => Array
(
[list_id] => 1235
[name] => name2
[description] => sample description2
[category_id] => 3
[title] => Category 3
[parent_id] => 0
)
)
...into an array like this...
Array
(
[1234] => Array
(
[name1] => Array
(
[sample description1] => Array
(
[0] => Category 1
[1] => Category 2
[2] => Category 3
)
)
)
[1235] => Array
(
[name2] => Array
(
[sample description2] => Array
(
[0] => Category 2
[1] => Category 3
)
)
)
)
try this code
select l.name,c.title
from list_to_category lc join list l on lc.list_id=l.id
join category c on lc.catg_id=c.id
I have 3 tables
user,
wink,
messages
Im going to clarify what i want because no one seems to understand
SELECT wink.*,user.id,user.points,user.gender,user.firstname,user.email
FROM wink
INNER JOIN user ON
(wink.id_user_from_wink=user.id OR wink.id_user_to_wink=user.id)
WHERE user.id!=?
AND (wink.id_user_from_wink=? OR wink.id_user_to_wink=?)
AND wink.wink_confirmed='1'
This works exactly as i want i to. I get the desired resultset, however now i need to get the last row matching from messages table.
I have tried using LEFT JOIN but it returns to many rows.
I need to return the last matching row for each result i get from the query above
As i said, i have tried:
SELECT wink.*,user.id,user.points,user.gender,user.firstname,user.email
FROM wink
INNER JOIN user ON
(wink.id_user_from_wink=user.id OR wink.id_user_to_wink=user.id)
LEFT JOIN messages ON (messages.id_user_from_message=user.id OR messages.id_user_to_message=user.id)
WHERE user.id!=?
AND (wink.id_user_from_wink=? OR wink.id_user_to_wink=?)
AND wink.wink_confirmed='1'
results:
[2] => Array
(
[id_wink_table] => 18
[id_user_from_wink] => 8
[id_user_to_wink] => 6
[wink_confirmed] => 1
[wink_date] => 2016-07-07 07:19:09
[id] => 8
[points] => 4
[gender] => 0
[firstname] =>
[email] => testuser1#hotmail.com
[id_messages_table] => 5
[id_user_from_message] => 6
[id_user_to_message] => 8
[message_text] => hejsan ss
[message_confirmed] => 0
[message_date] => 2016-07-09 02:43:59
)
[3] => Array
(
[id_wink_table] => 18
[id_user_from_wink] => 8
[id_user_to_wink] => 6
[wink_confirmed] => 1
[wink_date] => 2016-07-07 07:19:09
[id] => 8
[points] => 4
[gender] => 0
[firstname] =>
[email] => testuser1#hotmail.com
[id_messages_table] => 4
[id_user_from_message] => 6
[id_user_to_message] => 8
[message_text] => halluy
[message_confirmed] => 0
[message_date] => 2016-07-09 02:38:13
)
You can see that id_user_to_message and id_user_from_message are dublicate the only thing that differs is the message_text. So i want only the latest matching record from the messages table
EDIT:
SELECT wink.*,user.id,user.points,user.gender,user.firstname,user.email
FROM wink
INNER JOIN user
ON (wink.id_user_from_wink=user.id OR wink.id_user_to_wink=user.id)
**LEFT JOIN HERE returning latest message from messages table and join all rows that is returned when this left join is not used**
WHERE
user.id!=?
AND
(wink.id_user_from_wink=? OR wink.id_user_to_wink=?)
AND
wink.wink_confirmed='1'
/*
create table wink (id_wink_table int, id_user_from_wink int, id_user_to_wink int,wink_confirmed int,wink_date datetime);
insert into wink values
(18, 8,6,1,'2016-07-07 07:19:09'),(18,8,6,1,'2016-07-07 07:19:09');
create table user (id int,points int,gender int,firstaname varchar(20), email varchar(40));
truncate table user;
insert into user values
(8,4,0,null,'testuser1hotmail.com'), (8,4,0,null,'testuser1hotmail.com');
create table messages (id_messages_table int,id_user_from_message int,id_user_to_message int,message_text varchar(20),message_confirmed int,message_date datetime);
truncate table messages;
insert into messages values (5,6,8,'hejsan ss',0,'2016-07-09 02:43:59')
,(4,6,8,'halluy',0,'2016-07-09 02:38:13');
*/
select * from wink;
select * from user;
select * from messages;
SELECT wink.*,user.id,user.points,user.gender,user.firstaname,user.email, m.*
FROM wink
left outer JOIN user ON wink.id_user_from_wink = user.id OR wink.id_user_to_wink = user.id
left outer join messages m on m.id_user_from_message=user.id OR m.id_user_to_message=user.id
where m.id_messages_table =
(select max(m1.id_messages_table) from messages m1 where m.id_user_from_message=m1.id_user_from_message OR m.id_user_to_message = m1.id_user_to_message)
Can help me, I have something problem about query select distinct, :
My table
table_pemesan
id_pms
table_pesan
no_psn
id_pms
table_dpesan
no_psn
My query mysql
select pm.id_pms,
pm.nama,
pm.date_create,
ps.no_psn,
ps.status,
dps.no_dpsn
FROM pemesan as pm
INNER JOIN pesan ps on ps.id_pms=pm.id_pms
INNER JOIN dpesan dps on dps.no_psn=ps.no_psn
ORDER BY pm.id_pms ASC
//output
Array
(
[0] => Array
(
[id_pms] => 1
[nama] => Isnan
[date_create] => 2014-05-28 23:54:54
[no_psn] => 1
[status] => sedang diproses
[no_dpsn] => 1
)
[1] => Array
(
[id_pms] => 1
[nama] => Isnan
[date_create] => 2014-05-28 23:54:54
[no_psn] => 1
[status] => sedang diproses
[no_dpsn] => 2
)
)
the array index 0 & 1 the same data, and my question how to distinct the query? thanks b4, sorry my english not good..
Try to use this query:-
SELECT DISTINCT pm.id_pms, pm.nama, pm.date_create, ps.no_psn, ps.status, dps.no_dpsn
FROM pemesan as pm
INNER JOIN pesan ps on ps.id_pms=pm.id_pms
INNER JOIN dpesan dps on dps.no_psn=ps.no_psn
ORDER BY pm.id_pms ASC