SQL Query not completing correctly - not sure why - php

Alright,
I've got a multiple select dropdown on a page called week-select, its selections get passed via ajax to my php page.
I can get the data just fine, but when the query runs it doesn't complete appropriately.
I've got this:
//Deal with Week Array
$weekFilter = $_GET['week']; /*This is fine, if it's 1 week the query works great (weeks are numbered 12-15), but if it is 2 weeks the result is formatted like this 12-13 or 13-14-15 or whichever weeks are selected*/
$weekFilter = str_replace("-",",",$weekFilter); /*This works to make it a comma separated list*/
.../*I deal with other variables here, they work fine*/
if ($weekFilter) {
$sql[] = " WK IN ( ? ) ";
$sqlarr[] = $weekFilter;
}
$query = "SELECT * FROM $tableName";
if (!empty($sql)) {
$query .= ' WHERE ' . implode(' AND ', $sql);
}
$stmt = $DBH->prepare($query);
$stmt->execute($sqlarr);
$finalarray = array();
$count = $stmt->rowCount();
$finalarray['count'] = $count;
if ($count > 0) { //Check to make sure there are results
while ($result = $stmt->fetchAll()) { //If there are results - go through each one and add it to the json
$finalarray['rowdata'] = $result;
} //end While
}else if ($count == 0) { //if there are no results - set the json object to null
$emptyResult = array();
$emptyResult = "null";
$finalarray['rowdata'] = $emptyResult;
} //end if no results
If I just select one week it works great and displays the appropriate data.
If I select multiple options (say weeks 12, 14 and 15) it runs the query but only displays week 12.
When I manually input the query in SQL, how I imagine this query is getting entered - it runs and displays the appropriate data. So if I put SELECT * FROM mytablename WHERE WK IN ( 12, 14, 15 ) it gets exactly what I want.
I can't figure out why my query isn't executing properly here.
Any ideas?
**EDIT: I make the array from the multiple selections a string using javascript on the front end before it is passed to the backend.

Your resulting query with values probably looks like this with a single value in IN:
… WK IN ("12,14,15") …
Either use one placeholder for each atomic value:
if ($weekFilter) {
$values = explode(",", $weekFilter);
$sql[] = " WK IN ( " . implode(",", array_fill(0, count($values), "?")) . " ) ";
$sqlarr = array_merge($sqlarr, $values);
}
Or use FIND_IN_SET instead of IN:
$sql[] = " FIND_IN_SET(WK, ?) ";

I don't think you can bind an array to a singular ? placeholder. Usually you have to put in as many ? values as there are elements in your array.

If your HTML is correct and your week select has name="week[]", then you will get an array back with $_GET['week'];, otherwise without the [] it will only give you 1 value. Then, you're doing a string replace, but it's not a string. Instead, try this:
$weekFilter = implode(',', $_GET['week']);

Related

SQL query not working but works in PHPMyAdmin

I have a web application and I'm trying to modify one of the queries. The query fetches information (from a table named voyage_list) and returns various fields.
I want to modify the query so that it is based on certain filters the user applies (which will be placed in the URL).
I can't get the query to work in the web application, but if I copy the query and execute it directly within PHPMyAdmin, it works fine.
$vesselFilter = $_GET['vesselFilter'];
$vesselArray = explode(',', $vesselFilter);
$arrayCount = count($vesselArray);
$sqlExtend = ' status = 1 AND';
foreach ($vesselArray as $value) {
$i = $i + 1;
$sqlExtend .= " vesselID = '$value'";
if ($i < $arrayCount){
$sqlExtend .= " OR";
}
}
$newQuery = "SELECT * FROM voyage_list WHERE" . $sqlExtend;
echo $newQuery;
$query = $db->query($newQuery)->fetchAll();
I appreciate the above is pretty messy, but it's just so I can try and figure out how to get the query to work.
Any help would be greatly appreciated!
Thanks
That query probably doesn't return what you think it does. AND takes precedence over OR, so it will return the first vessel in the list if the status is 1, and also any other vessel in the list, regardless of status.
You'd do better to create a query with an IN clause like this:
SELECT * FROM voyage_list WHERE status = 1 AND vesselID IN(8,9,10)
Here's some code to do just that:
$vesselFilter = $_GET['vesselFilter'];
// Validate data. Since we're expecting a string containing only integers and commas, reject anything else
// This throws out bad data and also protects against SQL injection.
if (preg_match('/[^0-9,]/', $vesselFilter)) {
echo "Bad data in input";
exit;
}
// filter out any empty entries.
$vesselArray = array_filter(explode(',', $vesselFilter));
// Now create the WHERE clause using IN
$sqlExtend = 'status = 1 AND vesselID IN ('.join(',', $vesselArray).')';
$newQuery = "SELECT * FROM voyage_list WHERE " . $sqlExtend;
echo $newQuery;
$query = $db->query($newQuery)->fetchAll();
var_dump($query);

Foreach nested in a while loop with PDO query

To trim the fat so-to-speak in my script I decided to use 1 PDO prepare to span an array of predefined tables. The PDO executes in a while loop and within the while loop there is a foreach to build the output of each result set.
This is code for a search. The script currently searches 3 tables for results (through the while iterations). We will call them tables a, b, and c. For the tested search it finds 2 results in table a, 0 in table b, and 1 in table c.
Though it finds a total of 3 results it only displays 2. One from table 'a' and one from table 'c'. The script is not building the result from the second find in the table 'a'.
I have looked it over until my eyes bleed and searched for maybe something I have wrong, I cant figure it out. Any ideas of what is wrong with this code?
// --- Build an array of places to search
$tableArray = array("services", "webPages", "dsiu");
$tableCount = count($tableArray);
$count = "0";
$resCount = "0";
$result = "";
while ($tableCount > $count) {
// -- Search tables in the array for matches
$quotedString = $db->quote($searchString);
$qSQL = "SELECT title, ldesc, SUM(MATCH(title, sdesc, ldesc) AGAINST(:string IN BOOLEAN MODE)) AS score FROM ".$tableArray[$count]." WHERE MATCH (title, sdesc, ldesc) AGAINST (:string IN BOOLEAN MODE) ORDER BY score DESC";
$q = $db->prepare($qSQL);
$q->execute(array(':string'=>$quotedString));
// -- keep a count of the results
$rowCount = $q->rowCount();
if ($rowCount > 0) {
$resCount = $resCount + $rowCount;
// -- build result html
$html = $q->fetchAll(PDO::FETCH_ASSOC);
foreach ($html as $row) {
// --- Clean the results for display
$desc = cleanURL($row['ldesc']);
$desc = str_ireplace($searchString, '<b><font color="green">'.$searchString.'</font></b>', $desc);
$desc = substr($desc, 0, 300)."...";
$result .= "<font color='red'><b>".$row['title']."</b></font><br>".$desc."<br><br>";
}
}
$count++;
}
Thanks #dan08. I added a if ($row['score'] != null) { to the foreach. Also discovered that SUM() in the query was removing what should have been results.
This is now working with the changes.

PHP variable used in SQL

My code checks if there is $GET value, if not then assign ALL values of array.
Seems like simple thing,not sure why its not working.
if(isset($_GET["smonth"])) {$smonth= $_GET["smonth"];
}
else {$smonth =12;} working , but not what I want
else {$smonth =array (1,2,3,4,5,6,7,8,9,10,11) ;}
After that I would like to use it in SQL :
and d.month_of_year = '".$smonth."%'
That would be something like
and month_of_year = (all values of array) or 1 value)
My Question:
What would be best solution to check, if active month is available? If not, assign All months to query.Thank You
The built-in PHP functions of in_array and implode should solve your issue:
in_array('1', $_GET["smonth"]); // checks if January is in $_GET["smonth"]
implode("," , $_GET["smonth"]); // Pull all of the values out of $_GET["smonth"] as a A STRING
Try in your statement and d.month_of_year IN (" . implode(',', $smonth) . ")
= operator checks for single value. If you want to check multiple values, use in.
and d.month_of_year in (".$smonth.")
You also have a % there, which works with LIKE queries.
<?php
if(isset($_GET['month'])){
$month = date('m'); //This would give you the index of the current month.
$array = array('01','02','02');
$query = "select * from table where month = ";
if(in_array($month,$array)){
$query = "select * from table where month = '".$month."'";
//Then query here
}
else
{
$query = "select * from table";
$where = "";
foreach($month as $m){
$where .= ' month = "'.$m.'" and ';
}
//There would be a ending and pls just try remove it
$query .= $where;
// then query here
}
}
?>

Query returns different results between PL/SQL Developer and PHP

I have made a small intranet website to collect and store data to be used to expedite our logistics processes. I'm now in the process of adding search functionality which, if records are found that match that criteria, will allow the user to quickly select parts of that data to pre-populate a new shipping request with data (e.g, the user types 'Mar' in the Recipient Name input textbox and '109' in the Street Address input textbox and the query returns two records: {"Mary Smith", "1090 South Central St"} and {"Mark Swanson", "109 E. 31st St."}).
At the moment, when search criteria is entered and submitted, the data returned from the query in PHP is 100% accurate if and only if a single criteria is entered (such as Recipient Name). When I attempt to use two different search criterias in PHP, the record results do not match the results when running the same query in Oracle PL/SQL Developer. If three different search criterias are used, the query ran in PHP will return 0 records. In all three of the aforementioned scenarios, the query is executed without error in Oracle PL/SQL Developer.
The following code is from my PHP search function. The input data to this function is an associate array of field names and the user inputted search criteria data for that field.
public function Search()
{
if($this->dbcon)
{
$query = "SELECT * FROM ship_request ";
$postCount = count($this->post_data);
$counter = 0;
if ($postCount > 0)
{
$query .= "WHERE ";
}
foreach ($this->post_data as $k => $v)
{
$counter++;
if (strlen($v) > 0)
{
if ($k == 'SR_DATE')
{
$query .= $k . " = :" . $k . " AND ";
} else {
$query .= "upper(" . $k . ") like upper(:" . $k . ") AND ";
}
}
}
if (substr($query,-4) == "AND ")
{
$query = substr($query, 0, strlen($query) - 4);
}
$stid = oci_parse($this->ifsdb, $query);
foreach ($this->post_data as $k => $v)
{
if (strlen($v) > 0)
{
if ($k == 'SR_DATE')
{
$this->post_data[$k] = date("d-M-y", strtotime($this->post_data[$k]));
$placeHolder = $this->post_data[$k];
} else {
$placeHolder = '%' . $this->post_data[$k] . '%';
}
oci_bind_by_name($stid, $k, $placeHolder);
}
}
oci_execute($stid);
$nrows = oci_fetch_all($stid, $recordsFound);
$recordsFound = json_encode($recordsFound);
oci_free_statement($stid);
echo $recordsFound;
} else {
die("Could not connect to database!");
}
}
}
I've done a var_dump on $query to see what my query actually looks like when I enter multiple search criteria values. This is an example of what I see:
select * from HOL_SHIP_REQUEST where upper(sr_shipper_name) like upper(:sr_shipper_name) and upper(sr_recipient_name) like upper(:sr_recipient_name) and sr_recipient_phone like upper(:sr_recipient_phone)
That query returns 0 records when I enter "a" for Shipper Name, "m" for Recipient Name, and "2" for Phone Number.
This query, when executed in Oracle PL/SQL Developer, however, returns 27 records.
select * from HOL_SHIP_REQUEST where upper(sr_shipper_name) like upper('%a%') and upper(sr_recipient_name) like upper('%m%') and sr_recipient_phone like upper('%2%')
Is there something wrong with the way that I'm trying to bind the parameters in PHP? Is there something different I have to do when using multiple like statements?
You've forgotten the % wildcard chars in your built query string. The DB interface libraries do NOT parse the query you're building, and do NOT look for LIKE clauses - it's not their job to guess what kind of match you're trying to do. e.g. are you doing
WHERE a LIKE 'b'
WHERE a LIKE 'b%'
WHERE a LIKE '%b'
WHERE a LIKE '%b%'
It's up to you to provide the appropriate wildcards, and since you're using placeholders, you'll have to do it yourself, e.g.
WHERE UPPER(sr_shipper_name) LIKE CONCAT('%', :sr_shipper_name, '%')
If you were to do it something like this:
$shipper = '%foo%';
WHERE ... LIKE :shipper
you'd end up with the equivalent of:
WHERE ... LIKE '\%foo\%'
The placeholder system also doesn't parse your provided text and try to figure out if you're really trying to use a wilcard or just passing in a literal % char. That's why you have to use the CONCAT hack to build a proper wildcarded construct.

mysql PHP query question

Ok, i have a problem here...
I am sending values of drop down lists via ajax to this PHP file.
Now I want to search a mysql database using these values, which I have managed to do, BUT, only if I set the values to something...
Take a look:
$query = "SELECT * FROM cars_db WHERE price BETWEEN '$cars_price_from' AND '$cars_price_to' AND year BETWEEN '$cars_year_from' AND '$cars_year_to' AND mileage BETWEEN '$cars_mileage_from' AND '$cars_mileage_to' AND gearbox = '$cars_gearbox' AND fuel = '$cars_fuel'";
now, what if the user doesnt select any "price_from" or "year_from"... The fields are only optional, so if the user doesnt enter any "price from" or "year from", then the user wants ALL cars to show...
Do I have to write a query statement for each case or is there another way?
I do something similar to davethegr8 except I put my conditions in an array and then implode at the end just so I don't have to worry about which conditions got added and whether I need to add extra AND's.
For example:
$sql = "SELECT * FROM car_db";
// an array to hold the conditions
$conditions = array();
// for price
if ($car_price_from > 0 && $car_price_to > $car_price_from) {
$conditions[] = "(price BETWEEN '$cars_price_from' AND '$cars_price_to')";
}
elseif ($car_price_from > 0) {
$conditions[] = "(price >= '$cars_price_from')";
}
elseif ($car_price_to > 0) {
$conditions[] = "(price <= '$cars_price_from')";
}
else {
//nothing
}
// similar for the other variables, building up the $conditions array.
// now append to the existing $sql
if (count($conditions) > 0){
$sql .= 'WHERE ' . implode(' AND ', $conditions);
}
You could simply detect which parameters are missing in your PHP code and fill in a suitable default. eg
if (!isset($cars_mileage_to))
$cars_mileage_to = 500000;
You can build you query, adding the "where" part only if your variables are different from "".
or if you're using mysql 5.x, you can also use subselects:
http://dev.mysql.com/doc/refman/5.0/en/subqueries.html
don't forget to validate the input. It's trivial with firebug, for example, to inject some tasty sql.

Categories