I am creating a PHP function that will take some values, one of which is an array, that I need to use in a MySQL query.
I am creating the array as follows:
$newsArray = createArticleArray(array(2,20,3),5);
Then the function looks something like this (cut down for readability)
function createArticleArray($sectionArray = array(1),$itemsToShow)
{
$SQL = "
SELECT
*
FROM
tbl_section
WHERE
(tbl_section.fld_section_uid = 2 OR tbl_section.fld_section_uid = 20 OR tbl_section.fld_section_uid = 3)
ORDER BY
tbl_article.fld_date_created DESC LIMIT 0,$itemsToShow";
}
The section tbl_section.fld_section_uid = 2 OR tbl_section.fld_section_uid = 20 OR tbl_section.fld_section_uid = 3 is where I need to use the array values.
Basically I need to loop through the values in the array making up that part of the query, however I am having a little problem on how to show or not show the "OR" bits of it as there might be only 1 value or as many as I need.
I was thinking of something like this:
foreach($sectionArray as $section)
{
$sqlString = $sqlString . "tbl_section.fld_section_uid = $section OR";
}
but I don't know how to work out if to put the "OR" in there.
Use implode.
$conditionParts = array();
foreach($sectionArray as $section){
$conditionParts[] = "tbl_section.fld_section_uid = $section";
}
$sqlString .= implode(' OR ', $conditionParts);
This solution answers your question and show you how to use the implode function, but for your specific case you should really use the IN operator.
$sqlString .= "tbl_section.fld_section_uid IN(".implode(',', $sectionArray).")";
One solution is to put an extraneous 0 at the end to consume the final "OR" without any effect. The query parser will just remove it: A OR B OR C OR 0 is turned into A OR B OR C.
Another solution is to use implode to insert the OR:
$sqlString = "tbl_section.fld_section = "
. implode($sectionArray," OR tbl_section.fld_section_uid = ");
Of course, the correct solution is just to use IN:
"WHERE tbl_section.fld_section_uid IN(".implode($sectionArray,',').")";
The query can be made simpler and easier to generate if you use WHERE <column> IN (value1,value2,...) syntax.
Use PHP's implode to produce the (value1,value2,...) part:
$SQL .= ' WHERE tbl_section.fld_section_uid IN (' . implode(',', $array) . ') ';
Yields something like this:
SELECT
...
WHERE tbl_section.fld_section_uid IN (2,20,3)
...
Use PDO's prepare method: http://uk3.php.net/manual/en/pdo.prepare.php
$statement = $pdo->prepare("
SELECT
*
FROM
tbl_section
WHERE
(tbl_section.fld_section_uid = ? OR tbl_section.fld_section_uid = ? OR tbl_section.fld_section_uid = ?)
ORDER BY
tbl_article.fld_date_created DESC LIMIT 0,$itemsToShow");
$statement->execute( $sectionArray );
function createArticleArray($sectionArray = array(), $itemsToShow) {
$conditions = array();
for ($i = 0, $s = count($sectionArray); $i < $s; ++$i) {
$conditions[] = 'tbl_section.fld_section_uid = ' . (int) $sectionArray[$i];
}
$SQL = 'SELECT * FROM tbl_section WHERE ' . implode(' OR ', $conditions) . ' ORDER BY tbl_article.fld_date_created DESC LIMIT 0, ' . (int) $itemsToShow;
}
Related
I have a a form which let's the user select what they want to display. Now the results of this looks like that: 9, 10, 11. These are IDs from the table.
These are the IDs of the type they what to show. I have my query already, but I want to add this part at the end of my query.
So in this case:
$query = "type_ID = $result1 or type_ID = $result2 or type_ID = $result3"
if printed out with echo:
type_ID = 9 or type_ID = 10 or type_ID = 11
How can I achieve this?
I tried to loop and it,however this did not work and I am confused how to do add the MySQL code to this.
$result = $result . $_GET['type_ID'][$i]
I'm a tad unsure of what it is you are trying to achieve but from what I understand this should do it:
<?php
$tID = $_GET['type_ID'];
$query = 'SELECT * FROM table WHERE';
$i = 0;
foreach($tID AS $id){
if($i == 0){
$query .= ' type_ID = ' . $id;
$i++;
}else{
$query .= ' OR type_ID = ' . $id;
}
}
Although if you are only looking for the type_ID I'd still recommend using IN() like so:
<?php
$tID = $_GET['type_ID'];
$query = "SELECT * FROM table WHERE type_ID IN (" . implode(',',$tID) . ")";
In works just like OR, just instead of having to write multiple OR you can just use a single IN() :)
Have you try this ?
$sql = "SELECT * FROM table WHERE ".$query;
I need to do a sql query in php for search some entries (so using WHERE). But the field used to search could be of variable number.
I have a page with a search form, with 4 Field. It sends via POST the fields to a search.php that make a query:
$gomme_sql = $data->query("SELECT * FROM table WHERE parameter1 = '$_POST['name1']' AND parameter2 = '$_POST['name2']' ORDER BY id ASC");
But I don't know which field are filled. So, if I don't enter anything in field1 from the search form, I shouldn't have parameter1 = '$_POST['name1']' in the WHERE query.
Have you any idea how to obtain this?
Thank you
You can check the post data before appending that clause to the query in a way like this:
edit: adding additional check:
$sql="select something from someTable ";
if(!empty($_POST['name1']) || !empty($_POST['name2'])) // add as many as you like
{
$sql.=" where ";
if(!empty($_POST['name1']))
{
$sql.="parameter1= $_POST['name1']";
}
// etc etc...
}
$sql.=" ORDER BY id ASC";
and so on.
Having said that, please, please use prepared statements with this sort of input from the user. This is SUPER open to sql injection. Please do read this: How can I prevent SQL injection in PHP?
You can write generic sql select function like this , if you need more complex SQL just modify it.
<?php
function sqlSelect($table, $sel, $wh = '', $groupby = '', $order = '', $add = '') {
$tb = $table;
if (is_array($table)) {
$tb = implode(',', $table);
}
if ($wh) {
if (is_array($wh)) {
$w = array();
foreach ($wh as $k => $v) {
$v = mysqli_real_escape_string($v);
if (is_null($v))
$w [] = "$k=null ";
else
$w [] = "$k ='$v'";
}
$wh = 'where ' . implode(' and ', $w);
}else {
$wh = "where $wh";
}
}
if ($groupby)
$groupby = "group by $groupby";
if ($order)
$order = "order by $order";
$sql = "select $sel from $tb $wh $groupby $order $add ";
return $sql;
}
//set _GET as this is console test
$_GET['name1']='Bob';
$where = array(
'name1'=>$_GET['name1']
);
echo sqlSelect('sometable' , '*' , $where) ."\n";
// select * from sometable where name1 ='Bob'
//or some complex stuff
echo sqlSelect('persons', "age,status" , array('name'=>'Maria' , 'likes'=>'PHP') , null, 'age' , 'limit 20');
//select age,status from persons where name ='Maria' and likes ='PHP' order by age limit 20
When you need to do something like this:
SELECT * FROM userinfo WHERE id in (18,2,6,4,5)
And the id array comes from another query like:
$ids = $conn->fetchAll('SELECT origin from action WHERE url = "'.$url.'" AND SUBSTRING(origin,1,3)<>"pct" GROUP BY origin');
If I need to parse the array in order to give the right format to the query id do:
$norm_ids = '(';
foreach ($ids as $ids) {
$norm_ids .= $ids['origin'] .',';
}
$norm_ids = substr_replace($norm_ids ,"",-1) .')';
That outputs the ids like: (id1,id2,id3,id.......), so the I'll just: FROM userinfo WHERE id in ". $norm_ids;
But seems to ugly to me, is there a way to do this better?
You could do:
$idStr = rtrim(str_repeat('?,', count($ids), ',');
$query = 'SELECT * FROM userinfo WHERE id in (' . $idStr . ')';
and then use prepare():
$conn = $db->prepare($query);
$conn->execute($ids);
$res = $conn->fetchAll(...);
SELECT * FROM user_info WHERE id IN (SELECT origin from action ......) ....
Do you need the id's separate or can you combine them into 1 query?
perhaps something like:
SELECT * FROM userinfo WHERE id in (SELECT origin from action WHERE url = "'.$url.'" AND SUBSTRING(origin,1,3)<>"pct" GROUP BY origin');
this way you let the sql server do the work.
When i am faced with such situations, i use trim
$norm_ids_str = '';
foreach ($ids as $ids) {
$norm_ids_str .= $ids['origin'] .',';
}
$norm_ids = '(' . trim($norm_ids_str, ',') . ')';
I know this has been asked 1000 times, but for some reason I continue to bang my head agains the wall..
This works:
$sql = 'SELECT a.eventCode, a.eventTime, a.teamCode, a.playerCode, b.lastName, b.firstName, b.number, a.xCoord, a.yCoord, a.id ';
$sql = $sql . 'FROM events a, players b ';
$sql = $sql . 'WHERE a.regGUID in ( ' . $regGUID . ' ) and ';
$sql = $sql . 'a.playerCode=b.playerCode and a.gameCode = "' . $game . '" order by a.eventTime desc, a.actionCode asc';
$stmt = $db->prepare($sql);
$results = $stmt->execute();
This Doesn't:
$sql = 'SELECT a.eventCode, a.eventTime, a.teamCode, a.playerCode, b.lastName, b.firstName, b.number, a.xCoord, a.yCoord, a.id ';
$sql = $sql . 'FROM events a, players b ';
$sql = $sql . 'WHERE a.regGUID in ( :regGUID ) and ';
$sql = $sql . 'a.playerCode=b.playerCode and a.gameCode = :game order by a.eventTime desc, a.actionCode asc';
$stmt = $db->prepare($sql);
$stmt->bindValue(':regGUID', $regGUID, PDO::PARAM_STR);
$stmt->bindValue(':game', $game, PDO::PARAM_STR);
$results = $stmt->execute();
What am I missing? Thanks
The problem is here:
$sql = $sql . 'WHERE a.regGUID in ( :regGUID ) and ';
$stmt->bindValue(':regGUID', $regGUID, PDO::PARAM_STR);
I assume $regGUID is a comma-separated list of quoted strings.
Each query parameter accepts only a single scalar value. Not lists of values.
So you have two choices:
Continue to interpolate the $regGUID string, even if you use parameters for other scalar values. But you still want to be careful to avoid SQL injection, so you must form the $regGUID string correctly. You can't just call PDO::quote() on the whole string, that would make it a single quoted string containing UUIDs and commas. You have to make sure each UUID string is escaped and quoted individually, then implode the list together and interpolate it into the IN clause.
$regGUIDs = explode(',', $regGUID);
$regGUIDs = array_map(function ($g) { return $db->quote($g); }, $regGUIDs);
$regGUID = implode(',', $regGUIDs);
$sql = $sql . 'WHERE a.regGUID in (' . $regGUID . ') and ';
explode() the $regGUID into an array, and add one query parameter for each element in the array. Interpolate the dynamic list of query parameter placeholders.
$regGUIDs = explode(',', $regGUID);
$params = array_fill(1, count($regGUIDs), '?');
$sql = $sql . ' WHERE a.regGUID in ( ' . implode(',', $params) . ' ) and ';
You could bindValue() in a loop for the array, but keep in mind that other parameters should also be bound by position, not by name. PDO has bugs that make it not happy when you try to mix the two different styles of parameters in the same query.
Instead of using bindValue() I just pass an array of parameter values to PDOStatement::execute(), which is much easier.
$paramValues = $regGUIDs;
$paramValues[] = $game;
$results = $stmt->execute($paramValues);
This indeed has been asked 1000 times.
Prepared statements can only accept scalar values, not arbitrary parts of the SQL query.
You have to form IN() statement using as many placeholders, as many items you have to put in and then bind them one by one.
To ease this task one can use some helper function.
Say, using SafeMysql library this code could be written as
$sql = 'SELECT * FROM events a, players b WHERE regGUID in (?a) and';
$sql .= ' a.playerCode=b.playerCode and a.gameCode = ?s';
$sql .= ' order by a.eventTime desc, a.actionCode asc';
$results = $db->getAll($sql,$regGUID,$game);
Note that $regGUID should be an array, not string and $results already contain all the requested data, without any further processing.
What is the content of $regGUID? Since you're using an in clause, I suspect a comma separated list.
Binding a variable to a parameter is not like substituting that string into the query; it is like telling MySQL how to use your actual PHP variables. So if you bind a string like '1,2,3' to the query parameter, it stays as one string, and is not reinterpreted as a list of numbers.
Consequently, if $regGUID is something like "'AAA1', 'BBB2'", your first query becomes
... WHERE a.regGUID in ( 'AAA1', 'BBB2' ) ...
but your second query is more like
... WHERE a.regGUID in ( '\'AAA1\', \'BBB2\'' ) ...
which is the same as saying
... WHERE a.regGUID = '\'AAA1\', \'BBB2\'' ...
As others have state you can only bind a single scalar value to a placeholder. So this means you actually need a placeholder for each value in your IN statement. I normally do something like the following. It should be noted though that i never use bindValue so if it has rules about things having to be references like Mysqli then the below may need to be modified:
$regGUIDPlaceholders = array();
// prepare the placeholders
// assume regGUID is an array - if its a string then explode on whatever to make it an array
foreach($regGUID as $k => $v) {
$placeholder = ':regGUID' . $k;
$regGUIDPlaceholders[$key] = $value;
}
// prepare the IN statememnt
$in = sprintf('IN (%s)', implode(',', array_keys($regGUIDPlaceholders)));
$sql = 'SELECT a.eventCode, a.eventTime, a.teamCode, a.playerCode, b.lastName, b.firstName, b.number, a.xCoord, a.yCoord, a.id ';
$sql = $sql . 'FROM events a, players b ';
// USE the IN statement dynamically prepared above
$sql = $sql . 'WHERE a.regGUID '. $in . ' and ';
$sql = $sql . 'a.playerCode=b.playerCode and a.gameCode = :game order by a.eventTime desc, a.actionCode asc';
$stmt = $db->prepare($sql);
// bind each GUID to its placeholder
foreach($regGUIDPlaceholders as $placeholder => $value) {
$stmt->bindValue($placeholder, $value, PDO::PARAM_STR);
}
$stmt->bindValue(':game', $game, PDO::PARAM_STR);
$results = $stmt->execute();
I'm wondering how to query a database using an array, like so:
$query = mysql_query("SELECT * FROM status_updates WHERE member_id = '$friends['member_id']'");
$friends is an array which contains the member's ID. I am trying to query the database and show all results where member_id is equal to one of the member's ID in the $friends array.
Is there a way to do something like WHERE = $friends[member_id] or would I have to convert the array into a string and build the query like so:
$query = "";
foreach($friends as $friend){
$query .= 'OR member_id = '.$friend[id.' ';
}
$query = mysql_query("SELECT * FROM status_updates WHERE member_id = '1' $query");
Any help would be greatly appreciated, thanks!
You want IN.
SELECT * FROM status_updates WHERE member_id IN ('1', '2', '3');
So the code changes to:
$query = mysql_query("SELECT * FROM status_updates WHERE member_id IN ('" . implode("','", $friends) . "')");
Depending on where the data in the friends array comes from you many want to pass each value through mysql_real_escape_string() to make sure there are no SQL injections.
Use the SQL IN operator like so:
// Prepare comma separated list of ids (you could use implode for a simpler array)
$instr = '';
foreach($friends as $friend){
$instr .= $friend['member_id'].',';
}
$instr = rtrim($instr, ','); // remove trailing comma
// Use the comma separated list in the query using the IN () operator
$query = mysql_query("SELECT * FROM status_updates WHERE member_id IN ($instr)");
$query = "SELECT * FROM status_updates WHERE ";
for($i = 0 ; $i < sizeof($friends); $i++){
$query .= "member_id = '".$friends[$i]."' OR ";
}
substr($query, -3);
$result = mysql_query($query);