Match multiple columns from a form - php

I'm doing a price table, and I was wondering if there is a way to match multiple columns with different values base on the values from a form... please allow me.
Table: Price
id | name | color | class | year | price
________________________________________
1 | BMW | Red | XML | 2001 | 1200
2 | BMW | Red | XML | 2003 | 1201
3 | BMW | Blue | LXX | 2004 | 1230
4 | VW | Red | LXS | 2001 | 1100
5 | VW | Blue | LXV | 2003 | 1103
Basically my table looks like that, the idea is to get the price value by matching four columns...
if name is bmw and color is red and class is xml and year is 2001 then the price is 1200
How do I make that query?... I don't have any code for this type of query just yet... but I was thinking to do a few queries base on the first value....
SELECT * FROM price
WHERE name = '$user_query' AND (color = 'Red' OR class = 'XML' )
if [...] ... that just wont work...
I don't know how to do that query... I can go one by one matching the inputs from the form but I will have to make many queries... four queries actually... I'd love to simplified my query to get that value from column price base on the request from the user...
The other thing is to use switch case : value from the first query ... or use if, elseif .... r just IF ... that is because I know the values that the user will chose from the form and the form has only 4 selects ... one for each "column" name, color, class and year
You may think that I want you to do this for me... well yes and no... yes because I want to learn how to do this type of queries and NO because I have this combinations using IF's without a data base... I'd like to use a data base...
if ($name == 'bmw' && $color == 'red' && [...]) {
$price = 1200;
} [...] and so on...
about 23 elseif {} ...
Thank you for taking the time and share your thoughts on this idea...
** E D I T **
So far I have two good answers and I'm using both, and for that I have a bit of trouble choosing the right answer...
Mahmoud Gamal and Rajesh Paul
So I'm going to leave it like that for a few more days whichever gets more votes if any, thats the one that I'm going to choose...
Thank you.

if it's about reducing the query length then I suggest this-
SELECT * FROM price
WHERE (name, color, class) = ('$user_query', 'Red', 'XML' );
Just grouping the set of attributes instead of cascading the conditions using AND, OR definitely reduces the length of the query.

You must change the syntaxis
WHERE name = '$user_query' AND (color = 'Red' OR class = 'XML' )
WHERE name = '$user_query' AND color = 'Red' AND class = 'XML'

What you need here is a optional parameters in the WHERE clause:
SELECT *
FROM price
WHERE ($ColorPatam IS NULL OR Color = $ColorParam)
AND ($ClassParam IS NULL OR Class = $ClassParam)
...
If one of the parameters has a NULL values, then the expression is ignored.

Related

Create identification number in order and range delimited to registers

A have a list with many full names (>20000) and it increases with each new registration. I need create a seven digits identification number to every register in alphabetical order, so that the conversion start in 0100000 and finish in 9999999. This number must be based on the full name and your order.
When adding new names and that they are merged in the existing base, also generate new numbers merged too.
I have not yet been able to develop a good algorithm that solves this. Then I'll need to create a PHP script for this.
It is a conversion of names to numbers, but with a defined range.
For example
Anthony Felder : 0.459.789
Bianca Mall : 0.989.432
Danton Bishop : 2.986.999
Mario Cortez: 7.883.120
Paul Rudd: 8.788.454
Zeta Jones: 9.987.001
A new name inserted:
Augustus Novell : 0.589.223
Frederic Francis Ford Copolla : 3.765.453
You are going to run into problems, because eventually you are adding to many records that August zzzzzperson will get number 0.989.432 and that already exists.
If you don't expect TOO many new people being added, what you could do:
If Augustus Novell is added to your database - find out between which two names he should be placed (alphabetically).
Anthony Felder : 0.459.789
Bianca Mall : 0.989.432
Grab their numbers and get a number right in the middle of the two:
roundUp((0.459.789 + 0.989.432) / 2) = 0.724.611
As long as you leave a significant gap between each record at the start. In this example with this gap you can only do this 20 times when you keep adding a new name between Anthony Felder and the latest added name. Increasing the gap, increases the amount of times you can do this. But you have to DOUBLE the gap, just to get one additional name in there.
The limit of 20 is only if keep using the same name 20 times as the upper or lower limit. Would love to hear if there is a smarter algorithm, but I doubt it, without rebuilding indices. Taking the middle of two numbers makes sure you always have the biggest gap between two numbers. (not taking predictive models into account).
I don't like my solution of taking the average, but I think it may be the best solution. In other words, unless someone comes up with a better algo, I would try to sort your situation differently. For example, letting go of the need to make the numbers sequential to the alphabetical order of the names (I wonder why this is needed anyway)
EDIT: One other option. Map their name to a number
a = 01, b = 02, c = 03... z = 26, space = 27
Optional, space is a dot, but you can also put a dot every 3 letters (6 numbers)
That means 2 people with the same name would get the same number. You can solve this by having the first two numbers telling you which person it is.
So the first Anthony Felder would start with 01, second Anthony Felder with 02, third Anthony Felder with 03 etc and then start mapping the A (=01).
You have to define how to deal with other characters such as é .
This leads to numbers with variable lengths
This can lead to LONG numbers.
The limit is 99 people with the same name (or 100 if you start with 00)
Actually we can create your idea to code
but it need more time (You say that there are 20000 records)
$value = 100000;
$n= 100000 + $total_db_row; //find total name count from your db table
for( $i=100000; $i < $n; $i++ ) {
$a = str_pad($i, 7, '0', STR_PAD_LEFT);
$a = substr_replace( $a, '.', 1, 0 );
$id[] = substr_replace( $a, '.', 5, 0 );
}
//var_dump($id);
then ,after each insertion you should do...
mysql> SELECT * FROM ordered_names;
+----+-----------+----------+------------+
| id | firstname | lastname | sort_order |
+----+-----------+----------+------------+
| 1 | pamela | edwards | NULL |
| 2 | rolando | edwards | NULL |
| 3 | diamond | edwards | NULL |
+----+-----------+----------+------------+
3 rows in set (0.00 sec)
mysql>
Next, let's populate the sort order column:
SET #x = 0;
UPDATE ordered_names SET sort_order = (#x:=#x+1) ORDER BY lastname,firstname;
SELECT * FROM ordered_names;
Let's run that:
mysql> SET #x = 0;
Query OK, 0 rows affected (0.00 sec)
mysql> UPDATE ordered_names SET sort_order = (#x:=#x+1) ORDER BY lastname,firstname;
Query OK, 3 rows affected (0.00 sec)
Rows matched: 3 Changed: 3 Warnings: 0
mysql> SELECT * FROM ordered_names;
+----+-----------+----------+------------+
| id | firstname | lastname | sort_order |
+----+-----------+----------+------------+
| 1 | pamela | edwards | 2 |
| 2 | rolando | edwards | 3 |
| 3 | diamond | edwards | 1 |
+----+-----------+----------+------------+
3 rows in set (0.00 sec)
Then update php created array with where condition 'sort_order'.
foreach($i=0; $i < count($id); i++ )
{
$sql = "UPDATE ordered_names SET sort_order=.$id[$i]. WHERE sort_order=.$i.";
$db->query($sql);
}
it will update sort_order col with 0.100.100 to .....
But i repeat it need more execution time for larger records

display a list with the highest points appearing first

I am displaying a list of items where I want the highest point to appear first irrespective of how the data is sorted. At first the snippet that does the logic is working but when inputed with different variables as shown in the table structure, the expected logic output fails. Here is the entity structure
books.php
id | name | points | active
1 | huk | 5 | true
2 | foo | 2 | true
3 | doo | 2 | true
4 | jack | 12 | true
Here is my controller snippets
$restresults = $this->getDoctrine()
->getRepository('xxxBundle:Books')
->findBy(
['active' => true],
['points' => 'DESC']
);
the above snippets result is unpredictable from my coding intention, as it returns this result in sorting in respect to book points 5, 2, 2, 12 instead of 12, 5 , 2 , 2.
Please what could be wrong with my algorithm
Looking at sorting result it looks like the string type is sorted instead of int.
To fix that change the type of column points to int both in doctrine and db for example with #Column(type="integer") */ depending on your style of mapping.
The other way is to make DQL. If you can't do it then you need to make your own DQL
and write orderby there.
Ex.
$books = $em->getRepository('xxxBundle:Books')
->createQueryBuilder('q')
->addSelect('ABS(q.points) AS HIDDEN pointsOrder') // other way CAST(q.points AS UNSIGNED)
->orderBy('pointsOrder', 'DESC)
->getQuery()
->getResult();

Searching multiple values in sql table, with a range

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

Merge SQL database values when items have same value in specified column

I know how to solve this in a non-elegant, non-practical way, meaning sending requests, one by one, for each value in specified column that is shared and then handle all data from that specific output, then, do the same for another value, etc., etc. But I was wondering if someone out there thought of an ELEGANT and PRACTICAL way, which would mean all this is handled by one single PHP function.
Basically, I have this table:
location | title | description | quantity
============|===========|=============|==========
shelf | apple | red | 2
drawer | banana | yellow | 4
shelf | kiwi | green | 2
cupboard | lemon | yellow | 1
fridge | melon | orange | 3
drawer | peach | orange | 1
And what I eventually want is to create a jQuery pie chart that tells me what percentage of title is in each location. But before that I need a function that outputs shelf => 4 (2+2), drawer => 5 (4+1), etc., etc.
So, the question is, is there an elegant, practical way to make this happen? Meaning, to retrieve all rows but group together all data by location and, then, sum each location's quantity to be later on turned into a percentage for the pie chart?
Thanks!
select location, sum (quantity) as sum_quantity from table group by location;
and later using $rows as result from query above,
function prepareForChart ($rows) {
$ret = array();
$total = 0;
foreach ($rows as $el) $total += $el["sum_quantity"];
foreach ($rows as $el) {
$ret[] = array(
$el["location"] => $el["sum_quantity"],
"percentage" => 100 * $el["sum_quantity"]/$total,
);
}
return $ret;
}
This should work
SELECT location, SUM(quantity) as total_quantity
FROM table
GROUP BY location

Counting with PHP from a dynamictable

I'm not an expert in PHP even though I've been working with some stuff, copying and pasting from here and there, well I want to ask something that I can not find and that I don't have the slightest idea on how to implement it.
For instance, at a table like this:
+------+-----+
|NAME |BIRTH|
+------+-----+
|John |1980 |
|Carl |1982 |
|Alice |1990 |
|June |1994 |
|Rob |1998 |
|Alice |1998 |
|John |2000 |
|Alice |2001 |
|Etc. | |
+------+-----+
I do different queries, like these below (and I could keep doing queries with any combination of years):
Select * from table where BIRTH between 1980 and 1990
Select * from table where BIRTH between 1980 and 2001
Select * from table where BIRTH between 1990 and 2001
So I will get 3 different tables, and from those tables I need to count the different contents,
for instance, from the table obtained with the query1 I need to obtain:
John = 1
Carl = 1
Alice = 1
from table of query2:
John = 2
Carl = 1
Alice = 3
June = 1
Rob =1
from table of query3:
Alice = 3
John = 1
Carl = 1
June = 1
Rob =1
And remember the big table has 700 records, so it could appear any new name, and I need to print out the result in the same way:
Alice = 3
John = 1
NewName = 1
June = 1
Rob =1
My final goal is do percentages in relation to the obtained table, and not to the total of registers.
You should do it in SQL, not in PHP :
select NAME, count(1)
from TABLE
where condition
group by NAME
This will produce the exact view you want. Names as first column, the count on the second.

Categories