" People Who Liked this Also Liked " Query in Mysql PHP - php

Music table
id | title
1 Rap God
2 Blank Space
3 Bad Blood
4 Speedom
5 Hit 'em up
Like table
u_id | m_id
1 1
1 2
1 4
1 5
2 3
2 4
2 5
3 1
3 5
4 1
4 2
4 5
Now if someone visits music with m_id = 1
Then the output might be like
m_id
5
2
4
To explain this a bit...
As m_id = 1 is liked by users -> {1,3,4} which in turn likes ->{2,4,5} musics. Since m_id=5 is liked by max number of users its first followed by m_id = 2 and m_id = 4.
My Try
I queried the users who liked m_id = 1
SELECT u_id FROM likes WHERE m_id =1
Then i stored in in an array and selected each of their likes and
arranged them in desc order of count.
But it is a very slow and long process is there any way i can do this ?
p.s I have heard of Association Rules and Bayesian theorem can be user to achieve this. But can anyone help me out with an example ?

You can JOIN back on the Like table and do something like this.
SELECT also_like.m_id, COUNT(also_like.m_id)
FROM [like] AS did_like
JOIN [like] AS also_like ON
also_like.u_id = did_like.u_id
AND also_like.m_id != did_like.m_id
WHERE did_like.m_id = 1
GROUP BY also_like.m_id
ORDER BY COUNT(also_like.m_id)
Essentially you are getting a list of users who liked an item then getting a complete list of those user's likes excluding the item they just liked.
You can then add a HAVING clause or LIMIT to filter things down a bit more.

using a subquery ...
SELECT m_id, count(u_id) as Rank FROM `like`
WHERE u_id in
(
SELECT u_id
FROM `like`
WHERE m_id = 1
)
AND m_id <> 1
GROUP BY m_id
ORDER BY Rank DESC
and optionally
LIMIT 0, 10
or how many "alsolikes" you want to display

Related

Order by a columns count where another column has a static value

I have a table which stores user items, the two key columns which I would like to use in this query are user_id and item_id. The id field in the example is not needed but just added to show these aren't the only two columns in the table.
----------------------
id user_id item_id
----------------------
1 1 324
2 1 324
3 3 324
4 2 230
5 4 324
The query which I would like to construct should return the top 10 users who have the most items with a specific item id.
So for example if I wanted to run the query against the item ID 324 I should get the following result.
-------------------
user_id item_count
-------------------
1 2
3 1
4 1
2 0
try this
select user_id , count(*) as item_count from table
where item_id = 324 group by user_id order by item_count desc limit 10
limit 10 will show you the top 10 users and order by desc sort from high to low.
However, the above query will not give you the 0 count as per your question. If you really want the zero count you can try this: (assuming your table name is userlist)
SELECT distinct user_id,
(select
count(*) from `userlist`
where user_id=u.user_id and item_id=324
) as item_count FROM `userlist` u
order by item_count desc
I couldn't create the database in my local, but I think this will do the trick
SELECT user_id, COUNT(item_id) as item_count
FROM TABLE_NAME
WHERE item_id = 324
GROUP BY item_id
ORDER BY item_count;

Select Distinct from new tol old in same table

I have one table named:
thread_comment
Now the table is getting filled as followed:
thread_comment_id thread_id user_id thread_comment thread_comment_time
1 2 1 This is a comment 2016-09-14 15:30:28
2 4 1 This is a comment 2016-09-14 15:32:28
3 2 1 This is a comment 2016-09-14 15:33:28
4 5 1 This is a comment 2016-09-14 15:34:28
5 7 1 This is a comment 2016-09-14 15:35:28
6 2 1 This is a comment 2016-09-14 15:37:28
7 2 1 This is a comment 2016-09-14 15:40:28
I want to show the newest threads to my page. for example:
as number one i want thread_comment_id 7
as number two i want thread_comment_id 5
I skipped 6 because i don't want any duplicates in the list.
In order to do so i did the folowing:
$sql = "SELECT DISTINCT thread_id FROM thread_comment ORDER BY thread_comment_time DESC"
This is kind of working (Not showing any duplicates). However the order does not make any sense...
For example:
It goes like 5 - 6 -4 - 7 etc...
The column used in the ORDER BY isn't specified in the DISTINCT. You need to use an aggregate function and GROUP BY to make the DISTINCT work.
SELECT DISTINCT thread_id, max(thread_comment_id) FROM thread_comment GROUP BY thread_id ORDER BY max(thread_comment_id) DESC, thread_id
EDIT: added aggregate func max()
Also thread_id is not mandatory in the ORDER BY
It I understand correctly, you want one row per thread. Here is a way to do this:
select tc.*
from thread_comment tc
where tc.thread_date = (select max(tc2.thread_date)
from thread_comment tc2
where tc2.thread_id = tc.thread_id
);

MySql : Order by and Group By combining not giving the latest record

Using the following query I am looking for a solution to get the latest record that having some conditions.
But it gives me the first record, not the latest. I think its only considering the group by
Please advise me
SELECT * FROM `contacts` WHERE `id_receiver`=1 GROUP BY `id_thread` ORDER BY created DESC
id id_sender id_thread sender_email id_receiver created(datetime)
1 2 2 51 1 2012-03-24 13:44:48
2 4 4 1 5 2012-04-26 13:46:05
3 2 2 51 1 2012-04-09 12:12:30
Required output
id id_sender id_thread sender_email id_receiver created(datetime)
3 2 2 51 1 2012-04-09 12:12:30
I had done a test just swap the order by and group by , giving me an erros.
Anybody can just look in to this?. Thanks.
EDIT Edited question, forget to write id_thread
How can you GROUP BY id_thread when there is no id_thread column in your table?
SELECT *
FROM contacts
WHERE id_receiver = 1
--- GROUP BY id_thread
--- removed
ORDER BY created DESC
LIMIT 1 --- only show one row
Based on your comments, what you want is the latest (ordered by created) row for every id_thread, which is a different and more complex query. There's even a tag for this kind of queries, named [greatest-n-per-group].
SELECT c.*
FROM contacts AS c
JOIN
( SELECT id_thread, MAX(created) AS created
FROM contacts
WHERE id_receiver = 1
GROUP BY id_thread
) AS g
ON (g.id_thread, g.created) = (c.id_thread, c.created)
WHERE c.id_receiver = 1
if records goes sequential than you might SORT by id too -- if and only if it's created in sequential order --

Order by ID if two users have same number of credits

:-)
I have this script, which find a users position taken from the number of credits.
It all works, but i have a little problem. If two users have the same credits, both of them will be on the same position.
Can I do, so if there are more users with same credits, then the system need to order by the users ID and out from that give them a position?
This is my code so far:
$sql = "SELECT COUNT(*) + 1 AS `number`
FROM `users`
WHERE `penge` >
(SELECT `penge` FROM `users`
WHERE `facebook_id` = ".$facebook_uid.")";
$query_rang = $this->db->query($sql);
So if i have this:
ID -------- Credits
1 -------- 100
2 -------- 100
3 -------- 120
Then the rank list should be like this:
Number 1 is user with ID 3
Number 2 is user with ID 1
Number 3 is user with ID 2
ORDER BY credits DESC, id ASC. This will sort by credits and break ties with the id.
UPDATE
I understand now that you want the ranking information for the user, not just to sort the users by credits and ids. This will give you the complete list of users and their rankings:
SELECT #rank:=#rank+1 AS rank, users.id, users.facebook_id FROM users, (SELECT #rank:=0) dummy ORDER BY penge DESC, id ASC
Getting the row number is the tricky bit solved by this blog post:
http://jimmod.com/blog/2008/09/displaying-row-number-rownum-in-mysql/
$sql = "SELECT COUNT(*) + 1 AS `number` FROM `users` WHERE `penge` > (SELECT `penge` FROM `users` WHERE `facebook_id` = ".$facebook_uid.") ORDER BY COUNT(*) + 1 desc, users.ID";
$query_rang = $this->db->query($sql);
Later EDIT:
I don't understand why you still have the same results....
I made a quick test. I have created a table:
Test: ID (Integer) and No (Integer)
I have inserted some values:
id no
1 1
1 1
1 1
2 1
3 1
4 1
4 1
5 1
Now, if I run:
SELECT
id, COUNT(*) + 1 AS `number`
FROM
test
GROUP BY
id
I get:
id number
1 4
2 2
3 2
4 3
5 2
But if I add ORDER BY:
SELECT
id, COUNT(*) + 1 AS `number`
FROM
test
GROUP BY
id
ORDER BY
count(*) desc, id
then I get:
id number
1 4
4 3
2 2
3 2
5 2

Help with limiting a joined mysql database query

I have written a query which returns all records with some many-to-many joins correctly for the entire set or an individual article using WHERE a.id = ?
SELECT a.id, date_added, title, content, category_id, person_id, organization_id, c.name AS category_name, firstname, lastname, o.name AS organization_name
FROM articles AS a
LEFT OUTER JOIN articles_categories AS ac ON a.id=ac.article_id
LEFT OUTER JOIN categories AS c ON c.id=ac.category_id
LEFT OUTER JOIN articles_people AS ap ON a.id=ap.article_id
LEFT OUTER JOIN people AS p ON p.id=ap.person_id
LEFT OUTER JOIN articles_organizations AS ao ON a.id=ao.article_id
LEFT OUTER JOIN organizations AS o ON o.id=ao.organization_id
ORDER BY date_added
BUT!
I've hit a brick wall trying to work out how to limit the articles to a specific number of IDs, for working with pagination.
I'm ideally trying to use as simple and clear SQL statements as possible because I'm using the codeigniter framework with their active record class.
http://codeigniter.com/user_guide/database/active_record.html
Would really appreciate some help as I don't want to revert to using multiple queries for this as I've tried to reduce it down to a single query for database efficiency.
Have search around and tried some alternatives but nothing seems to work. Many thanks!
For example the results I return are like this
---------------------------------------------------------------------
id title category_id person_id organization_id
---------------------------------------------------------------------
1 test 1 1 1
1 test 2 1 1
1 test 1 2 1
1 test 1 1 2
1 test 5 1 1
1 test 8 1 1
1 test 1 4 1
1 test 1 4 2
1 test 1 1 1
2 test 2 2 1 1
2 test 2 1 2 1
2 test 2 1 1 2
2 test 2 5 1 1
2 test 2 8 1 1
2 test 2 1 4 1
2 test 2 1 4 2
I need the results like this so that I can create sub-arrays in the php like this:
$articles = $query->result_array();
$output = array();
foreach ($articles as $article) {
// set up article details
$article_id = $article['id'];
// add article details
$output[$article_id]['article_id'] = $article_id;
$output[$article_id]['date_added'] = $article['date_added'];
$output[$article_id]['title'] = $article['title'];
$output[$article_id]['content'] = $article['content'];
// set up people details and add people array with details if exists
if (isset($article['person_id'])) {
$person_id = $article['person_id'];
$output[$article_id]['people'][$person_id]['person_id'] = $person_id;
$output[$article_id]['people'][$person_id]['lastname'] = $article['lastname'];
$output[$article_id]['people'][$person_id]['firstname'] = $article['firstname'];
}
// set up organizations details and add organizations array with details if exists
if (isset($article['organization_id'])) {
$organization_id = $article['organization_id'];
$output[$article_id]['organizations'][$organization_id]['organization_id'] = $organization_id;
$output[$article_id]['organizations'][$organization_id]['organization_name'] = $article['organization_name'];
}
// set up categories details and add categories array with details if exists
if (isset($article['category_id'])) {
$category_id = $article['category_id'];
$output[$article_id]['categories'][$category_id]['category_id'] = $category_id;
$output[$article_id]['categories'][$category_id]['category_name'] = $article['category_name'];
}
}
But if I just use LIMIT (with offset etc) 1
the results I get are
---------------------------------------------------------------------
id title category_id person_id organization_id
---------------------------------------------------------------------
1 test 1 1 1
instead of
---------------------------------------------------------------------
id title category_id person_id organization_id
---------------------------------------------------------------------
1 test 1 1 1
1 test 2 1 1
1 test 1 2 1
1 test 1 1 2
1 test 5 1 1
1 test 8 1 1
1 test 1 4 1
1 test 1 4 2
1 test 1 1 1
which is my desired result.
OK, so finally I worked out how it is possible.
Thought i'd include it here in case anyone else has the same problem.
Changing this line
FROM articles AS a
to this
FROM (SELECT * FROM articles LIMIT 5,3) AS a
does what I wanted.
So, why don't you use OFFSET 0,10 and LIMIT *number_of_results* in the SQL Query? (if I understood the question)
Specific number of IDs... WHERE ID IN (2,4,6,8)... ?
Are you using codeigniter's pagination?
http://codeigniter.com/user_guide/libraries/pagination.html
You can easily limit the number of records that are being returned using the MySQL LIMIT clause. This can be achieved like the following with your sample query.
SELECT a.id, date_added, title, content, category_id, person_id, organization_id, c.name AS category_name, firstname, lastname, o.name AS organization_name
FROM articles AS a
LEFT OUTER JOIN articles_categories AS ac ON a.id=ac.article_id LEFT OUTER JOIN categories AS c ON c.id=ac.category_id
LEFT OUTER JOIN articles_people AS ap ON a.id=ap.article_id LEFT OUTER JOIN people AS p ON p.id=ap.person_id
LEFT OUTER JOIN articles_organizations AS ao ON a.id=ao.article_id LEFT OUTER JOIN organizations AS o ON o.id=ao.organization_id
ORDER BY date_added
LIMIT 10
Where 10 is the number of records you wish to display. The MySQL LIMIT clause allows you to specify a limit of the number of records and an initial offset. Like so:
LIMIT <offset>,<limit>
In your case <offset> would be the current page * the number of records on a page. <limit> would be the number of records you would like to display per page.

Categories