Zend Framework DB Adapter fetchCol problem with "IN" - php

When making selects using the fetchCol method of the Zend_Db_Adapter class, queries are not working as I expected eg: (where $db is a reference to a DB_Adapter)
$ids = array(1,2,3,4);
$idString = implode(",", $ids);
$query = "SELECT id FROM some_table WHERE id IN (?)";
$result = $db->fetchCol($query, $idString);
You would expect this to return an array of ids that matched the idString, but it only returns an array with a single item - the first id matched. If I were to rewrite it like this there would be no problem:
$ids = array(1,2,3,4);
$idString = implode(",", $ids);
$query = "SELECT id FROM some_table WHERE id IN ($idString)";
$result = $db->fetchCol($query);
Is the expected behaviour or a bug in ZF? The main problem I have with it is it isn't an obvious error to track, no functionality is broken I just have fewer results.

ZF is clever enough to know what to with arrays, so all you need is pass in the array itself, skip the implode:
$query = "SELECT id FROM some_table WHERE id IN (?)";
$result = $db->fetchCol($query, array($ids));
with your code, since you are passing in a string it gets quoted, so the query you are running ends up being something like this:
SELECT id FROM some_table WHERE id IN ('1, 2, 3, 4')

Try:
$query = "SELECT id FROM some_table WHERE id IN (?)";
$result = $db->fetchAll($query, $idString);
OR
create a DbTable for 'sometable'
class SomeTable extends Zend_Db_Table_Abstract {
protected $_name = 'sometable';
}
Fetch results like this
$table = new SomeTable();
$select = $table->select();
$select->where('id IN (?)', $idString );
$result = $table->fetchAll( $select );
See following POST as well:
Zend Framework: Proper way to interact with database?

Try this:
$ids = array( 1, 2, 3 );
$db->fetchCol( 'SELECT id FROM some_table WHERE id IN (' . str_repeat( '?,', sizeof( $ids )-1 ) . '?)', $ids );
you can alse do something like this:
$db->fetchCol( 'SELECT id FROM some_table WHERE id IN (' . $db->quoteInto( '?', $ids ) . ')' );

Related

PDO: Delete query only deleting entries of first value in IN statement [duplicate]

I found this code on SO, which is great for using PDO and the IN() statement together.
$values = explode(',', $values) ; # 1,4,7
$placeholders = rtrim(str_repeat('?, ', count($values)), ', ') ;
$query = "SELECT * FROM table WHERE id IN ($placeholders)";
$stm = $db->prepare($query) ;
$stm->execute($values) ;
However, how can I mix in another addition to the query so the query looks like this:
$query = "SELECT * FROM table WHERE id IN ($placeholders) AND product=?";
$stm = $db->prepare($query) ;
$stm->execute(array($values,$product)) ; //error happens when adding product placeholder
I thought this would work but I get:
Warning: PDOStatement::execute() [pdostatement.execute]: SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens in line 3 (the $stm line)
Any idea how to get this to behave as intended?
UPDATED execute to array, still not working..
Solution
This should work, if $values is an array:
$query = "SELECT * FROM table WHERE id IN ($placeholders) AND product=?";
$stm->execute(array_merge($values, array($product)));
Explanation
execute() expects one parameter - in this case an array - to be provided. By adding array_merge($values, array($product)) you create one array with $product added at the end, so the query should work correctly.
See the demo here: http://ideone.com/RcClX
$stm->execute($values,$product) ; //error happens when adding product placeholder
The problem here is that execute needs a single array. You can't pass multiple arrays, and worse, you can't nest arrays.
We already have a perfectly good $values array, so let's reuse it after you create the placeholder string.
$values = explode(',', $values) ; # 1,4,7
$placeholders = rtrim(str_repeat('?, ', count($values)), ', ') ;
$query = "SELECT * FROM table WHERE id IN ($placeholders) AND product=?";
// New!
$values[] = $product;
$stm = $db->prepare($query);
$stm->execute($values);
And an other solution can be (if you like the :param_name = $value way, as me):
$params = array(
':product' => $product
);
$_in_params = array();
foreach ( $_in_values as $idx_in => $value_in)
{
$_in_params[] = ':param_in_'.$idx_in;
$params[':param_in_'.$idx_in] = $value_in;
}
$query .= "SELECT * FROM table WHERE id IN (".join(',',$_in_params).") AND product=:product";
I'm not sure if this is the best and the most optimal solution, but it's a little bit more human readable :) And it can be helpful if you have a big an complicated query and you want to debug it
(I'm curious if someone have a good argument why NOT to do in this way)
You forgot to prepare it ^_^
$query = "SELECT * FROM table WHERE id IN ($placeholders) AND product=?";
$stm = $db->prepare($query) ;
$stm->execute($values,$product) ; //p00f
And aside from that execute() should only have one parameter
So the above won't work AT ALL!
See the DOCs
Placeholders version if you need it
$values = [1, 4, 7, 8];
$placeholders = preg_filter('/^/', ':prefix_', array_keys($values)));
$query = 'SELECT * FROM table WHERE id IN ( '. implode(', ', $placeholders) . ')';
$stmt = $db->prepare($query);
if (count($values) > 0) {
foreach ($values as $key => $current_value) {
$stmt->bindValue($placeholders[$key] , $current_value, PDO::PARAM_STR);
}
}
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);

Separate ids by commas and quotes

I got an array of ids that I want to use inside an IN statement (sql). However this can only be done when it is written correctly, for example: IN ('12', '13', '14')
How can I change an array of ids into that format? This means adding quotes around every number, and after every number surrounded by quotes a comma, except for the last one in the array.
My code:
$parent = "SELECT * FROM `web_categories` WHERE `parent_id` = 13 AND published = 1";
$parentcon = $conn->query($parent);
$parentcr = array();
while ($parentcr[] = $parentcon->fetch_array());
foreach($parentcr as $parentid){
if($parentid['id'] != ''){
$parentoverzicht .= "".$parentid['id']."";
}
}
I later want to use it like this:
$project = "SELECT * FROM `web_content` WHERE `catid` IN ('".$parentoverzicht."') AND state = 1";
Do this as a single query! SQL engines have all sorts of optimizations for working with tables, and doing the looping in your code is usually way more expensive.
The obvious query for your purposes would be:
SELECT wc.*
FROM web_content wc
WHERE wc.catid IN (SELECT cat.id
FROM web_categories cat
WHERE cat.parent_id = 13 AND cat.published = 1
) AND
wc.state = 1;
Use implode()..
<?php
$a1 = array("1","2","3");
$a2 = array("a");
$a3 = array();
echo "a1 is: '".implode("','",$a1)."'<br>";
echo "a2 is: '".implode("','",$a2)."'<br>";
echo "a3 is: '".implode("','",$a3)."'<br>";
?>
output->>>>>>>
a1 is: '1','2','3'
a2 is: 'a'
a3 is: ''
Have you tried to implode()?
Use ", " as glue. You will have to edit the string yourself to add a " at the beginning and end.
More info: http://php.net/manual/en/function.implode.php
Alternatively you can use single join query, like this.
SELECT con.* FROM `web_content` as con LEFT JOIN `web_categories` as cat
ON con.catid=cat.id WHERE cat.parent_id=13 AND published = 1
If the column's type in the DB is integer you do not actually need to quote the values, but in case it isn't, you can use array_map to quote every item in the array, then implode to join them with commas:
<?php
$ids = [1, 2, 3, 4, 5];
$sql = 'SELECT * FROM mytable WHERE id IN (?)';
$in_clause = array_map(function ($key) {
return "'$key'";
}, $ids);
$sql = str_replace('?', implode(',', $in_clause), $sql);
echo $sql;
Result:
SELECT * from mytable where id in ('1','2','3','4','5')
You can do something like this:
$ids = ['1','2','3','4']; //array of id's
$newArr = array(); //empty array..
foreach($ids as $ids)
{
$newArr[] = "'".$ids."'"; //push id into new array after adding single qoutes
}
$project = "SELECT * FROM `web_content` WHERE `catid` IN (".implode(',',$newArr).") AND state = 1"; /// implode new array with commaa.
echo $project;
This will give you :
SELECT * FROM `web_content` WHERE `catid` IN ('1','2','3','4') AND state = 1

Pass an array as parameters to SQL procedure

I have SQL procedure in which I'm using an IN statment. It goes like this:
SELECT * FROM costumers WHERE id IN('1','2','12','14')
What I need to do is pass the values in to the IN statment as parameter which is an array in php, rather than hard-coded. How can I do that?
You can implode on this case:
$array = array('1','2','12','14');
$ids = "'".implode("','", $array) . "'";
$sql = "SELECT * FROM `costumers` WHERE `id` IN($ids)";
echo $sql;
// SELECT * FROM `costumers` WHERE `id` IN('1','2','12','14')
or if you do not want any quotes:
$ids = implode(",", $array);
You can use PHP function Implode
$array = array("1","2","12","14");
$query = "SELECT * FROM costumers WHERE id IN(".implode(', ',$array).")"
implode() is the right function, but you also must pay attention to the type of the data.
If the field is numeric, it is simple:
$values = array(1. 2, 5);
$queryPattern = 'SELECT * FROM costumers WHERE id IN(%s)';
$query = sprintf($queryPattern, implode(', ',$values));
But if it's a string, you must play with single and double quotes:
$values = array("foo","bar","baz");
$queryPattern = 'SELECT * FROM costumers WHERE id IN("%s")';
$query = sprintf($queryPattern, implode('", "',$values));
This should do the trick
$array = array('1','2','12','14');
SELECT * FROM `costumers` WHERE `id` IN('{$array}');
Try imploding the php into an array, and then interpolating that string into the SQL statement:
$arr = array('foo', 'bar', 'baz');
$string = implode(", ", $arr);
SELECT * FROM customers WHERE id in ($string);
use PHP's join function to join the values of an array.
$arr = array(1,2,12,14);
$sql = "SELECT * FROM costumers WHERE id IN(" . join($arr, ',') . ")";

CodeIgniter - query binding "IN" parameter

I have a following query in my CodeIgniter, which I'm trying to bind via parameter.
$q = "SELECT * FROM my_table WHERE id IN (?)"
$ids = "1,2,3,4";
$this->db->query($q, array($ids));
Above is not working, because the query binding treats $ids as string. How can I parameterize my query, but still be able to do "IN" operation?
EDIT
sorry, I have to use "raw SQL query". Above query is just a part of a much larger + complex query, which I can't use ActiveRecord for. Also I'm using Postgres.
Instead of string put it in array
$q = "SELECT * FROM my_table WHERE id IN (?)"
$ids = array(1,2,3,4);
$this->db->query($q, $ids);
You can achieve same thing like this without binding
Alternative
$ids = array(1,2,3,4);
$this->db->where_in('id',$ids);
$this->db->get('my_table');
Try this with where_in
$ids = array(1,2,3,4);
$this->db->select('*');
$this->db->from('my_Table');
$this->db->where_in('id',$ids);
$this->db->query($q, explode(',', $ids));
or
$this->db->where_in('id', explode(',', $ids))->get('my_table');
Active Records documentation: http://ellislab.com/codeigniter/user-guide/database/active_record.html#select
Use FIND_IN_SET like this
select * from table where FIND_IN_SET('$ids', id);
Try this code:
$ids = "('1','2','3','4')";
$q = "SELECT * FROM my_table WHERE id IN ".$ids;
$this->db->query($q);
you should use the
$ids = array('1','2','3','4');
$this->db->where_in('id', $ids);
The where_in is used in codignitor.
point is
$ids = "1,2,3,4";
$a = array($ids);
//$a[0] = "1,2,3,4";
//not $a[0]=1;$a[1]=2;$a[2]=3;$a[3]=4;
want to keep your style
$ids = "1,2,3,4";
$a = explode(",",$ids);
$q = "SELECT * FROM my_table WHERE id IN ?"
$ids = "1,2,3,4";
$this->db->query($q, explode(",", $ids));

How to query a database with an array? WHERE = 'array()'

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);

Categories