Searching multiple values in sql table, with a range - php

I have a table that contains some ingredients. Example:
id | title | ingredients
1 | ex1 | ketchup, chicken, salt, honey, mountain dew
2 | ex2 | beef, pepper, chili, honey, salt
And when the user searchs for the ingredients like:
ketchup, salt, honey
I generate a sql-query:
select * from recipes where(
(ingredients LIKE '%ketchup%')
AND (ingredients LIKE '%salt%')
AND (ingredients LIKE '%honey%')
And it returns all recipes containing these specific ingredients, and it works grey.
Now. I've added a range-slider, to pick how many of the entered ingredients that should match for the search to return anything. Lets say i chose that 2 ingredients should match at least, i want to make a PHP function that outputs a sql string that pairs everyone of the entered ingredients, but i simply don't have the mindset for it.
Example:
(ingredients LIKE '%ketchup%') AND (ingredients LIKE '%salt%')
OR
(ingredients LIKE '%ketchup%') AND (ingredients LIKE '%honey%')
OR
So on. So ketchup & salt pair, ketchup & honey pair, salt & honey pair.
And of course variable so theres no limit to the ingredients inputted. I've tried for hours but no success. Hope i've explained my self clearly & someone will be able to help or teach me something :-)
My php function that does the current string looks like this:
$c_soeg = "ketchup, whatever, whatever. etc";
$c_ing_arr = explode(",", $c_soeg);
$c_count_arr = count($c_ing_arr);
$i = 0;
$c_sql = "SELECT * FROM recipes WHERE (";
while($i < $c_count_arr){
$c_sql .= "(ingredients LIKE '%".trim($c_ing_arr[$i])."%')";
if($i != $c_count_arr-1){
$c_sql .= " AND ";
}
$i++;
}
$c_sql .= ")";
And the variable that contains the value of the range is named
$c_range;

Instead of AND and OR conditions count the met criteria. This example gives you all records where at least two ingredients match:
select * from recipes
where
case when ingredients like '%ketchup%' then 1 else 0 end
+
case when ingredients like '%salt%' then 1 else 0 end
+
case when ingredients like '%honey%' then 1 else 0 end
> = 2;

I think you should make 3 tables meaning
one for the title and another for the ingredients and one to connect them
recipy
id | title |
1 | ex1 |
3 | ex2 |
recipyingredients
recipyid | ingredientsid
1 | 1
1 | 2
1 | 3
1 | 4
1 | 5
2 | 1
2 | 6
2 | 7
ingredients
id | ingredients
1 | ketchup
2 | chicken
3 | salt
4 | honey
5 | mountain dew
6 | beef
7 | pepper
In that case one recipy can have many ingredients and viceversa
The database would be clearer and you would not have to use like % as much.
Also you do not have to write the same ingredients every time for a recipy

Related

Count number of family members from one table for each rows in another table called house?

I have two MySQL tables, first, is house and second one family, The house table has two columns called house_id and house_name while the second table has three columns family_id, member_name the last column in the family table used to reference house_id from first table this is house_id
CONCEPT:
How can get number of family_members with/who come from a certain house and put the counted number in the HTML table by fetching only on house table?
I created the following script to fetch from house,
SELECT * FROM house;
And I manipulated the fetched data using foreach like this,
$mystmt = $db -> prepare('SELECT * FROM house');
$mystmt->execute();
$myresult = $mystmt->fetchAll();
foreach($myresult as $mydata) {
$myarray = array();
$myarray[] = $mydata['house_id'];
$myarray[] = $mydata['house_name'];
$output[] = $myarray;
}
echo json_encode($output);
On the above code i get only two columns the house_id and house_name, Now how can i adjust this code to count from family table so that I can get another column called total_family_members
Just like this
family_id | member_name | house_id
1 | John Jackson | 1
2 | Ketty Bebe | 2
3 | Maam Juke | 1
4 | Tike Nuke | 2
5 | Carol Michael | 2
Desired result
house_id | house_name | total_family_members
1 | Joh's house| 2
2 | kim's house| 3
In your example, two different processes are involved:
Link everyone's house id to the house name. This can be achieved with a JOIN.
Count the number of people in each house. This can be achieved with a GROUP BY and a COUNT.
Here is a solution:
SELECT house.house_id , house.house_name , COUNT( * ) AS total_family_members
FROM house
INNER JOIN family ON family.house_id = house.house_id
GROUP BY family.house_id

Array in where clause in mysql

i am developing an small application which disease after asking about symptoms,,php + mysql
my table is
i have an array of symptoms, i want to get disease that match to array symptoms
$a= array('fever','pain');
$sql=mysql_query("select * from disease where `d_symptoms` like '$a'");
already tryed using join and in
echo $v=join(',',$a);
$sql=mysql_query("select * from disease where `d_id` in ($v)");
please help me
you need to have a new table called symptoms, which includes a foreign key of the disease id (d_id) in your current table and the symptom name (d_symptom). Then each row will have the name of the symptom and the id of the disease it is linked with. That way you will not have multiple values in the symptom field. You then call it be selecting all symptoms where id='d_id' to get the list of symptoms associated with that disease.
the query might be
$a= array('fever','pain');
$sql=mysql_query("SELECT d_name FROM disease, symptoms WHERE disease.d_id = symptoms.d_id AND d_symptom IN ($a)";);
or something..
The correct answer is to properly normalize your database. You shouldn't use comma separated values (as suggested in comments). I am sure you can find many articles teaching normalization, so I won't go into details here.
You need to separate the symptoms from the diseases.
Diseases table
id | d_name
---------------------
1 | Dengu
2 | Typhoid
3 | Cervical
Symtoms table
id | s_name
---------------------
1 | Fever
2 | Pain
3 | Vomit
4 | Abc
5 | Xyz
Diseases-Symptom table (this is an intersection)
id | d_id | s_id
---------------------------
1 | 1 | 1
2 | 1 | 2
3 | 1 | 3
2 | 2 | 3
3 | 2 | 2
1 | 2 | 4
2 | 3 | 2
3 | 1 | 5
This way you don't create duplicate symptoms and makes your data easier to use and present, for example
SELECT id, s_name FROM symptoms
will give you a list of all symptoms available.
SELECT diseases.id, diseases.d_name, symptoms.s_name
FROM diseases
JOIN diseases_symptoms ON d_id = diseases.id
JOIN symptoms ON symptoms.id = diseases_symptoms.s_id
WHERE diseases.id = 1;
will give you a result similar to:
id | d_name | s_name
---------------------------
1 | Dengu | Fever
2 | Dengu | Pain
3 | Dengu | Vomit
You may use a single FIND_IN_SET for each symtoms you are looking for:
$query = "SELECT * FROM disease WHERE 1=1 ";
foreach($a as $row)
$query += "AND FIND_IN_SET($row, d_symptoms)";
$sql=mysql_query($query);
Well, you shouldn't store multiple values in a single column, as a best practice rule.(I really would fix that).
But, maybe something like this would work if you want to continue the way you have it:
$query = "select * from disease where d_symptoms like " . $a[0];
for($i = 1; $i < count($a); i++){
$query = $query + " AND d_symptoms like " $a[$i];
}
$sql=mysql_query($query);

Creating multivalue search, struggling with SQL

Based on user input, which could be a single or multiple values, and using the following table
+------+--------+
| seed | item |
+------+--------+
| 1 | apple |
| 1 | grapes |
| 2 | apple |
| 3 | grapes |
| 3 | banana |
+------+--------+
I want to return
1 when the user entered (apple, grape),
[1, 2] for (apple), and
nothing for (apple, banana).
My current PHP code
$keyword = Input::get('keyword');
$searchTerms = explode(",", $keyword);
$query = DB::table('items');
foreach($searchTerms as $term)
{
$query->where('item', 'LIKE', '%'.$term.'%');
}
$results = $query->distinct()->get(array('seed'));
works for single values. Iterating in the loop, I'm just appending more search terms to the current $query. At the end, I need to find the intersection of all the queries. This is currently my main concern.
With the input available try
SELECT seed
FROM Items
WHERE item IN ('apple', 'grapes')
GROUP BY seed
HAVING COUNT(item) >= 2
;
SELECT seed
FROM Items
WHERE item IN ('apple')
GROUP BY seed
HAVING COUNT(item) >= 1
;
SELECT seed
FROM Items
WHERE item IN ('apple', 'banana')
GROUP BY seed
HAVING COUNT(item) >= 2
;
The total to compare against in the HAVING clause is the count of items, you are checking in the respective batch.
SQL Fiddle
Please comment, if further detail or adjustment is required.

Is it possible to add more text to a text from MySQL?

Okay so I am trying to make this form for teams. Something like:
Football Club Name | W-W-L-D-W (W=win, D=draw, L=lose)
The way I thought I will do this is by adding text. For example, there is this match between FC Apple - FC Banana. Banana wins 0-1. In the team's row from the teams table, the "form" column is modified, adding "-W". Another match for Banana, with Kiwi, which they lose. Again adding "-L" to the column. So now the column is "-W-L". Is this possible?
I've thought about making 5 colums, lastmatch, lastmatch2, ... lastmatch5. When a team wins, lastmatch5 is W. If lastmatch4 is null and the team loses, lastmatch4 will be L. If all lastmatch columns are filled, then make lastmatch1 = lastmatch2, 2=3, 3=4, 4=5 , 5 = null, and its filled by the result.
But this is very complicated... Thats why I thought about the first method.
Any other methods? What do you think?
First, to answer your question, you could just grab the current content, like W-W-L-D, from the column, add the recent outcome, like -W, and then update the column with the new string - W-W-L-D-W. But I don't suggest doing it this way. Storing individual records in a long string is probably not the best idea. Instead, create separate relational tables. This is just off the top of my head, but I would consider doing something more like this:
Table: Football_club
+========================+
| Id | Name |
|---------|--------------|
| 1 | Apple |
| 2 | Banana |
| 3 | Kiwi |
+========================+
//This table stores each Football club's basic info
Table: Matches
+================================================+
| Id | Date | Team1_id | Team2_id |
|-------|-----------|-------------|--------------|
| 1 |2014-05-14 | 1 | 2 |
| 2 |2014-05-15 | 1 | 3 |
| 3 |2014-05-16 | 2 | 3 |
+================================================+
//This table stores basic info about each match.
Table: Match_outcomes
+==================================+
| Id | Match_id | Winner_id |
|-------|--------------|-----------|
| 1 | 1 | 2 |
| 2 | 2 | NULL |
| 3 | 3 | 3 |
+==================================+
//This table stores match outcomes.
//A winner ID of NULL would mean it was a draw (you could also use 0 or -1 or some other value that is not a team id)
This way, you can always get the number of wins, losses, and draws for any team, or add matches and match outcomes pretty easily.
For example, to get number of wins for team $id:
(I haven't tested this, but I think it would work)
SELECT
COUNT(mo.id) AS wins
FROM match_outcomes mo
JOIN matches m ON m.id = mo.match_id
AND (m.team_id1 = $id OR m.team_id2 = $id)
WHERE mo.winner_id = $id
GROUP BY mo.winner_id
Update - Been messing around with this... here's a sample query to get all wins, losses, and draws for each team using the above DB:
SELECT
fc.name,
SUM(IF(mo.winner_id=fc.id, 1, 0)) AS wins,
SUM(IF(mo.winner_id!=fc.id, 1, 0)) AS losses,
SUM(IF(ISNULL(mo.winner_id), 1, 0)) AS draws
FROM match_outcomes mo
JOIN matches m ON m.id = mo.match_id
JOIN football_clubs fc ON fc.id = m.team1_id
OR fc.id = m.team2_id
GROUP BY fc.name
See this SQL Fiddle
This is just a rough idea - hopefully it's helpful!

How to remove specific numbers from list MySQL

I have a comma separated list of numbers in a MySQL entry 'id_user' like so:
127,130,150,12,4,7,8,9
What is the best way to find a number in this comma-separated list and (1) remove it with the comma if it's with other numbers or (2) just remove itself if the number is by itself like:
127
Then update the MySQL entry.
So if I wanted to remove 150 from the list, it would be updated in the MySQL as:
127,130,12,4,7,8,9
I want to avoid trying to remove the id '12' but end up removing the '12's in numbers like 127 or 512
Thank you!
Reading between the lines, it sounds to me like you are storing a list of foreign keys in a comma-separated string field to represent a many-to-many relationship. This is not a good idea.
What you should do instead is create a table to store the relations.
For example, lets say you have a table called users and you want to store friend relationships between them. What you are doing is something like this (N.B. I realised this is actually not a great example as I wrote the end but I'm sticking with it for now):
id | name | friends
------+--------+-----------
1 | Dave | 2,4
2 | Bob | 1
3 | Tom | 4
4 | Bill | 1,3
Whereas what it's much better to do is something like this:
users
id | name
------+--------
1 | Dave
2 | Bob
3 | Tom
4 | Bill
friends
id | user | friend
------+--------+----------
1 | 1 | 2
2 | 1 | 4
3 | 2 | 1
4 | 3 | 4
5 | 4 | 1
6 | 4 | 3
To select Dave's friends you can do
SELECT u.*
FROM friends f
JOIN users u ON u.id = f.friend
WHERE f.user = 1
...and to delete the relationship between Dave and Bob (what you want to do here), you can simply do
DELETE FROM friends
WHERE (
user = 1 AND friend = 2
) OR (
user = 2 AND friend = 1
)
Using PHP:
$array = explode(',', $string);
$pos = array_search('127', $array);
unset($array[$pos]);
$string = implode(',', $array);
Or using MySQL:
REPLACE(column, '127,', '')
REGEX_REPLACE(column, '127$', '')
Get UDF REGEX_REPLACE - https://launchpad.net/mysql-udf-regexp with ^127$
In PHP:
$string="," . $string . ",";
str_replace("127,", "", $string);
Or you could split the string:
$list=explode(",",$string);
$new="";
foreach($list as $item){
if($item!="127"){
$new.=$item.",";
}
$new=substr_replace($new ,"",-1);
That should work.
As pyrate suggests try this in MySQL
TRIM(BOTH ',' FROM REGEX_REPLACE(column, '127\,?', ''))
using the UDF
Hope this helps

Categories