Bir diziyi IN () koşuluna bağlayabilir miyim?


562

PDO kullanarak bir yer tutucusuna bir değer dizisi bağlamak mümkün olup olmadığını bilmek merak ediyorum. Buradaki kullanım örneği, bir değerle kullanmak için bir değer dizisi geçirmeye çalışıyorIN() koşulla .

Böyle bir şey yapabilmek istiyorum:

<?php
$ids=array(1,2,3,7,8,9);
$db = new PDO(...);
$stmt = $db->prepare(
    'SELECT *
     FROM table
     WHERE id IN(:an_array)'
);
$stmt->bindParam('an_array',$ids);
$stmt->execute();
?>

Ve PDO bağlamak ve dizideki tüm değerleri alıntı var.

Şu anda yapıyorum:

<?php
$ids = array(1,2,3,7,8,9);
$db = new PDO(...);
foreach($ids as &$val)
    $val=$db->quote($val); //iterate through array and quote
$in = implode(',',$ids); //create comma separated list
$stmt = $db->prepare(
    'SELECT *
     FROM table
     WHERE id IN('.$in.')'
);
$stmt->execute();
?>

İş kesinlikle hangisi, ama eksik bir çözüm olup olmadığını merak ediyorum?


3
Sorguda başka yer tutucuların olduğu durumlar da dahil olmak üzere, bir diziyi IN () koşuluna bağlama hakkında eksiksiz bir kılavuz
Ortak

Soru, bu sorunun kopyası olarak kapatıldı . Yinelenen bayrağı tersine çevirdim, çünkü bu soru 4 yaşında, 4 kat görüş, 3 kat cevap ve 12 kat puan. Açıkça üstün hedeftir.
miken32

2020'de buna bakan herkes: Bunun için github.com/morris/dop'u deneyebilirsiniz .
morris4

Yanıtlar:


262

ruhun doğru olduğunu düşünüyorum. sorgu dizesini oluşturmanız gerekir.

<?php
$ids     = array(1, 2, 3, 7, 8, 9);
$inQuery = implode(',', array_fill(0, count($ids), '?'));

$db = new PDO(...);
$stmt = $db->prepare(
    'SELECT *
     FROM table
     WHERE id IN(' . $inQuery . ')'
);

// bindvalue is 1-indexed, so $k+1
foreach ($ids as $k => $id)
    $stmt->bindValue(($k+1), $id);

$stmt->execute();
?>

düzeltme: dan, haklıydın. kodu düzeltti (yine de test etmedi)

edit: hem chris (yorumlar) ve birisi foreach-loop önerdi ...

(...)
// bindvalue is 1-indexed, so $k+1
foreach ($ids as $k => $id)
    $stmt->bindValue(($k+1), $id);

$stmt->execute();

... gereksiz olabilir, bu yüzden foreachdöngü ve $stmt->executeyerine sadece ...

<?php 
  (...)
  $stmt->execute($ids);
?>

(yine test etmedim)


7
Bu ilginç bir çözüm ve ben ids üzerinde yineleme ve PDO :: quote () çağıran tercih ederken, '?' önce sorgunun başka bir yerinde başka bir yer tutucu varsa, yer tutucuları dağıtacak, değil mi?
Andru

5
evet, bu bir sorun olurdu. ancak bu durumda? 'yerine adlandırılmış parametreler oluşturabilirsiniz.
stefs

9
Eski soru, ama ben inanıyorum, değer olduğunu $foreachve bindValue()gerekli değildir - sadece dizi ile yürütmek. Örn:$stmt->execute($ids);
Chris

2
Yer tutucuların oluşturulması şu şekilde yapılmalıdırstr_repeat('?,', count($array) - 1). '?';
Xeoncross

8
Sadece farkında olmayanlar için bir ipucu, adlandırılmış ve adlandırılmamış parametreleri karıştıramazsınız. Bu nedenle, sorgunuzda adlandırılmış parametreler kullanırsanız, bunları '' olarak değiştirin ve bindValue dizini uzaklığınızı IN? 'In konumlarını birbirinize göre nerede olacak şekilde eşleştirmek için artırın? parametreler.
justinl

169

Hızlı bir şey için:

//$db = new PDO(...);
//$ids = array(...);

$qMarks = str_repeat('?,', count($ids) - 1) . '?';
$sth = $db->prepare("SELECT * FROM myTable WHERE id IN ($qMarks)");
$sth->execute($ids);

7
Mükemmel, input_parameters argümanını bu şekilde kullanmayı düşünmemiştim. Sorguları IN listesinden daha fazla parametreye sahip olanlar için, dizinin önüne ve sonuna gerekli bağımsız değişkenleri eklemek için array_unshift ve array_push komutlarını kullanabilirsiniz. Ayrıca, tercih ediyorum $input_list = substr(str_repeat(',?', count($ids)), 1);
orca

7
Ayrıca deneyebilirsiniz str_repeat('?,', count($ids) - 1) . '?'. Bir daha az işlev çağrısı.
orca

5
@erfling, bu hazırlanmış bir açıklama, enjeksiyon nereden gelecek? Bunu gerçek bir kanıtla destekleyebiliyorsanız, herhangi bir düzeltme yapmaktan mutluluk duyacağım.
DonVaughn

5
@erfling, evet, doğru ve paramleri bağlamak, executebir dizi kimlik göndererek tam olarak bu örnekte yaptığımız
şeydir

5
Gerçekten. Diziyi geçtiğinizi bir şekilde özledim. Bu gerçekten güvenli ve iyi bir cevap gibi görünüyor. Özür dilerim.
15'te 23

46

İfadeyi kullanmak çok mu önemli IN? Kullanmaya çalışmakFIND_IN_SETOp .

Örneğin, PDO'da böyle bir sorgu var

SELECT * FROM table WHERE FIND_IN_SET(id, :array)

O zaman sadece virgülle yerleştirilmiş bir değer dizisini bağlamanız gerekir, bunun gibi

$ids_string = implode(',', $array_of_smth); // WITHOUT WHITESPACES BEFORE AND AFTER THE COMMA
$stmt->bindParam('array', $ids_string);

ve bitti.

UPD: Bazı insanların bu cevaba yaptığı yorumlarda belirttiği gibi, açıkça ifade edilmesi gereken bazı konular var.

  1. FIND_IN_SETbir tabloda dizin kullanmıyor ve henüz uygulanmadı - MYSQL hata izleyicide bu kayda bakın . @BillKarwin'e bildirim için teşekkürler.
  2. Arama dizisinin değeri olarak içinde virgül bulunan bir dize kullanamazsınız. implodeAyırıcı olarak virgül sembolü kullandığınız için bu dizeyi doğru şekilde ayrıştırmak imkansızdır . Not için @VaL'a teşekkürler.

İyi bir şekilde, dizinlere büyük ölçüde bağımlı değilseniz ve arama için virgül içeren dizeler kullanmıyorsanız, çözümüm yukarıda listelenen çözümlerden çok daha kolay, daha basit ve daha hızlı olacaktır.


25
IN () bir dizin kullanabilir ve aralık taraması olarak sayılır. FIND_IN_SET () bir dizin kullanamaz.
Bill Karwin

1
Bu bir nokta. Bunu bilmiyordum. Ancak herhangi bir şekilde soruda performans için herhangi bir gereklilik yoktur. Çok büyük olmayan tablolar için, farklı sayıda yer tutucu ile sorgu oluşturmak için ayrı bir sınıftan çok daha iyi ve daha temiz.
Tim Tonkonogov

11
Evet, ama bu günlerde kim o kadar büyük olmayan bir masaya sahip? ;-)
Bill Karwin

3
Bu yaklaşımla ilgili başka bir sorun, içinde virgül bulunan dize olacaksa ne olur? Örneğin ... FIND_IN_SET(description,'simple,search')işe yarayacak, ancak FIND_IN_SET(description,'first value,text, with coma inside')başarısız olacak. Böylece işlev "first value", "text", "with coma inside" istenen yerine arama yapar "first value", "text, with coma inside"
VaL

33

Çok sayıda dinamik sorgu yaptığım için yaptığım süper basit bir yardımcı işlev.

public static function bindParamArray($prefix, $values, &$bindArray)
{
    $str = "";
    foreach($values as $index => $value){
        $str .= ":".$prefix.$index.",";
        $bindArray[$prefix.$index] = $value;
    }
    return rtrim($str,",");     
}

Şöyle kullanın:

$bindString = helper::bindParamArray("id", $_GET['ids'], $bindArray);
$userConditions .= " AND users.id IN($bindString)";

Bir dize döndürür :id1,:id2,:id3ve $bindArraysorgunuzu çalıştırma zamanı geldiğinde ihtiyaç duyacağınız bağlamaları günceller . Kolay!


6
Bu çok daha iyi bir çözümdür, çünkü parametrelerin bağlanması kuralını bozmaz. Bu, burada başkaları tarafından önerilen satır içi sql'den çok daha güvenlidir.
Dimitar Darazhanski

1
Awesomeness. Zarif. Mükemmel.
Ricalsin

17

EvilRygy'nin çözümü benim için işe yaramadı. Postgres'te başka bir geçici çözüm yapabilirsiniz:


$ids = array(1,2,3,7,8,9);
$db = new PDO(...);
$stmt = $db->prepare(
    'SELECT *
     FROM table
     WHERE id = ANY (string_to_array(:an_array, ','))'
);
$stmt->bindParam(':an_array', implode(',', $ids));
$stmt->execute();

Bu işe yaramazsa: ERROR: operator does not exist: integer = text. En azından açık döküm eklemeniz gerekiyor.
collimarco

17

postgres için çok temiz bir yol postgres dizisini kullanmaktır ("{}"):

$ids = array(1,4,7,9,45);
$param = "{".implode(', ',$ids)."}";
$cmd = $db->prepare("SELECT * FROM table WHERE id = ANY (?)");
$result = $cmd->execute(array($param));

sql enjeksiyon engellemek?
Fábio Zangirolami

1
@ FábioZangirolami PDO, yani evet.
ESCOBAR

EVET, PDO! 4 yıl sonra. Yanıtınız benim için iyi, çok basit ve etkili oldu. teşekkür ederim!!!
Fábio Zangirolami

14

İşte benim çözümüm:

$total_items = count($array_of_items);
$question_marks = array_fill(0, $total_items, '?');
$sql = 'SELECT * FROM foo WHERE bar IN (' . implode(',', $question_marks ). ')';

$stmt = $dbh->prepare($sql);
$stmt->execute(array_values($array_of_items));

Dizi_değeri kullanımına dikkat edin. Bu, anahtar sipariş sorunlarını düzeltebilir.

Kimlik dizilerini birleştirip yinelenen öğeleri kaldırıyordum. Gibi bir şey vardı:

$ids = array(0 => 23, 1 => 47, 3 => 17);

Ve bu başarısız oluyordu.


Bu mükemmel bir çözümdü. Sorgu dizesini oluşturmanın aksine, bu doğru bir şekilde bağlamayı kullanır. Bunu şiddetle tavsiye ediyorum.
Lindylead

Not: Çözümünüzü kullanarak, dizinin önüne veya arkasına öğeler ekleyebilirsiniz, böylece başka bağlantılar da ekleyebilirsiniz. $original_array Orijinal diziden önce öğe ekle: Orijinal diziden array_unshift($original_array, new_unrelated_item); sonra öğe ekle: array_push($original_array, new_unrelated_item); Değerler bağlandığında, new_unrelated öğeler doğru konumlara yerleştirilir. Bu, Dizi ve dizi olmayan öğeleri karıştırmanıza olanak tanır. `
Lindylead

12

PDO'yu stefs'in önerdiğine benzer bir şey yapmak için genişlettim ve uzun vadede benim için daha kolaydı:

class Array_Capable_PDO extends PDO {
    /**
     * Both prepare a statement and bind array values to it
     * @param string $statement mysql query with colon-prefixed tokens
     * @param array $arrays associatve array with string tokens as keys and integer-indexed data arrays as values 
     * @param array $driver_options see php documention
     * @return PDOStatement with given array values already bound 
     */
    public function prepare_with_arrays($statement, array $arrays, $driver_options = array()) {

        $replace_strings = array();
        $x = 0;
        foreach($arrays as $token => $data) {
            // just for testing...
            //// tokens should be legit
            //assert('is_string($token)');
            //assert('$token !== ""');
            //// a given token shouldn't appear more than once in the query
            //assert('substr_count($statement, $token) === 1');
            //// there should be an array of values for each token
            //assert('is_array($data)');
            //// empty data arrays aren't okay, they're a SQL syntax error
            //assert('count($data) > 0');

            // replace array tokens with a list of value tokens
            $replace_string_pieces = array();
            foreach($data as $y => $value) {
                //// the data arrays have to be integer-indexed
                //assert('is_int($y)');
                $replace_string_pieces[] = ":{$x}_{$y}";
            }
            $replace_strings[] = '('.implode(', ', $replace_string_pieces).')';
            $x++;
        }
        $statement = str_replace(array_keys($arrays), $replace_strings, $statement);
        $prepared_statement = $this->prepare($statement, $driver_options);

        // bind values to the value tokens
        $x = 0;
        foreach($arrays as $token => $data) {
            foreach($data as $y => $value) {
                $prepared_statement->bindValue(":{$x}_{$y}", $value);
            }
            $x++;
        }

        return $prepared_statement;
    }
}

Bu şekilde kullanabilirsiniz:

$db_link = new Array_Capable_PDO($dsn, $username, $password);

$query = '
    SELECT     *
    FROM       test
    WHERE      field1 IN :array1
     OR        field2 IN :array2
     OR        field3 = :value
';

$pdo_query = $db_link->prepare_with_arrays(
    $query,
    array(
        ':array1' => array(1,2,3),
        ':array2' => array(7,8,9)
    )
);

$pdo_query->bindValue(':value', '10');

$pdo_query->execute();

1
Mark'ın yorumunun ilk kısmını ele aldım, ancak işaret ettiği gibi :array, sorgudaki bir dizede benzer bir token varsa hala güvenli değil .
Chris

4
Gelecekteki tüm okuyuculara not: Bu çözüm asla kullanılmamalıdır. Ekler, üretim kodu için tasarlanmamıştır
Common Sense,

1
YCS: geri bildirimler için teşekkürler, iddiaların uygunluğunun dışındaki yaklaşım hakkındaki görüşlerinizle ilgilenin.
Chris

1
Fikir oldukça aynı ama sadece iddialar olmadan ve daha basit ve açık bir şekilde - sadece tek bir vaka için bir istisna olarak değil, her sorguyu oluşturmanın genel bir yolu olarak. Her yer tutucu türü ile işaretlenmiştir. Tahmin çalışmasını ( if (is_array($data))biri gibi ) gereksiz kılar, ancak veri işlemeyi daha doğru hale getirir.
Ortak Duygunuz

1
Yorumları okuyan herhangi bir kişiye: @ Common Sense'iniz tarafından bahsedilen sorun düzeltme 4'te giderilmiştir .
user2428118

11

PDO'ya bakarken : Önceden Tanımlı Sabitler PDOStatement-> bindParam'da listelendiği gibi ihtiyacınız olan PDO :: PARAM_ARRAY yoktur

bool PDOStatement :: bindParam (karışık $ parametresi, karışık & $ değişkeni [, int $ data_type [, int $ length [, karışık $ driver_options]]])

Bu yüzden ulaşılabilir olduğunu sanmıyorum.


1
Bunun işe yarayıp yaramadığını bilmiyorum. Ben imploded dize alıntı olduğunu tahmin ediyorum.
soulmerge

2
Haklısın, tırnaklar kaçtı, böylece kazandı; Bu kodu kaldırdım.

11

Başka bir parametreniz olduğunda, bunu yapabilirsiniz:

$ids = array(1,2,3,7,8,9);
$db = new PDO(...);
$query = 'SELECT *
            FROM table
           WHERE X = :x
             AND id IN(';
$comma = '';
for($i=0; $i<count($ids); $i++){
  $query .= $comma.':p'.$i;       // :p0, :p1, ...
  $comma = ',';
}
$query .= ')';

$stmt = $db->prepare($query);
$stmt->bindValue(':x', 123);  // some value
for($i=0; $i<count($ids); $i++){
  $stmt->bindValue(':p'.$i, $ids[$i]);
}
$stmt->execute();

Harika cevap için teşekkürler. Benim için gerçekten işe yarayan tek şey buydu. Ancak 1 hata gördüm. $ Rs değişkeni $ stmt olmalıdır
Piet

11

Benim için en seksi çözüm dinamik bir ilişkilendirici dizi oluşturmak ve kullanmaktır

// A dirty array sent by user
$dirtyArray = ['Cecile', 'Gilles', 'Andre', 'Claude'];

// we construct an associative array like this
// [ ':name_0' => 'Cecile', ... , ':name_3' => 'Claude' ]
$params = array_combine(
    array_map(
        // construct param name according to array index
        function ($v) {return ":name_{$v}";},
        // get values of users
        array_keys($dirtyArray)
    ),
    $dirtyArray
);

// construct the query like `.. WHERE name IN ( :name_1, .. , :name_3 )`
$query = "SELECT * FROM user WHERE name IN( " . implode(",", array_keys($params)) . " )";
// here we go
$stmt  = $db->prepare($query);
$stmt->execute($params);

Gerçek senaryoda denemeden emin olmak zor, ama iyi görünüyor. + 1
Anant Singh --- Alive to Die

9

Ben de bu iş parçacığı eski ama benzersiz bir sorun vardı nerede, yakında-to-be-mexql sürücüsünü PDO sürücüsüne dönüştürürken dinamik olarak hem normal params hem de INs inşa edebilecek bir işlevi yapmak zorunda kaldı param dizisi. Bu yüzden hızlı bir şekilde inşa ettim:

/**
 * mysql::pdo_query('SELECT * FROM TBL_WHOOP WHERE type_of_whoop IN :param AND siz_of_whoop = :size', array(':param' => array(1,2,3), ':size' => 3))
 *
 * @param $query
 * @param $params
 */
function pdo_query($query, $params = array()){

    if(!$query)
        trigger_error('Could not query nothing');

    // Lets get our IN fields first
    $in_fields = array();
    foreach($params as $field => $value){
        if(is_array($value)){
            for($i=0,$size=sizeof($value);$i<$size;$i++)
                $in_array[] = $field.$i;

            $query = str_replace($field, "(".implode(',', $in_array).")", $query); // Lets replace the position in the query string with the full version
            $in_fields[$field] = $value; // Lets add this field to an array for use later
            unset($params[$field]); // Lets unset so we don't bind the param later down the line
        }
    }

    $query_obj = $this->pdo_link->prepare($query);
    $query_obj->setFetchMode(PDO::FETCH_ASSOC);

    // Now lets bind normal params.
    foreach($params as $field => $value) $query_obj->bindValue($field, $value);

    // Now lets bind the IN params
    foreach($in_fields as $field => $value){
        for($i=0,$size=sizeof($value);$i<$size;$i++)
            $query_obj->bindValue($field.$i, $value[$i]); // Both the named param index and this index are based off the array index which has not changed...hopefully
    }

    $query_obj->execute();

    if($query_obj->rowCount() <= 0)
        return null;

    return $query_obj;
}

Hala denenmemiş, ancak mantık orada görünüyor.

Umarım aynı pozisyonda birine yardımcı olur,

Düzenleme: Bazı testlerden sonra öğrendim:

  • PDO '.' isimleriyle (bana sorarsan biraz aptalca)
  • bindParam yanlış işlev, bindValue doğru işlevdir.

Kod çalışma sürümüne düzenlendi.


8

Schnalle koduyla ilgili küçük bir düzenleme

<?php
$ids     = array(1, 2, 3, 7, 8, 9);
$inQuery = implode(',', array_fill(0, count($ids)-1, '?'));

$db   = new PDO(...);
$stmt = $db->prepare(
    'SELECT *
     FROM table
     WHERE id IN(' . $inQuery . ')'
);

foreach ($ids as $k => $id)
    $stmt->bindValue(($k+1), $id);

$stmt->execute();
?>

//implode(',', array_fill(0, count($ids)-1), '?')); 
//'?' this should be inside the array_fill
//$stmt->bindValue(($k+1), $in); 
// instead of $in, it should be $id

1
Benim için çalışmak için sayısı ($ ids) sonra -1 kaldırmak zorunda kaldı ya da her zaman eksik bir yer tutucu olurdu.
Marcel Burkhard

7

Hangi veritabanını kullanıyorsunuz? PostgreSQL'de HERHANGİ (dizi) kullanmayı seviyorum. Örneğinizi yeniden kullanmak için:

<?php
$ids=array(1,2,3,7,8,9);
$db = new PDO(...);
$stmt = $db->prepare(
    'SELECT *
     FROM table
     WHERE id = ANY (:an_array)'
);
$stmt->bindParam('an_array',$ids);
$stmt->execute();
?>

Ne yazık ki bu oldukça taşınabilir değil.

Diğer veritabanlarında, başkalarının bahsettiği gibi kendi büyünüzü oluşturmalısınız. Elbette programınız boyunca yeniden kullanılabilir hale getirmek için bu mantığı bir sınıfa / işleve koymak isteyeceksiniz. mysql_queryBu senaryonun konusu ve örnekleri hakkında daha fazla düşünce için PHP.NET'teki sayfadaki yorumlara bir göz atın .


4

Aynı problemden geçtikten sonra, daha basit bir çözüme gittim (yine de PDO::PARAM_ARRAY olmayacak olsa da):

dizi verildi $ids = array(2, 4, 32):

$newparams = array();
foreach ($ids as $n => $val){ $newparams[] = ":id_$n"; }

try {
    $stmt = $conn->prepare("DELETE FROM $table WHERE ($table.id IN (" . implode(", ",$newparams). "))");
    foreach ($ids as $n => $val){
        $stmt->bindParam(":id_$n", intval($val), PDO::PARAM_INT);
    }
    $stmt->execute();

... ve bunun gibi

Dolayısıyla, bir karışık değerler dizisi kullanıyorsanız, param türünü atamadan önce değerlerinizi test etmek için daha fazla koda ihtiyacınız olacaktır:

// inside second foreach..

$valuevar = (is_float($val) ? floatval($val) : is_int($val) ? intval($val) :  is_string($val) ? strval($val) : $val );
$stmt->bindParam(":id_$n", $valuevar, (is_int($val) ? PDO::PARAM_INT :  is_string($val) ? PDO::PARAM_STR : NULL ));

Ama bunu test etmedim.


4

Bildiğim gibi bir dizi PDO deyimine bağlamak için herhangi bir olasılık yoktur.

Ancak 2 ortak çözüm var:

  1. Konumsal Yer Tutucular (?,?,?,?) Veya Adlandırılmış Yer Tutucular (: id1,: id2,: id3) kullanın

    $ whereIn = implode (',', dizi_dosyası (0, sayım ($ ids), '?'));

  2. Diziyi daha önce alıntıla

    $ whereIn = array_map (dizi ($ db, 'quote'), $ ids);

Her iki seçenek de iyi ve güvenlidir. Daha kısa olduğu için ikincisini tercih ediyorum ve eğer gerekiyorsa parametreleri değiştirebilirim. Yer tutucuları kullanarak değerleri bağlamanız gerekir ve sonunda SQL kodunuz aynı olur.

$sql = "SELECT * FROM table WHERE id IN ($whereIn)";

Ve benim için son ve önemli olan hatadan kaçınmak "bağlı değişkenlerin sayısı belirteç sayısıyla eşleşmiyor"

Doktrin, yalnızca gelen parametreler üzerinde iç kontrole sahip olması nedeniyle konumsal yer tutucuları kullanmanın harika bir örneğidir.


4

Sütun yalnızca tamsayılar içerebiliyorsa, bunu muhtemelen yer tutucular olmadan yapabilir ve kimlikleri doğrudan sorguya koyabilirsiniz. Dizinin tüm değerlerini tamsayılara çevirmeniz yeterlidir. Bunun gibi:

$listOfIds = implode(',',array_map('intval', $ids));
$stmt = $db->prepare(
    "SELECT *
     FROM table
     WHERE id IN($listOfIds)"
);
$stmt->execute();

Bu herhangi bir SQL enjeksiyonuna karşı savunmasız olmamalıdır.


3

işte benim çözümüm. Ayrıca PDO sınıfını genişlettik:

class Db extends PDO
{

    /**
     * SELECT ... WHERE fieldName IN (:paramName) workaround
     *
     * @param array  $array
     * @param string $prefix
     *
     * @return string
     */
    public function CreateArrayBindParamNames(array $array, $prefix = 'id_')
    {
        $newparams = [];
        foreach ($array as $n => $val)
        {
            $newparams[] = ":".$prefix.$n;
        }
        return implode(", ", $newparams);
    }

    /**
     * Bind every array element to the proper named parameter
     *
     * @param PDOStatement $stmt
     * @param array        $array
     * @param string       $prefix
     */
    public function BindArrayParam(PDOStatement &$stmt, array $array, $prefix = 'id_')
    {
        foreach($array as $n => $val)
        {
            $val = intval($val);
            $stmt -> bindParam(":".$prefix.$n, $val, PDO::PARAM_INT);
        }
    }
}

Yukarıdaki kod için örnek bir kullanım:

$idList = [1, 2, 3, 4];
$stmt = $this -> db -> prepare("
  SELECT
    `Name`
  FROM
    `User`
  WHERE
    (`ID` IN (".$this -> db -> CreateArrayBindParamNames($idList)."))");
$this -> db -> BindArrayParam($stmt, $idList);
$stmt -> execute();
foreach($stmt as $row)
{
    echo $row['Name'];
}

Ne düşündüğü söyle


Bunun aşağıdaki user2188977 yanıtına dayandığını belirtmeyi unutmuşum.
Lippai Zoltan

GetOne () ne olduğundan emin değilim, PDO'nun bir parçası gibi görünmüyor. Ben sadece PEAR'da gördüm. Tam olarak ne yapar?
Lippai Zoltan

@ YourCommonSense kullanıcı tanımlı işlevinizi yanıt olarak gönderebilir misiniz?
nullabilite

BindArrayParamBu tamsayılar için sınırlayıcı gibi görünüyor veri türünü ilişkilendirici dizide geçirerek öneririz .
Ian Brindley

2

PDO'da böyle bir dizi kullanmak mümkün değildir.

Her değer için bir parametre içeren bir dize oluşturmanız (veya?) Kullanmanız gerekir, örneğin:

:an_array_0, :an_array_1, :an_array_2, :an_array_3, :an_array_4, :an_array_5

İşte bir örnek:

<?php
$ids = array(1,2,3,7,8,9);
$sqlAnArray = join(
    ', ',
    array_map(
        function($index) {
            return ":an_array_$index";
        },
        array_keys($ids)
    )
);
$db = new PDO(
    'mysql:dbname=mydb;host=localhost',
    'user',
    'passwd'
);
$stmt = $db->prepare(
    'SELECT *
     FROM table
     WHERE id IN('.$sqlAnArray.')'
);
foreach ($ids as $index => $id) {
    $stmt->bindValue("an_array_$index", $id);
}

Kullanmaya devam etmek istiyorsanız bindParam, bunun yerine şunları yapabilirsiniz:

foreach ($ids as $index => $id) {
    $stmt->bindParam("an_array_$index", $ids[$id]);
}

Yer ?tutucuları kullanmak istiyorsanız , bunu şu şekilde yapabilirsiniz:

<?php
$ids = array(1,2,3,7,8,9);
$sqlAnArray = '?' . str_repeat(', ?', count($ids)-1);
$db = new PDO(
    'mysql:dbname=dbname;host=localhost',
    'user',
    'passwd'
);
$stmt = $db->prepare(
    'SELECT *
     FROM phone_number_lookup
     WHERE country_code IN('.$sqlAnArray.')'
);
$stmt->execute($ids);

$idsBoş olup olmadığını bilmiyorsanız , bunu test etmeli ve bu durumu uygun şekilde ele almalısınız (boş bir dizi döndürün veya bir Boş Nesne döndürün veya bir istisna atın, ...).


0

Parametreleri bağlamak için yer tutucuları kullanma konusundaki orijinal soruya cevap bulmayı biraz daha ileri götürdüm.

Bu yanıt, sorguda kullanılacak dizi boyunca iki döngü yapmak zorunda kalacaktır. Ancak, daha seçici sorgular için diğer sütun yer tutucularına sahip olma sorununu çözer.

//builds placeholders to insert in IN()
foreach($array as $key=>$value) {
    $in_query = $in_query . ' :val_' . $key . ', ';
}

//gets rid of trailing comma and space
$in_query = substr($in_query, 0, -2);

$stmt = $db->prepare(
    "SELECT *
     WHERE id IN($in_query)";

//pind params for your placeholders.
foreach ($array as $key=>$value) {
    $stmt->bindParam(":val_" . $key, $array[$key])
}

$stmt->execute();

0

önce "?" sayısını ayarladınız sorguda ve sonra bir "for" ile aşağıdaki gibi parametreleri gönderin:

require 'dbConnect.php';
$db=new dbConnect();
$array=[];
array_push($array,'value1');
array_push($array,'value2');
$query="SELECT * FROM sites WHERE kind IN (";

foreach ($array as $field){
    $query.="?,";
}
$query=substr($query,0,strlen($query)-1);
$query.=")";
$tbl=$db->connection->prepare($query);
for($i=1;$i<=count($array);$i++)
    $tbl->bindParam($i,$array[$i-1],PDO::PARAM_STR);
$tbl->execute();
$row=$tbl->fetchAll(PDO::FETCH_OBJ);
var_dump($row);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.