mySQL: How do I combine a search value with a variable? - php

I'm sure that there is a stupidly simple solution to this, but unfortunately my google-fu is too weak to find it.
I have a number of different tables for sizing, all following the same naming convention i.e size_001, size_002 etc. Within a loop I need to get the size entry that matches with the results already found.
Unfortunately there are no totally unique identifiers, as they repeat in each table (roman numerals for sizing). But they are unique in each individual table. So what I've tried so far looks a little bit like this:
SELECT * FROM CONCAT('size_00', '.$sizeTableID[$j].') WHERE sizeName LIKE '$sizeNames[$j]'"
Where $sizeTableId is a number from 1-9 and sizeName is a string e.g II or VI or, occasionally (because there's no consisitency), 2 etc
I've also tried ''$var'' inside the CONCAT and not using the CONCAT at all. Really I just need a way to join the database.size_00 and an integer variable.

If I understand correctly, this is actually simple:
$tablename = 'size00'.$sizeTableID[$j];
$sql = "SELECT * FROM $tablename WHERE sizeName LIKE '{$sizeNames[$j]}'";
and I think that solves it.

PHP is a bit quirky here.....
Try this one (when the variable is from an array/object, surround it with {})
$sql = "SELECT * FROM CONCAT('size_00', '{$sizeTableID[$j]}') WHERE sizeName LIKE '{$sizeNames[$j]}'";

Related

MySQL select only using first word of variable

I am using php and mySQL. I have a select query that is not working. My code is:
$bookquery = "SELECT * FROM my_books WHERE book_title = '$book' OR book_title_short = '$book' OR book_title_long = '$book' OR book_id = '$book'";
The code searches several title types and returns the desired reference most of the time, except when the name of the book starts with a numeral. Though rare, some of my book titles are in the form "2 Book". In such cases, the query only looks at the "2", assumes it is a "book_id" and returns the second entry in the database, instead of the entry for "2 Book". Something like "3 Book" returns the third entry and so forth. I am confused why the select is acting this way, but more importantly, I do not know how to fix it.
If you have a column in your table with a numeric data type (INT, maybe), then your search strategy is going to work strangely for values of $book that start with numbers. You have discovered this.
The following expression always returns true in SQL. It's not intuitive, but it's true.
99 = '99 Luftballon'
That's because, when you compare an integer to a string, MySQL implicitly does this:
CAST(stringvalue AS INT)
And, a cast of a string beginning with the text of an integer always returns the value of the integer. For example, the value of
CAST('99 Luftballon' AS INT)
is 99. So you'll get book id 99 if you look for that search term.
It's pointless to try to compare an INT column to a text string that doesn't start with an integer, because CAST('blah blah blah' AS INT) always returns zero. To make your search strategy work better, you should consider omitting OR book_id = '$book' from your search query unless you know that the entirety of $book is a number.
As others mention, my PHP allowed both numerical enties and text entries from the browser. My query was then having a hard time with this, interpreting some of my text entries as numbers by truncating the end. Thus, my "2 Book" was being interpreted as the number "2" and then being queried to find the second book in the database. To fix this I just created a simple if statement in PHP so that my queries only looked for text or numbers. Thus, in my case, my solution was:
if(is_numeric($book)){
$bookquery = "SELECT * FROM books WHERE book_id = '$book'";
}else{
$bookquery = "SELECT * FROM books WHERE book_title = '$book' OR book_title_short = '$book' OR book_title_long = '$book'";
}
This is working great and I am on my way coding happily again. Thanks #OllieJones and others for your questions and ideas which helped me see I needed to approach the problem differently.
Not sure if this is the correct answer for you but it seems like you are searching for only exact values in your select. Have you thought of trying a more generic search for your criteria? Such as...
$bookquery = "SELECT * FROM my_books WHERE book_title LIKE '".$book."' OR book_title_short LIKE '".$book."' OR book_title_long LIKE '".$book."' OR book_id LIKE '".$book."'"
If you are doing some kind of searching you might even want to ensure the characters before the search key are found as well like so....
$bookquery = "SELECT * FROM my_books WHERE book_title LIKE '%".$book."' OR book_title_short LIKE '%".$book."' OR book_title_long LIKE '%".$book."' OR book_id LIKE '%".$book."'"
The % is a special char that looks for allows you to search for the chars you want to search for PLUS any characters before this that aren't in the search criteri... for example $book = "any" with a % before hand in the query like so, '%".$book."'"`` would return bothcompanyand also the wordany` by itself.
If you need to you can add a % to the end also like so, `'%".$book."%'"`` and it would do the same for the beginning and end of the search key

LIKE Condition in PHP Not Work correctly

i have a row in my database with name "active_sizes" and i want filter my website items by size, for this, i use LIKE Condition in php :
AND active_sizes LIKE '%" . $_GET['size'] . "%'
but by using this code i have problem
for example when $_GET['size']=7.0 this code shows items that active_sizes=17.0
my active_sizes value looks like 17.0,5.0,6.5,7.5,,
thanks
Using comma-separated values in a single field in a database is indicative of bad design. You should normalize things, and have a seperate "item_sizes" table. As it stands now, you need a VERY ugly where clause to handle such sub-string mismatches:
$s = (intval)$_GET['size'];
... WHERE (active_sizes = $s) // the only value in the field
OR (active_sizes LIKE '$s%,') // at the beginning of the field
OR (active_sizes LIKE '%,$s,%') // in the middle of the field
OR (active_sizes LIKE '%,$s') // at the end of the field
Or, if you normalized things properly and had these individual values in their own child table:
WHERE (active_sizes_child.size = $s)
I know which one I'd choose to go with...
You don't state which DB you're using, but if you're in MySQL, you can temporarily accomplish the same thing with
WHERE find_in_set($s, active_sizes)
at the cost of losing portability. Relevant docs here: http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_find-in-set
You Have % signs around your $_GET value. Combined with LIKE, this means that any string that simply contains your get value will be retuned. If you want an exact match, use the = operator instead, without the percentage signs.
This will solve your immediate issue:
AND active_sizes LIKE '" . mysql_real_escape_string($_GET['size']) . "%'
If you are using the database other than MySQL, use corresponding escape function. Never trust input data.
Besides, I'd suggest using numeric field (DECIMAL or NUMERIC) for active_sizes field. This will accelerate your queries, will let you consume less memory, create queries like active_sizes BETWEEN 16.5 AND 17.5, and generally this is more correct data type for a shoe size.

Converting varchar into an int just for the search query?

What I've been trying to do is to select a row from a table while treating the varchar cells as int ones,
Here's a little explanation:
I have a table of phone numbers, some have "-" in them, some don't.
I wanted to select a number from the database, without including those "-" in the query.
So I used this preg_replace function:
$number = preg_replace("/[^0-9]/","",$number); //that leaves only the numbers in the variable
and then I run the following query:
"SELECT * FROM `contacts` WHERE `phone` = '{$number}'"
Now, of course it won't match sometimes since the number Im searching may have "-" in the database, so I tried to look for a solution,
on solution is just converting the cells into int's, but I'm not interested in doing that,
So after looking around, I found a MySQL function named CAST, used like : CAST(phone AS UNSIGNED)
I tried to mess with it, but it didn't seem to work.
Edit:
I kept looking around for a solution, and eventually used MySQL's REPLACE function for that.
"SELECT * FROM `contacts` WHERE REPLACE(phone,'-','') = '{$number}'"
Thank you all for your help.
MySQL doesn’t support extraction of regex matches.
You could try writing a stored function to handle it, but your best bet is to convert the data to ints so that all the numbers are uniform. I know you said you don't want to do that, but if you can, then it’s the best thing to do. Otherwise, you could do something like:
"SELECT * FROM `contacts` WHERE `phone` = '{$number}' OR `phone` = '{$number_with_dashes}'"
That is, search for the plain number OR the number with dashes.
1.
The easiest way to do it might be by using the REPLACE operator.
SELECT * FROM `contacts` WHERE REPLACE(REPLACE(`phone`, '-', ''), ' ', '') = '5550100';
What it does is simpy replacing all whitespaces and dashes with nothing, namely removing all spaces and dashes.
2.
Another alternative to solve the problem would be to use LIKE. If the phone numbers with a dash always are formatted the same way like 555-0100 and 555-0199 you can simple insert a %-sign instead of the dash. If your number may be formatted in different ways you can insert a %-between every character. It's not a beautiful solution but it does the trick.
SELECT * FROM `contacts` WHERE `phone` LIKE '555%0100';
or
SELECT * FROM `contacts` WHERE `phone` LIKE '5%5%5%0%1%0%0';
3.
You can use regular expressions. Since MySQL doesn't implement regex replace functions you need to use user defined functions. Have a look at https://launchpad.net/mysql-udf-regexp. It supports REGEXP_LIKE, REGEXP_SUBSTR, REGEXP_INSTR and REGEXP_REPLACE.
Edit: Removed my first answer and added some other alternatives.
I kept looking around for a solution, and eventually used MySQL's REPLACE function for that.
"SELECT * FROM `contacts` WHERE REPLACE(phone,'-','') = '{$number}'"

How can i query mysql with just numbers when a user may type in a suffix?

I have a function below which works perfectly, but now the client came back and asked that the number only be taken to do the search because most of his clients won't type in the suffix "h" or whatever it may be as per my example below:
38039 or 38039h
However he also said he only has one group of product codes which begin with "T" so they could be typing in "T760" in which case we would need the prefix.
My code below does a search on the exact product currently, can anyone help me work in these examples?
<?php
//Find Stock Value
function checkstock($prodCode) {
$prodCode = strtoupper($prodCode);
require '../../../../config.php';
$dbh = new PDO(DB_DSN, DB_USER, DB_PASS);
$sql = "SELECT * FROM isproducts WHERE prodCode = '".
$prodCode."' AND AllowSalesOrder = '1'";
$stmt = $dbh->query($sql);
$obj = $stmt->fetch(PDO::FETCH_OBJ);
$count = $stmt->rowCount();
echo ($count == 1 ?
ROUND($obj->FreeStockQuantity, 0) : 'Invalid product code '.$prodCode.'');
}
//Call Stock Function
checkstock($_POST['productcode']);
?>
Change the query to like below ?
SELECT * FROM isproducts
WHERE
(
prodCode='{$prodCode}' // for product with prefix or suffix
OR prodCode LIKE '{$prodCode}%' // without suffix
OR prodCode='T{$prodCode}' // without prefix
)
AND AllowSalesOrder = ''";
Wild-card by single character
OR prodCode LIKE '{$prodCode}_' // single character wild-card
It seems that you may have products with the same number but not the same suffix? like 8512n and 8512h ?
You could use LIKE '%$code%'
$sql = "SELECT * FROM isproducts WHERE prodCode LIKE '%".$prodCode."%' AND AllowSalesOrder = ''";
and I think its the more secure way in your case, so that all products containing the number will appear, regardless of suffix or prefix.
The above may return more than one product, so the user still has to choose which one it is he is actually looking for.
You can use % wild card for this kind of problem.
check this out....
http://www.w3schools.com/SQL/sql_wildcards.asp
it might be useful... :-)
In some of my code I use the following strategy:
# psuedo-code ... NOT intended for real use:
SELECT COUNT(*) FROM someTable WHERE someColumn = "{XXX}"
# If that returns exactly one than use the corresponding query
SELECT COUNT(*) FROM someTable WHERE someColumn LIKE "{XXX}"
# If that returns exactly one then use it
SELECT COUNT(*) FROM someTable WHERE someColumn LIKE "{XXX}%"
# If that returns exactly one then use it
SELECT COUNT(*) FROM someTable WHERE someColumn LIKE "%{XXX}%"
# If that returns exactly one then use it
... (where {XXX} is the placeholder for the user supplied search term).
The idea here is that I first try a precise match, then I try it under the assumption that the term already may contain SQL wildcards, then I try suffixing the % wild card and finally I try wrapping it with % wild cards.
At any point if I've found an unambiguous match then I use it. If I find more than one match at any point (not shown in the psuedo-code here) then I might throw an exception or I might return them or a subset of them based on the specifics of what I'm doing.
(In reality I'm using the parameter interpolation features of Python or Perl or sanitizing my inputs to allow wild cards while preventing SQL injections; so the code doesn't look like what I'm showing here. This is just to convey the general idea).
My goal is to allow my scripts to be called with the minimum unambiguous arguments supplied which sounds roughly similar to what your clients are requesting here.
From a usability perspective most users will get the first characters of any input right. So exact match following by suffixed wildcard match is most likely to succeed most of the time. In my case my users are likely to be familiar with SQL wildcards and may prefer to use them to construct their own unambiguous match; and logically that attempt has to be inserted before I start suffixing or wrapping it with my own wildcards.
This is why I use this specific sequence of matching attempts.

MySQL: How to search for spelling variants? ("murrays", "murray's" etc)

I want to search like this: the user inputs e.g. "murrays", and the search result will show both records containing "murrays" and records containing "murray's". What should I do in my query.pl?
What do you think about using the SOUNDEX function and the SOUNDS LIKE operator ?
That way, you can simply do:
SELECT * from USERS WHERE name SOUNDS LIKE 'murrays'
I'm pretty sure it doesn't work for every case, and perhaps it is not the most efficient way to solve the problem, but it could fit your needs.
This won't help if you absolutely need to do these queries in SQL, but if you can set up a Lucene search index for it, you gain a lot of this kind of "fuzzy search" functionality. Note though that Lucene is quite a complex topic by itself.
What you could do is create an extra field in the database, which contains the data with all special characters stripped from it, and search there. A bit lame, I know. Looking forward to see smarter answers ;)
Quick and dirty:
SELECT * FROM myTable WHERE REPLACE(name, '\'', '') = 'murrays'
I would first build a search column which has the text without punctuation and then search on that. Otherwise you'll have have to have a series of regular expressions to search against or check individual records in PHP for matching: both of which are computational intensive operations.
Maybe something like this: (untested!)
SELECT * FROM users WHERE REPLACE(user_name, '\'', '') = "murrays"
If this is for single word searching, you could try using Soundex or Metaphone functions? These would handle sounds-like as well as spelling
Not sure if MySQL has these, but PHP does (which would require separate columns to hold these values).
Otherwise, Richy's no-punctuation extra column seems best.
You could try adding a replace to your query like this
replace(name, '''','')
to temporarily get rid of the apostrophes for the match.
select name from nametable where name = replace(name,'''','');
This query should be able to pick up "murrays" or "murray's".
var inputStr = "murrays";
inputStr = String.Replace("'", "\'", inputStr);
SELECT * FROM ATable WHERE Replace(AField, '\'', '') = inputStr OR AField = inputStr
strip user input and names in database from all non-letter characters.
Use levenstein distance or soundex to find murrays with murray or marrays. This is optional but your users would love that.

Categories