Advanced ORDER BY when searching - php

We have made a search field where you can search for multiple ingredients and find recipes.
We would like to sort the recipes according to the recipe with most ingredients from the search box.
if (isset($_POST['search'])) {
$searchquery = $_POST['search'];
$vals = "'" . str_replace(",", "','", $searchquery) . "'";
$query = mysql_query("SELECT * FROM opskrifter WHERE id IN
(SELECT opskrifterid FROM ingredienser WHERE ing_name IN ('$vals'))") or die("search failed");
Is it possible to sort them?
EDIT:
Recipe-table
+---------+----------+-------------+------------+------------+--+
| id | name | procedure | category | image_url | |
+---------+----------+-------------+------------+------------+--+
| 1 | Sausage | Fry it | Main dish | www....com | |
| 2 | Pizza | Bake it | Main dish | www....com | |
| 3 | Burger | Eat it | Main dish | www....com | |
+---------+----------+-------------+------------+------------+--+
Ingredient-table
+---------+----------+-------------+------------+------------+--+
| id | recipeid | ing_num | ing_meas | ing_name | |
+---------+----------+-------------+------------+------------+--+
| 1 | 1 | 1 | stack | sausage | |
| 2 | 2 | 200 | g | wheat | |
| 3 | 2 | 100 | g | beef | |
+---------+----------+-------------+------------+------------+--+
UPDATE
I've tried implementing the solution from Beginner/Raymond:
"SELECT *, COUNT(*) as `total_ingredients`
FROM opskrifter as k
, ingredienser as i
WHERE k.id = i.opskrifterid
AND i.ing_name IN ($vals)
GROUP BY k.id
ORDER BY COUNT(*) DESC"
Where $vals = "'" . str_replace(",", "', '", $searchquery) . "'";
and $searchsquery = $_POST['search']; //From the searchfield
Unfortunately the search only takes the first word into account, example:
"salt, pasta" it shows every recipe containing salt. But the recipe containing both ingredients is not the top sorted one.
What did I miss?

The answer below before me just missed a GROUP BY that's why it only returns one row
SELECT k.id
, k.name
, COUNT(*) as `total_ingredients`
FROM receipts as k
, ingredients as i
WHERE k.id = i.receipt_id
AND i.ing_name IN ('sausage','beef', 'wheat', 'sauce', 'flour', 'wheat', 'beef', 'ketsup', 'onion', 'garlic')
GROUP BY k.id, k.name
ORDER BY COUNT(*) DESC;
JS Fiddle Here

Jacob!
I think this query can solve your problem.
Please, try it.
SELECT k.id
, k.name
, COUNT(*)
FROM opskrifter k
, ingredienser i
WHERE k.id = i.opskrifterid
AND i.ing_name IN ('sausage','beef', 'wheat')
ORDER BY COUNT(*) DESC

Related

PHP SQL - Retrieve shared values from a another table not as expected

I'm needing to retrieve shared values from a table based on a value from another table, but don't show duplicates.
Example of what tables I have...
Table - members
+-----------------+
| ID | NAME |
+-----------------+
| 1 | Bob |
| 2 | Jack |
| 3 | Jane |
| 4 | Bruce |
| 5 | Clark |
| 6 | Peter |
+-----------------+
Table - groups
+--------------------------------+
| ID | NAME | MANAGER_ID |
+--------------------------------+
| 1 | Group A | 1 | (Bob)
| 2 | Group B | 2 | (Jack)
| 3 | Group C | 1 | (Bob)
+--------------------------------+
Table - group_members
+--------------------------------+
| ID | GROUP_ID | MEMBER_ID |
+--------------------------------+
| 1 | 1 | 3 | (Group A - Jane)
| 2 | 1 | 4 | (Group A - Bruce)
| 3 | 1 | 5 | (Group A - Clark)
| 4 | 1 | 6 | (Group A - Peter)
| 5 | 2 | 3 | (Group B - Jane)
| 6 | 3 | 4 | (Group B - Bruce)
| 7 | 3 | 5 | (Group C - Clark)
+--------------------------------+
What I am needing
(Note: I'm using * in queries here to shorten code.)
If 'Bob' sees all his groups.
Look at 'group_members' table and show all members that belong to it...
$q = SELECT * FROM groups WHERE manager_id = $id;
$r = mysqli_query($dbc, $q);
while ($row = mysqli_fetch-assoc($r) {
$q2 = SELECT *, count(MEMBERS_ID) AS group_count FROM group_members LEFT JOIN members ON group_members.MEMBER_ID = members.id WHERE group_id = '$row[GROUP_ID]';
$r2 = mysqli_query($dbc, $q2);
while ($row2 = mysqli_fetch-assoc($r2) {
echo $row2['name'];
}
}
This shows me the list as expected.
+------------------------+
| NAME | GROUP COUNT |
+------------------------+
| Jane | 1 |
| Bruce | 1 |
| Clark | 1 |
| Peter | 1 |
| Bruce | 1 |
| Clark | 1 |
+------------------------+
I Add GROUP BY group_members.group_id to my 2nd query and that shows.
+------------------------+
| NAME | GROUP COUNT |
+------------------------+
| Jane | 1 |
| Bruce | 2 |
| Clark | 2 |
| Peter | 1 |
+------------------------+
Which is perfect... But here is the problem
if I add a WHERE members.name LIKE \'%clark%\' then it outputs...
+------------------------+
| NAME | GROUP COUNT |
+------------------------+
| | |
| | |
| Clark | 1 |
| | |
| | |
| Clark | 1 |
+------------------------+
It ignores GROUP BY and shows blank rows where other entries would show.
So with all that said. Does any one know why or a better way to do this please?
Been at it for a while now and would really appreciate any assistance.
EDITED:
Here's the full query with all the columns used:
$q = SELECT * FROM groups WHERE manager_id = $id;
$r = mysqli_query($dbc, $q);
while ($row = mysqli_fetch-assoc($r) {
$q2 = SELECT members.id) AS memid, members.first, members.last, members.comname, members.email, members.sector, (members.status) AS memstatus, (group_members.id) AS groupid, (group_members.member_id) AS memidgroup, group_members.group_id, COUNT(group_members.member_id) AS groupcount, member_roles.role FROM members LEFT JOIN group_members ON members.id = group_members.member_id LEFT JOIN member_roles ON members.role_id = member_roles.id WHERE group_id = '$row[GROUP_ID]' AND members.name LIKE '%clark%' GROUP BY group_members.group_id;
$r2 = mysqli_query($dbc, $q2);
while ($row2 = mysqli_fetch-assoc($r2) {
echo $row2['name'];
}
}
Your query or problem is not completely stated. One cannot guess or assume.
Post your last query as well as all queries dont worry about saving the space.
Those blank rows have data that why they are in the table.
Base on your explanation or your query, here is my simple answer
SELECT id,
(select groups.id from groups where groups.id = group_members.group_id )AS group_members_id,
(select groups.name from groups where groups.id = group_members.group_id )AS group_members_name,
(select members.id from members where members.id = group_members.member_id )AS members_id,
(select members.name from members where members.id = group_members.member_id )AS members_name,
count((select members.id from members where members.id = group_members.member_id ) )as members_id_count FROM group_members WHERE (select members.name from members where members.id = group_members.member_id ) LIKE '%clark%' group by members_id
As you mentioned
WHERE members.name LIKE \'%clark%\'
you were selecting data from the members table whereas you have to select the data from group_members table.

Mysql query to join two table and group by matching id

Am trying to group user orders by the order id, but am not getting it right i know this will be first get done in the SQL query then organise it well in PHP and HTML but i don't know how to get it done.
orderinfo
oid | userid | total | payid
-----|---------|--------|----------
oi10 | peter | 650 | VCC-100
oi12 | john | 30 | VCC-500
oi15 | peter | 60 | COD-500
itemorder
pid | ioid | userid | price | qty | itemname
----| ------|---------|--------|-----|-----------
p10 | oi10 | peter | 200 | 1 | lexus
p20 | oi10 | peter | 150 | 1 | Toyota
p15 | oi10 | peter | 300 | 1 | Myvi
p66 | oi15 | peter | 25 | 2 | BMW
p67 | oi15 | peter | 10 | 1 | Saga
p67 | oi12 | john | 10 | 3 | Saga
My current Code
$handler->prepare('
SELECT * FROM itemorder io
LEFT JOIN orderinfo oi
ON io.oid = oi.ioid
WHERE io.userid = 'peter'
GROUP BY io.oid
ORDER BY oi.pid DESC
');
$handler->execute();
$RecentOrder = $handler->getAll();
$handler->free();
if(!empty($RecentOrder)){
foreach($RecentOrder as $row){
}
}
Expected Result
I want the result to be sorted according to the order id all item that has same order id will be listed (list according to order id).
oid: oi10
--------
lexus
Toyota
Myvi
---------------------
oid: oi15
--------
BMW
Saga
The desired output can be retrieved with just ORDER BY.
SELECT *
...
ORDER BY oi.oid DESC, io.pid DESC
And then do the specific formatting in PHP. Easiest way is probably to remember the order_id of the last row.
$lastOrderId = null;
foreach ($result as $row) {
if ($lastOrderId != $row['oid']) {
echo 'oid: ' . $row['oid'] . PHP_EOL;
echo ' -----------' . PHP_EOL;
}
echo ' ' . $row['itemname'] . PHP_EOL;
$lastOrderId = $row['oid'];
}
You can try this :
SELECT io.ioid,GROUP_CONCAT("",io.itemname) as order_items FROM itemorder as io
LEFT JOIN orderinfo as oi
ON io.ioid = oi.oid
WHERE io.userid = 'peter'
GROUP BY io.ioid
ORDER BY io.pid DESC
Please not the columns on which join is done.
Then in PHP you can use explode function to get the array of names for each order.
Hope this helps!

Mysql Remove Duplicates on Left Join 3 Tables using id

I have the following tables
hobbies
+----+-------------+---------------+
| id | employeeid | hobby_name |
+----+-------------+---------------+
| 1 | 123 | cooking |
| 2 | 123 | painting |
| 3 | 124 | dancing |
+----+-------------+---------------+
nonacad_recog
+----+-------------+---------------+
| id | employeeid | recog_name |
+----+-------------+---------------+
| 1 | 123 | Award1 |
| 2 | 123 | Award2 |
| 3 | 124 | Award3 |
+----+-------------+---------------+
org_membership
+----+-------------+---------------+
| id | employeeid | recog_name |
+----+-------------+---------------+
| 1 | 123 | Boyscout |
| 2 | 124 | Girlscout |
+----+-------------+---------------+
This is the query I used:
SELECT h.hobby_name,r.recog_name,o.org_name
FROM hobbies as h
JOIN nonacad_recog as r ON (h.employeeid=r.employeeid)
JOIN org_membership as o ON (r.employeeid=o.employeeid)
WHERE h.employeeid='123'
I am getting duplicate outputs:
+----+-------------+---------------------+
| hobby_name | recog_name | org_name |
+----+-------------+---------------------+
| cooking | Award1 | Boyscout |
| cooking | Award2 | Boyscout |
| painting| Award1 | Boyscout |
| painting| Award2 | Boyscout |
+----+-------------+---------------------+
What I want as an output is like this: with no duplicates
+----+-------------+---------------------+
| hobby_name | recog_name | org_name |
+----+-------------+---------------------+
| cooking | Award1 | Boyscout |
| painting| Award2 | NULL |
+----+-------------+---------------------+
also giving a null to the other columns/rows if there is nothing to return.
I might have missed out some things.
Is this possible to achieve using mysql queries?
Any solution to this?
If I get the correct table, it will be easy for me to
mysqli_fetch assoc the results and display it on a table using PHP.
The problem is that in the desired output you want to relate rows in your tables by non-existent column, which is a row number.
You can technically do it like this
SELECT MAX(CASE WHEN source = 1 THEN name END) hobby_name,
MAX(CASE WHEN source = 2 THEN name END) recog_name,
MAX(CASE WHEN source = 3 THEN name END) org_name
FROM
(
SELECT 1 source, id, hobby_name name, #n1 := #n1 + 1 rnum
FROM hobbies CROSS JOIN (SELECT #n1 := 0) i
WHERE employeeid = 123
UNION ALL
SELECT 2 source, id, recog_name, #n2 := #n2 + 1 rnum
FROM nonacad_recog CROSS JOIN (SELECT #n2 := 0) i
WHERE employeeid = 123
UNION ALL
SELECT 3 source, id, org_name, #n3 := #n3 + 1 rnum
FROM org_membership CROSS JOIN (SELECT #n3 := 0) i
WHERE employeeid = 123
ORDER BY source, id
) q
GROUP BY rnum
Output:
| HOBBY_NAME | RECOG_NAME | ORG_NAME |
|------------|------------|----------|
| cooking | Award1 | Boyscout |
| painting | Award2 | (null) |
Here is SQLFiddle demo
Here is an alternative solution. You pack all values as delimited strings with GROUP_CONCAT()
SELECT GROUP_CONCAT(DISTINCT hobby_name ORDER BY h.id) hobby_name,
GROUP_CONCAT(DISTINCT recog_name ORDER BY r.id) recog_name,
GROUP_CONCAT(DISTINCT org_name ORDER BY o.id) org_name
FROM
(
SELECT 123 employeeid
) e LEFT JOIN hobbies h
ON e.employeeid = h.employeeid
LEFT JOIN nonacad_recog r
ON e.employeeid = r.employeeid
LEFT JOIN org_membership o
ON e.employeeid = o.employeeid;
Output:
| HOBBY_NAME | RECOG_NAME | ORG_NAME |
|------------------|---------------|----------|
| cooking,painting | Award1,Award2 | Boyscout |
Here is SQLFiddle demo
and then in your client php code easily explode() column values while iterating over the resultset and build your presentation.
I think "Limit" can work:
SELECT h.hobby_name,r.recog_name,o.org_name
FROM hobbies as h,
nonacad_recog as r,
org_membership as o
WHERE h.employeeid='123'
AND r.employeeid=o.employeeid
AND h.employeeid=r.employeeid
LIMIT 1

I need to create a query using MySQL and PHP to get a result of two tables

I'm new to MySQL and PHP. I have two tables, one to hold all the company names and the other table has only the company name below the user:
Table 1
| # | Company name |
--------------------
| 1 | Microsoft |
| 2 | HP |
| 3 | Asus |
| 4 | Apple |
| 5 | Amazon |
| 6 | CCN |
table 2
| # | Company name | User name |
--------------------------------
| 1 | Asus | x1 |
| 2 | Apple | x1 |
| 3 | HP | x2 |
| 4 | Asus | x2 |
| 5 | Apple | x2 |
I need to create a query that achieves the following. First of all the companies are shown which are associated with a specific user (say Asus and Apple for user x1). After that, the remaining companies from table 1 are shown.
For example, the result of the query I'm looking for, for user X1 will display the rows in this way:
| # | Company name |
--------------------
| 1 | Asus |
| 2 | Apple |
| 3 | Microsoft |
| 4 | HP |
| 5 | Amazon |
| 6 | CCN |
How can I achieve this?
It looks like you want to include all companies, but for a given user, list the companies associated with that user first. If that's the case, you do not want to use an INNER JOIN.
Here's some SQL that should work. I've provided reasonable table and field names since you didn't give those. I'm also assuming that you have a reasonably sane table design with no duplicate rows.
SELECT c.company_name,
CASE
WHEN u.company_name IS NULL THEN 'N'
ELSE 'Y'
END AS user_has_company
FROM companies c
LEFT JOIN (
SELECT *
FROM users
WHERE user_name = 'x1'
) u
ON u.company_name = c.company_name
ORDER BY user_has_company DESC, c.company_name
This query will return an extra column - user_has_company. I'd use that to indicate whether the current user is associated with a given company, but you can ignore it if you want.
You will need a JOIN Statement to join another in the SELECT-Statement of table1
Quick example:
SELECT * FROM table2 INNER JOIN table1.id = table2.id WHERE table2.username = 'x1'
You'll find everything you need in the Documentation of JOINs.
http://dev.mysql.com/doc/refman/5.1/en/left-join-optimization.html
If you're just after the MySQL query for this then something like this would work
SELECT company_name,SUM(IF(user_name='x1',1,0)) as ordering
FROM `table2`
GROUP BY company_name
ORDER BY ordering DESC
But you should look at your schema before you go much further. If you have a column (company_name) in one table that refers to another table you should make that column refer to the PRIMARY KEY of the other table, i.e.
Table1
| # | company_name |
--------------------
| 1 | microsoft |
| 2 | hp |
| 3 | asus |
| 4 | apple |
| 5 | amazon |
| 6 | CCN |
table2
| # | company_id | user_name |
--------------------------------
| 1 | 3 | x1 |
| 2 | 4 | x1 |
| 3 | 2 | x2 |
| 4 | 3 | x2 |
| 5 | 4 | x2 |
This is one of the first things you learn in database design/normalisation. You will need to change your query in this case. Something like this:
SELECT company_name,SUM(IF(user_name='x1',1,0)) as ordering
FROM `table1`
LEFT JOIN `table2` ON table2.company_id=table1.id
GROUP BY company_name
ORDER BY ordering DESC
Create your query like this:
$sql = "SELECT b.companyName FROM table1 a INNER JOIN table2 b ON a.companyName = b.companyName WHERE b.userName = 'x1'";
Then, using PHP, use:
$con = mysql_connect("localhost","peter","abc123");
if (!$con)
{
die('Could not connect: ' . mysql_error());
}
mysql_select_db("my_db", $con);
$result = mysql_query($sql);
while($row = mysql_fetch_array($result))
{
echo $row['companyName'];
echo "<br />";
}
mysql_close($con);
Try this query:
SELECT company_name FROM table2 ORDER BY user_name ASC
In the HTML table, using PHP code:
$result = mysql_query(" SELECT company_name, user_name FROM table2 ORDER BY user_name ASC");
echo "<table>
<tr><th>Company Name</th><th>username</th></tr>";
while($row = mysql_fetch_array($result) {
echo "<tr><td>{$row['company_name']}</td><td>{$row['user_name']}</td></tr>";
}
echo "</table>"

Combining results on a MySQL INNER JOIN into one PHP array

I have two tables that I would like to join into one, but not all the fields. I've used INNER JOIN with some success, but can't get the exact results I need. Essentially, when using PHP to return results, I would like the key to be the 'meta_key' value.
Below are the two tables I want to combine:
USERS
+--------+-----------------+------------------+----------------+
| ID | username | first_name | last_name |
+--------+-----------------+------------------+----------------+
| 2 | hthompson | Hunter | Thompson |
| 7 | coak | Carol | Oak |
| 8 | delk | Dannie | Elk |
| 9 | mride | Mark | Ride |
| 10 | kken | Kyle | Ken |
| 11 | glee | Ginny | Lee |
| 12 | nwatts | Naomi | Watts |
| 13 | jwong | Jin | Wong |
| 14 | syin | Shen | Yin |
+--------+-----------------+------------------+----------------+
USERS_META
+--------+--------+-----------------+------------------+
| ID | UID | meta_key | meta_value |
+--------+--------+-----------------+------------------+
| 1 | 2 | business_name | Company Inc. |
| 2 | 2 | city | New York |
| 3 | 2 | state | NY |
| 5 | 9 | city | Boston |
| 6 | 9 | state | MA |
| 7 | 11 | business_type | Printer |
| 8 | 8 | chamber_member | true |
| 9 | 2 | business_type | Design |
+--------+--------+-----------------+------------------+
Below is an example of what I'd like to return:
USERS
+--------+-----------------+------------+------------+------------------+
| ID | username | city | state | business_name |
+--------+-----------------+------------+------------+------------------+
| 2 | hthompson | New York | NY | Company Inc. |
+--------+-----------------+------------+------------+------------------+
OR
$user['ID'] = 2
$user['username'] = hthompson
$user['city'] = New York
$user['state'] = NY
$user['business_name'] = Company Inc.
The closest I've come is this:
$query = ("SELECT *
FROM users
INNER JOIN users_meta ON users.ID = users_meta.UID
WHERE
users_meta.meta_key = 'city' OR
users_meta.meta_key = 'state' OR
users_meta.meta_key = 'business_name'
");
However, doing such returns three results for each unique user ID, and I'm aiming to returning one with all the meta info specified. The primary purpose of this is so that I will be able to search using a keyword, which would apply to the USERS.first_name, USERS.first_name and USERS_META.business_name columns and then obviously return results in a table showing ID, Business Name, City, State, First & Last Name.
Thanks in advance!
You can try this:
SELECT
u.ID,
u.username,
m0.meta_value as city,
m1.meta_value as state,
m2.meta_value as business_name
FROM
users u,
users_meta m0,
users_meta m1,
users_meta m2
WHERE
u.ID = m0.UID
AND m0.meta_key = 'city'
AND u.ID = m1.UID
AND m1.meta_key = 'state'
AND u.ID = m2.UID
AND m2.meta_key = 'business'
As far as getting the information out I would just suggest joining the table together and using php to make the array. Something similar to this:
<?php
//if search is blank, returns all rows
$search = isset($_POST['search'])?mysql_real_escape_string($_POST['search']):'';
//query for all rows with meta key/values including extra
//rows from the join. extra rows will be taken out later.
$result = mysql_query(
"SELECT
U.ID,
U.USERNAME,
U.FIRST_NAME,
U.LAST_NAME,
UM.META_KEY,
UM.META_VALUE
FROM USERS U
JOIN USERS_META UM ON U.ID=UM.UID
WHERE
UM.META_KEY IN ('city', 'state', 'business_name')
AND U.FIRST_NAME LIKE '%{$search}%'");
//an empty array to put our results into
$out = array();
//loop through the rows
while($row=mysql_fetch_assoc($out)){
//check if the user id has been added already
if(!isset($out[$row['ID']])){
//if not, add it with generic information
$out[$row['ID']] = array(
'ID'=>$row['ID'],
'USERNAME'=>$row['USERNAME'],
'FIRST_NAME'=>$row['FIRST_NAME'],
'LAST_NAME'=>$row['LAST_NAME']);
}
//add the meta key and value
$out[$row['ID']][$row['META_KEY']] = $row['META_VALUE'];
}
//display
echo '<pre>'.print_r($out,1).'</pre>';
?>

Categories