MySQL Joins and ORDER BY in PHP / MYSQL - php

I have a database that looks like this with two tables
Items
id | Title
-----------------------------
1 Bus
2 Plane
3 Jet
4 Shoes
5 Chair
Sorting
id | CatID | ItemID | SortOrder
-------------------------------------------------------------------------------
1 3 3 3
2 3 2 1
3 3 4 2
4 3 1 0
5 4 5 4
I can't figure out how to list the Titles of the ITEMS table based on the "SortOrder" Column of the SORTING table.
Here is what I tried so far:
SELECT *
FROM Items
LEFT JOIN Sorting ON Items.id = Sorting.ItemID
WHERE Sorting.CatID = 3
ORDER BY Sorting.SortOrder
I'm not sure what I'm doing wrong
EDIT
It looks like the MySQL query is correct, the problem is happening because when I output the $row['id'] of the Items Table it is incorrect. I have an Ajax PHP update that is updating the database based on the id of an li tag.
Any ideas why the $row['id'] is outputting incorrectly? I think it has something to do with the Items.id = Sorting.ItemID

This works as expected - SQLFiddle DEMO:
SELECT i.*, s.SortOrder
FROM items i, sorting s
WHERE i.id = s.ItemID
AND s.CatID = 3
ORDER BY s.SortOrder

Try
SELECT *
FROM Items
LEFT JOIN Sorting ON Items.id = Sorting.ItemID
WHERE Sorting.CatID = 3
ORDER BY Sorting.SortOrder ASC
add DESC or ASC in ORDER BY clause.
if you use ASC then sorted result will be 0 1 2 3 4 for SortOrder.
sample php code to get title
<?php
$query = mysqli_query(above_query)or die(mysqli_error());
while($result = mysqli_fetch_assoc($query))
{
echo $result['title']. '<br/>';
}

Related

Not getting required result after joining 2 tables

I have a view where i need to get list of all dishes from menu table according to main_menuid for a particular user, But here i need to put some conditions
Currently i am using 3 tables for the entire process (table view for all 3 is given at the end)
1) main_menu
2) menu
3) cart
1) I need to get list of dishes according to main_menuid
so here if i need a list of dishes below MM1, so list of dishes that i should get from menu table is (main_menuid is the id of main_menu table)
id main_menuid dish
1 1 D1
2 1 D2
3 1 D3
code i used to get the above data is
$sql = "select * from menu where main_menuid = '".$mainmenuid."'";
$result = mysqli_query($con, $sql);
if (mysqli_num_rows($result) > 0)
{
while($row = mysqli_fetch_assoc($result))
{
print_r($row);
}
}
2) i will also have a userid with me so now i need to display the above list to a particular user (Let the userid be "1"), but if he already has added any of the above product to cart earlier then it's quanity should also get fetched from cart and for rest of the items(that are not added by him to the cart but is present in the above list) the quantity will be null, so the resulting view should be like this (menuid is the id of menu table)
id main_menuid menuid dish quantity userid
1 1 1 D1 3 1
2 1 1 D2 2 1
3 1 1 D3 0 1
code that i tried for the above result is (but it didn't gave me the desired result)
SELECT menu.main_menuid, menu.dish, cart.userid,
cart.quantity
FROM menu
LEFT JOIN cart ON menu.id=cart.menuid
WHERE main_menuid = '".$main_menuid."' and userid = '".$userid."'
Below is a sample view of all the tables that are being used in the above process
main menu
id mainmenu_name
1 MM1
2 MM2
3 MM3
4 MM4
menu
id main_menuid dish
1 1 D1
2 1 D2
3 1 D3
4 2 D4
5 3 D5
6 4 D6
cart
id userid menuid dish main_menuid quantity
1 1 1 D1 1 3
2 1 2 D2 1 2
3 2 1 D1 1 3
can anyone please tell how to achieve the desired result (DBMS: mysql)
move userID to the join as it is eliminating the null values generated from the left join.
SELECT menu.main_menuid, menu.menuid, menu.dish, cart.userid,
cart.quantity
FROM menu
LEFT JOIN cart ON menu.id=cart.menuid
and userid = '".$userid."'
WHERE main_menuid = '".$main_menuid."'
However this implies you want some dishes not associated to the user so userID will be NULL in some cases.
Why does this work and not in the where clause? Because the filter is applied BEFORE the join. This allows the null values which would occur as a result of the left join to remain.
You can't get userid from your cart table directly, if the desired menu item is not in cart. So your WHERE clause filters out these records. Try this request:
SELECT menu.main_menuid, menu.menuid, menu.dish, IF(ISNULL(cart.userid), ".$main_menuid.", cart.userid) AS userid,
IF(ISNULL(cart.quantity), 0, cart.quantity) AS quantity
FROM menu
LEFT JOIN cart ON menu.id=cart.menuid
WHERE menu.main_menuid = '".$main_menuid."'
I think the problem is on the LEFT JOIN. You should do this way:
LEFT JOIN cart ON menu.id=cart.menuid and cart.dish = menu.dish
EDIT
When you do this way, the userid column will be null at the last line, to avoid this, on select you should put something like this:
SELECT menu.main_menuid, menu.dish,
COALESCE(cart.quantity, 0), -- will put 0 when null
COALESCE(cart.userid, '".$userid."') as userid -- will put '".$userid."' when null

" People Who Liked this Also Liked " Query in Mysql 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

get the last row of which one of its column value is less than the rows of interest within a set

This is kind of hard to explain so I'll break it down...Here's the objective
Suppose you have a table
ID | Weight
1 2
2 4
3 8
4 66
5 11
6 44
7 33
And suppose I have a set of interested IDs, say (3,4)
My objective is to get two other rows (one for each of the two interested IDs) such that the row that matches with the interested ID has a weight that is one level less than the weight of the interested ID
so in this case
for id 3, we want to return row with ID 2 and weight 4 since row id 2 is the first row of which the weight (4) is less than the weight of row id 3 (8)
for id 4, we want to return row with id 6 and weight 44 since row id 6 is the first row of which the weight (44) is less than the weight of row id 4 (66)
How would you accomplish this with mysql in one single query whereby we use the IN() notation for the interested IDs.....
I'd like to propose the following (used ourtable as table name obviously)
SELECT id,weight FROM ourtable WHERE weight IN (SELECT MAX(t.weight) FROM ourtable t,ourtable t2 WHERE t.weight < t2.weight && t2.id IN (3,4) GROUP BY t2.id);
it gives the following result
+----+--------+
| id | weight |
+----+--------+
| 2 | 4 |
| 6 | 44 |
+----+--------+
as requested.
You could solving this selecting the first row of a selection of the rows ordered by weight desc which weight is lower than the given weight, in this case for mysql something like:
select * from t where weight < (select weight from t where id = :id) order by weight desc limit 1
in a in statement following the idea above, you could have something like:
select * from (select id, (select weight from t where weight < (select weight from t where id = tp.id) order by weight desc limit 1) from t tp) a where id in (3,4)
Another solution w/o subquery:
select w1.id,w1.weight,
left(group_concat(w2.id order by w2.id desc ),LOCATE(',', group_concat(w2.id order by w2.id desc ))-1) as w2_id,
left(group_concat(w2.weight order by w2.weight desc ),LOCATE(',', group_concat(w2.weight order by w2.weight desc ))-1) as w2_weight
from weight as w1, weight as w2
where w2.weight < w1.weight
and w1.id in (3,4)
group by w1.id

PHP MySQL Joins

Is there a way I could somehow do the following?
Table ONE
id c_id type
-------------------
1 1 7
2 2 7
3 3 5
4 4 7
Table TWO
id title live
-------------------
1 row1 1
2 row2 0
3 row3 0
4 row4 1
The c_id column links the data from table ONE to table TWO. Example: in table ONE, if the c_id is 2, that row in table ONE will be directly linked to table TWO's row with id 2, which has a title of "row2".
I want to select from table ONE, everything with type 7, but only if their associated data in table TWO has live set to 1.
Here's how I thought I'd do it, but this doesn't seem to work:
SELECT * FROM ONE, TWO WHERE ONE.type='7' AND TWO.live='1' ORDER BY ONE.id DESC LIMIT 5
I would expect the above to return only rows 1 and 4 from table ONE, because although table ONE has three rows with type "7", only rows 1 and 2's associated row in table TWO have live set to 1.
You were close... try using an implicit join:
SELECT ONE.* FROM ONE, TWO WHERE ONE.type='7' AND TWO.live='1' AND ONE.c_id = TWO.id ORDER BY ONE.id DESC LIMIT 5
select * from one join two on c_id = two.id where type=7 and live = 1
order by one.id desc limit 5

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