Posso associare un array a una condizione IN ()?


562

Sono curioso di sapere se è possibile associare una matrice di valori a un segnaposto utilizzando DOP. Il caso d'uso qui sta tentando di passare un array di valori per l'uso con una IN()condizione.

Mi piacerebbe poter fare qualcosa del genere:

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

E fare in modo che DOP si associ e citi tutti i valori dell'array.

Al momento sto facendo:

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

Che sicuramente fa il lavoro, ma mi chiedo solo se c'è una soluzione integrata che mi manca?


3
Una guida completa sull'associazione di un array a una condizione IN () , incluso il caso in cui nella query siano presenti altri segnaposto
Il tuo senso comune

La domanda è stata chiusa come duplicato di questa domanda . Ho invertito la bandiera duplicata perché questa domanda ha 4 anni in più, ha 4 volte le visualizzazioni, 3 volte il numero di risposte e 12 volte il punteggio. È chiaramente l'obiettivo superiore.
miken32

Chiunque lo guardi nel 2020: potresti provare github.com/morris/dop per questo.
morris4,

Risposte:


262

penso che il soulmerge sia giusto. dovrai costruire la stringa di query.

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

correzione: dan, avevi ragione. risolto il codice (non testato però)

modifica: sia chris (commenti) sia qualcuno non suggeriscono che il ciclo foreach ...

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

$stmt->execute();

... potrebbe essere ridondante, quindi il foreachloop e il $stmt->executepotrebbero essere sostituiti da solo ...

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

(di nuovo, non l'ho provato)


7
Questa è una soluzione interessante, e mentre preferisco iterare sugli ID e chiamare PDO :: quote (), penso che l'indice del '?' i segnaposto verranno incasinati se si verificano altri segnaposto altrove nella query, giusto?
Andru,

5
sì, sarebbe un problema. ma in questo caso è possibile creare parametri denominati anziché? 's.
stefs,

9
La vecchia domanda, ma credo che sia degna di nota, è che il $foreache bindValue()non è richiesto - basta eseguire con l'array. Ad esempio:$stmt->execute($ids);
Chris,

2
Generare i segnaposto dovrebbe essere fatto in questo modostr_repeat('?,', count($array) - 1). '?';
Xeoncross

8
Solo un consiglio per chi non lo sapesse, non è possibile mescolare parametri nominati e non nominati. Pertanto, se si utilizzano parametri denominati nella query, commutarli su? 'S e quindi aumentare l'offset dell'indice bindValue in modo che corrisponda alla posizione degli IN? Con quelli ovunque siano relativi all'altro? Parametri.
justinl

169

Per qualcosa di veloce:

//$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
Eccellente, non avevo pensato di usare l'argomento input_parameters in questo modo. Per coloro le cui query hanno più parametri rispetto all'elenco IN, è possibile utilizzare array_unshift e array_push per aggiungere gli argomenti necessari all'inizio e alla fine dell'array. Inoltre, preferisco $input_list = substr(str_repeat(',?', count($ids)), 1);
orca

7
Potresti anche provare str_repeat('?,', count($ids) - 1) . '?'. Una chiamata di funzione in meno.
orca,

5
@erfling, questa è una dichiarazione preparata, da dove verrà l'iniezione? Sarò più che felice di apportare eventuali correzioni se è possibile eseguirne il backup con alcune prove concrete di ciò.
DonVaughn,

5
@erfling, sì, è corretto, e l'associazione dei parametri è esattamente ciò che stiamo facendo in questo esempio inviando executeuna serie di ID
DonVaughn,

5
Oh davvero. In qualche modo mancato il fatto che stavi passando l'array. Questo sembra davvero essere sicuro e una buona risposta. Mie scuse.
eruzione il

46

È così importante usare la INdichiarazione? Prova a usare FIND_IN_SETop.

Ad esempio, esiste una query in DOP come quella

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

Quindi devi solo associare una matrice di valori, implosa con una virgola, come questa

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

ed è fatto.

UPD: Come alcuni hanno sottolineato nei commenti a questa risposta, ci sono alcuni problemi che dovrebbero essere dichiarati esplicitamente.

  1. FIND_IN_SETnon utilizza l'indice in una tabella e non è ancora implementato - vedere questo record nel bug tracker MYSQL . Grazie a @BillKarwin per l'avviso.
  2. Non è possibile utilizzare una stringa con virgola all'interno come valore dell'array per la ricerca. È impossibile analizzare tale stringa nel modo giusto dopo che implodesi utilizza il simbolo virgola come separatore. Grazie a @VaL per la nota.

Bene, se non sei fortemente dipendente dagli indici e non usi stringhe con virgola per la ricerca, la mia soluzione sarà molto più facile, più semplice e più veloce delle soluzioni sopra elencate.


25
IN () può usare un indice e conta come scansione di intervallo. FIND_IN_SET () non può utilizzare un indice.
Bill Karwin,

1
Questo è un punto. Non lo sapevo. Ma in ogni caso non ci sono requisiti per le prestazioni nella domanda. Per tabelle non molto grandi è molto più migliore e più pulito della classe separata per generare query con diversi numeri di segnaposto.
Tim Tonkonogov,

11
Sì, ma chi ha un tavolo non così grande in questi giorni? ;-)
Bill Karwin l'

3
Un altro problema con questo approccio è che se ci fosse una stringa con virgola all'interno? Ad esempio ... FIND_IN_SET(description,'simple,search')funzionerà, ma FIND_IN_SET(description,'first value,text, with coma inside')fallirà. Quindi la funzione cercherà "first value", "text", "with coma inside" invece di quella desiderata"first value", "text, with coma inside"
VaL,

33

Dal momento che faccio molte query dinamiche, questa è una funzione di supporto super semplice che ho creato.

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

Usalo in questo modo:

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

Restituisce una stringa :id1,:id2,:id3e aggiorna anche le $bindArrayassociazioni di cui avrai bisogno quando è il momento di eseguire la query. Facile!


6
Questa è una soluzione molto migliore, dal momento che non rompe il legame della regola dei parametri. Questo è molto più sicuro che avere sql in linea come proposto da alcuni altri qui.
Dimitar Darazhanski,

1
Grandiosità. Elegante. Perfetto.
Ricalsin,

17

La soluzione di EvilRygy non ha funzionato per me. In Postgres puoi fare un'altra soluzione alternativa:


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

Questo non funziona: ERROR: operator does not exist: integer = text. Almeno è necessario aggiungere il cast esplicito.
Collimarco,

17

un modo molto pulito per postgres è usare l'array postgres ("{}"):

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

blocca l'iniezione sql?
Fábio Zangirolami,

1
@ FábioZangirolami è DOP, quindi sì.
ESCOBAR

SÌ, DOP! dopo 4 anni. La tua risposta è andata bene per me, molto semplice ed efficace. grazie!!!
Fábio Zangirolami,

14

Ecco la mia soluzione:

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

Nota l'uso di array_values. Questo può risolvere i problemi di ordinamento chiave.

Stavo unendo array di ID e quindi rimuovendo elementi duplicati. Ho avuto qualcosa di simile:

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

E quello stava fallendo.


Questa è stata un'ottima soluzione. A differenza della creazione della stringa di query, utilizza correttamente l'associazione. Consiglio vivamente questo.
Lindylead

Nota: utilizzando la soluzione, è possibile aggiungere elementi nella parte anteriore o posteriore dell'array, in modo da poter includere altri collegamenti. $original_array Aggiungi elementi prima dell'array originale: array_unshift($original_array, new_unrelated_item); Aggiungi elementi dopo l'array originale: array_push($original_array, new_unrelated_item); quando i valori sono associati, gli elementi new_unrelated verranno posizionati nelle posizioni corrette. Ciò consente di mescolare elementi array e non array. `
Lindylead il

12

Ho esteso la DOP a fare qualcosa di simile a ciò che suggerisce stefs, ed è stato più facile per me nel lungo periodo:

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

Puoi usarlo in questo modo:

$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
Ho affrontato la prima parte del commento di Mark, ma come ha sottolineato, non è ancora sicuro se un token come :arrayè in una stringa nella query.
Chris,

4
Una nota per tutti i futuri lettori: questa soluzione non dovrebbe mai essere utilizzata. Le asserzioni non sono intese per il codice di produzione
Il tuo senso comune

1
YCS: grazie per il feedback, interessato alla tua opinione dell'approccio al di fuori dell'idoneità delle asserzioni.
Chris

1
L'idea è praticamente la stessa, ma senza affermazioni e un modo più diretto ed esplicito, non come un'eccezione per un solo caso, ma come un modo generale di costruire ogni query. Ogni segnaposto è contrassegnato con il suo tipo. Rende if (is_array($data))inutili le congetture (come una) ma rende l'elaborazione dei dati molto più accurata.
Il tuo senso comune

1
A tutti coloro che leggono i commenti: il problema menzionato da @Your Common Sense è stato risolto nella revisione 4 .
user2428118

11

Guardando DOP: Costanti predefinite non c'è PDO :: PARAM_ARRAY di cui avresti bisogno come elencato su PDOStatement-> bindParam

bool PDOStatement :: bindParam (parametro $ misto, misto e $ variabile [, int $ data_type [, int $ length [, misto $ driver_options]]])

Quindi non penso che sia realizzabile.


1
Non so se funzioni. Immagino che la stringa implosa venga quotata.
soulmerge,

2
Hai ragione, le virgolette vengono sfuggite in modo che non funzionino. Ho rimosso quel codice.

11

Quando hai altri parametri, puoi fare così:

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

Grazie per la magnifica risposta. Questo è stato l'unico di tutti che ha funzionato per me. Tuttavia, ho visto 1 errore. La variabile $ rs dovrebbe essere $ stmt
Piet

11

Per me la soluzione più sexy è costruire un array associativo dinamico e usarlo

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

Difficile essere certi senza provarlo in uno scenario reale, ma sembra a posto. + 1
Anant Singh --- Alive to Die

9

Mi rendo anche conto che questo thread è vecchio ma ho avuto un problema unico in cui, durante la conversione del driver mysql che sarà presto deprecato in driver PDO, ho dovuto creare una funzione che potesse costruire, dinamicamente, sia parametri normali che IN dallo stesso array di parametri. Quindi ho rapidamente creato questo:

/**
 * 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;
}

Non è ancora stato testato, tuttavia la logica sembra essere lì.

Spero che aiuti qualcuno nella stessa posizione,

Modifica: dopo alcuni test ho scoperto:

  • Alla DOP non piace '.' nei loro nomi (che è un po 'stupido se me lo chiedi)
  • bindParam è la funzione sbagliata, bindValue è la funzione giusta.

Codice modificato alla versione funzionante.


8

Un piccolo editing sul codice di Schnalle

<?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
Ho dovuto rimuovere -1 dopo il conteggio ($ ids) perché funzionasse per me o mancava sempre un segnaposto.
Marcel Burkhard,

7

che database stai usando? In PostgreSQL mi piace usare ANY (array). Quindi, per riutilizzare il tuo esempio:

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

Purtroppo questo è piuttosto non portatile.

Su altri database dovrai creare la tua magia come altri hanno già detto. Avrai voglia di mettere quella logica in una classe / funzione per renderla riutilizzabile ovviamente durante il tuo programma. Dai un'occhiata ai commenti sulla mysql_querypagina su PHP.NET per ulteriori riflessioni sull'argomento e sugli esempi di questo scenario.


4

Dopo aver affrontato lo stesso problema, sono andato a una soluzione più semplice (anche se ancora non elegante come PDO::PARAM_ARRAYsarebbe):

dato l'array $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();

... e così via

Quindi se stai usando un array di valori misti, avrai bisogno di più codice per testare i tuoi valori prima di assegnare il tipo param:

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

Ma non ho provato questo.


4

Come so, non esiste alcuna possibilità di associare un array all'istruzione DOP.

Ma esistono 2 soluzioni comuni:

  1. Usa segnaposto posizionali (?,?,?,?) O segnaposto nominati (: id1,: id2,: id3)

    $ whereIn = implode (',', array_fill (0, count ($ ids), '?'));

  2. Citazione array in precedenza

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

Entrambe le opzioni sono buone e sicure. Preferisco il secondo perché è più corto e posso var_dump parametri se ne ho bisogno. Utilizzando i segnaposto è necessario associare i valori e alla fine il codice SQL sarà lo stesso.

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

E l'ultimo e importante per me è evitare l'errore "il numero di variabili associate non corrisponde al numero di token"

La dottrina è un ottimo esempio dell'uso di segnaposto posizionali, solo perché ha il controllo interno sui parametri in arrivo.


4

Se la colonna può contenere solo numeri interi, è possibile farlo senza segnaposto e inserire direttamente gli ID nella query. Devi solo trasmettere tutti i valori dell'array a numeri interi. Come questo:

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

Questo non dovrebbe essere vulnerabile a nessuna iniezione SQL.


3

ecco la mia soluzione. Ho anche esteso la classe DOP:

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

Ecco un esempio di utilizzo per il codice sopra:

$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'];
}

Fatemi sapere cosa ne pensate


Hai dimenticato di dire che questo si basa sulla risposta dell'utente2188977, di seguito.
Lippai Zoltan,

Non sono sicuro di cosa sia getOne (), non sembra far parte di DOP. L'ho visto solo in PERA. Che cosa fa esattamente?
Lippai Zoltan,

@YourCommonSense puoi pubblicare la tua funzione definita dall'utente come risposta?
nullability

Suggerirei di passare il tipo di dati BindArrayParamnell'array associativo poiché sembra che tu stia limitando questo a numeri interi.
Ian Brindley,

2

Non è possibile utilizzare un array come quello in DOP.

Devi creare una stringa con un parametro (o utilizzare?) Per ciascun valore, ad esempio:

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

Ecco un esempio:

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

Se si desidera continuare a utilizzare bindParam, è possibile farlo invece:

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

Se si desidera utilizzare i ?segnaposto, è possibile farlo in questo modo:

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

Se non sai se $idsè vuoto, dovresti testarlo e gestire il caso di conseguenza (restituisce un array vuoto, o restituisce un oggetto null, o genera un'eccezione, ...).


0

Ho preso un po 'di più per avvicinare la risposta alla domanda originale sull'utilizzo dei segnaposto per associare i parametri.

Questa risposta dovrà effettuare due cicli attraverso l'array da utilizzare nella query. Ma risolve il problema di avere altri segnaposto di colonna per query più selettive.

//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

hai prima impostato il numero di "?" in query e quindi da un "per" inviare parametri come questo:

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);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.