क्या मैं किसी सरणी को IN () स्थिति में बाँध सकता हूँ?


562

मुझे यह जानने की उत्सुकता है कि क्या पीडीओ का उपयोग करके किसी प्लेसहोल्डर के लिए मूल्यों की एक सरणी को बांधना संभव है। यहां उपयोग मामला एक IN()शर्त के साथ उपयोग के लिए मूल्यों की एक सरणी को पारित करने का प्रयास कर रहा है ।

मैं ऐसा कुछ करने में सक्षम होना चाहता हूं:

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

और पीडीओ बाँध और सरणी में सभी मूल्यों को उद्धृत किया है।

फिलहाल मैं कर रहा हूँ:

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

जो निश्चित रूप से काम करता है, लेकिन सोच रहा था कि क्या कोई समाधान है जो मुझे याद आ रहा है?


3
किसी सरणी को IN () कंडीशन में बाँधने पर एक पूरा गाइड , जब आप क्वेरी में अन्य प्लेसहोल्डर होते हैं तो केस सहित
आपका कॉमन सेंस

इस प्रश्न के डुप्लिकेट के रूप में प्रश्न को बंद कर दिया गया था । मैंने डुप्लिकेट ध्वज को उलट दिया क्योंकि यह प्रश्न 4 साल पुराना है, इसमें 4 बार विचार, 3 बार उत्तर की संख्या और 12 बार स्कोर है। यह स्पष्ट रूप से बेहतर लक्ष्य है।
miken32

2020 में इसे देखने वाला कोई भी व्यक्ति: आप इसके लिए github.com/morris/dop की कोशिश कर सकते हैं ।
मॉरिस

जवाबों:


262

मुझे लगता है कि आत्मीयता सही है। आपको क्वेरी-स्ट्रिंग का निर्माण करना होगा।

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

तय: दान, आप सही थे। कोड तय किया (हालांकि यह परीक्षण नहीं किया है)

संपादित करें: दोनों क्रिस (टिप्पणियां) और किसी ने बताया कि फॉरच-लूप ...

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

$stmt->execute();

... निरर्थक हो सकता है, इसलिए foreachपाश और $stmt->executeबस द्वारा प्रतिस्थापित किया जा सकता है ...

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

(फिर, मैंने इसका परीक्षण नहीं किया)


7
यह एक दिलचस्प समाधान है, और जब मैं इसे आईडी पर पुनरावृत्ति करना और पीडीओ को कॉल करना पसंद करता हूं :: उद्धरण (), मुझे लगता है कि 'का सूचकांक?' यदि कोई अन्य प्लेसहोल्डर क्वेरी में कहीं और सही है, तो प्लेसहोल्डर्स गड़बड़ करने जा रहे हैं?
एंडरू

5
हाँ, यह एक समस्या होगी। लेकिन इस मामले में आप के बजाय नामित पैरामीटर बना सकते हैं?
stefs

9
पुराने सवाल है, लेकिन ध्यान देने योग्य बात मेरा मानना है कि मूल्य, कि है $foreachऔर bindValue()सिर्फ सरणी के साथ निष्पादित - आवश्यकता नहीं है। जैसे:$stmt->execute($ids);
क्रिस

2
प्लेसहोल्डर्स को उत्पन्न करना इस तरह से किया जाना चाहिएstr_repeat('?,', count($array) - 1). '?';
Xeoncross

8
उन अनजान लोगों के लिए सिर्फ एक टिप, आप नाम और अनाम पैरामीटर को नहीं मिला सकते हैं। इसलिए यदि आप अपनी क्वेरी में नामित मापदंडों का उपयोग करते हैं, तो उन्हें स्विच आउट करें? और फिर IN की स्थिति से मिलान करने के लिए अपने bindValue इंडेक्स ऑफ़सेट को बढ़ाएँ? जहाँ भी वे आपके अन्य के सापेक्ष हैं? पैरामीटर।
जस्टिन

169

कुछ जल्दी के लिए:

//$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
बहुत बढ़िया, मैंने इस तरह से input_parameters तर्क का उपयोग करने के लिए नहीं सोचा था। जिनके प्रश्नों में IN सूची से अधिक पैरामीटर हैं, आप सरणी के सामने और अंत में आवश्यक तर्क जोड़ने के लिए array_unshift और array_push का उपयोग कर सकते हैं। इसके अलावा, मैं पसंद करता हूं $input_list = substr(str_repeat(',?', count($ids)), 1);
orca

7
आप भी आजमा सकते हैं str_repeat('?,', count($ids) - 1) . '?'। एक कम फ़ंक्शन कॉल।
ओर्का

5
@ हेफ़्लिंग, यह एक तैयार कथन है, इंजेक्शन कहाँ से आने वाला है? अगर आप इसे वापस ले सकते हैं, तो आपको किसी भी सुधार के लिए खुशी होगी।
18

5
@ हेरिंग, हां, यह सही है, और परम को बांधना बिल्कुल वैसा ही है जैसा हम इस उदाहरण में कर रहे हैं कि execute
आइडी

5
ओह वास्तव में। किसी तरह इस तथ्य को याद किया कि आप सरणी से गुजर रहे थे। यह वास्तव में सुरक्षित और एक अच्छा जवाब प्रतीत होता है। मैं क्षमाप्रार्थी हूं।
erfling

46

क्या INकथन का उपयोग करना इतना महत्वपूर्ण है ? FIND_IN_SETसेशन का उपयोग करने का प्रयास करें ।

उदाहरण के लिए, पीडीओ में एक क्वेरी होती है

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

तब आपको केवल इस तरह के अल्पविराम से निहित मूल्यों की एक सरणी को बांधने की जरूरत है

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

और हो गया।

UPD: जैसा कि कुछ लोगों ने इस उत्तर में टिप्पणियों में बताया है, कुछ मुद्दे हैं, जिन्हें विस्फोटक रूप से बताया जाना चाहिए।

  1. FIND_IN_SETतालिका में अनुक्रमणिका का उपयोग नहीं करता है, और यह अभी भी लागू नहीं हुआ है - MYSQL बग ट्रैकर में इस रिकॉर्ड को देखें । नोटिस के लिए @BillKarwin को धन्यवाद।
  2. आप खोज के लिए सरणी के मान के रूप में अल्पविराम के साथ एक स्ट्रिंग का उपयोग नहीं कर सकते। implodeजब आप विभाजक के रूप में अल्पविराम चिह्न का उपयोग करते हैं, तो इस तरह के स्ट्रिंग को सही तरीके से पार्स करना असंभव है । नोट के लिए @VaL को धन्यवाद।

ठीक है, यदि आप अनुक्रमित पर बहुत अधिक निर्भर नहीं हैं और खोज के लिए अल्पविराम के साथ तार का उपयोग नहीं करते हैं, तो मेरा समाधान ऊपर सूचीबद्ध समाधानों की तुलना में बहुत आसान, सरल और तेज़ होगा।


25
IN () एक इंडेक्स का उपयोग कर सकता है, और एक रेंज स्कैन के रूप में गिना जाता है। FIND_IN_SET () एक इंडेक्स का उपयोग नहीं कर सकता।
बिल कारविन ऑक्ट

1
वह एक बिंदु है। मुझे इसकी जानकारी नहीं थी। लेकिन किसी भी तरह से प्रश्न में प्रदर्शन की कोई आवश्यकता नहीं है। इतनी बड़ी तालिकाओं के लिए यह अलग-अलग वर्ग की तुलना में बहुत अधिक बेहतर और साफ-सुथरा नहीं है, क्योंकि अलग-अलग संख्या में प्लेसहोल्डर्स के साथ क्वेरी उत्पन्न करने के लिए।
टिम टोंकोनोगोव

11
हां, लेकिन इन दिनों किसके पास इतनी बड़ी मेज नहीं है? ;-)
बिल कारविन

3
इस दृष्टिकोण के साथ एक और समस्या यह है कि क्या होगा अगर अंदर कॉमा के साथ स्ट्रिंग होगी? उदाहरण के लिए ... FIND_IN_SET(description,'simple,search')काम करेंगे, लेकिन FIND_IN_SET(description,'first value,text, with coma inside')असफल रहेंगे। तो फ़ंक्शन "first value", "text", "with coma inside" वांछित के बजाय खोज करेगा "first value", "text, with coma inside"
VaL

33

चूंकि मैं बहुत सारे गतिशील प्रश्न करता हूं, यह एक सुपर सरल सहायक फ़ंक्शन है जिसे मैंने बनाया है।

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

इसे इस तरह उपयोग करें:

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

एक स्ट्रिंग लौटाता है :id1,:id2,:id3और आपके $bindArrayबाइंडिंग के बारे में भी अपडेट करता है , जिसे आपको अपनी क्वेरी चलाने के लिए समय की आवश्यकता होगी। आसान!


6
यह एक बेहतर समाधान है, क्योंकि यह मापदंडों के नियम के बंधन को नहीं तोड़ता है। यहाँ कुछ अन्य लोगों द्वारा प्रस्तावित इनलाइन एसक्यूएल होने की तुलना में यह अधिक सुरक्षित है।
दिमितर दराज़न्स्की

1
त। सुरुचिपूर्ण। उत्तम।
रिटिकलिन

17

EvilRygy से समाधान मेरे लिए काम नहीं किया। Postgres में आप एक और समाधान कर सकते हैं:


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

यह काम नहीं करता है ERROR: operator does not exist: integer = text:। कम से कम आपको स्पष्ट कास्टिंग जोड़ने की आवश्यकता है।
कोलीमारको

17

पोस्टग्रेज के लिए बहुत साफ तरीका पोस्टग्रेज-ऐरे ("{}") का उपयोग कर रहा है:

$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 इंजेक्शन को रोकता है?
फोबियो जांगिरोलमी

1
@ FábioZangirolami यह पीडीओ है, तो हाँ।
ESCOBAR

हाँ, पीडीओ! 4 साल बाद। आपकी प्रतिक्रिया मेरे लिए बहुत ही सरल और प्रभावी थी। धन्यवाद!!!
फाबियो जांगिरोलमी

14

यहाँ मेरा समाधान है:

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

Array_values ​​के उपयोग पर ध्यान दें। यह महत्वपूर्ण आदेश समस्याओं को ठीक कर सकता है।

मैं आईडी के एरेज़ को मर्ज कर रहा था और फिर डुप्लिकेट आइटम हटा रहा था। मेरे पास कुछ ऐसा था:

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

और वह असफल हो रहा था।


यह एक उत्कृष्ट समाधान था। यह क्वेरी स्ट्रिंग के निर्माण के विपरीत है, यह सही ढंग से बाइंडिंग का उपयोग करता है। मैं दृढ़ता से यह सलाह देता हूं।
लिंडलीड

नोट: अपने समाधान का उपयोग करके, आप सरणी के आगे या पीछे आइटम जोड़ सकते हैं, ताकि आप अन्य बाइंडिंग शामिल कर सकें। $original_array मूल सरणी से पहले आइटम जोड़ें: मूल सरणी के array_unshift($original_array, new_unrelated_item); बाद आइटम जोड़ें: array_push($original_array, new_unrelated_item); जब मानों को बाध्य किया जाता है, तो नए_संबंधित आइटम सही स्थानों पर रखे जाएंगे। यह आपको ऐरे और गैर-सरणी आइटम को मिलाने की अनुमति देता है। `
लिंडलाइड

12

मैंने पीडीओ को कुछ ऐसा करने के लिए बढ़ाया, जो सीढ़ियों का सुझाव देता है, और लंबे समय में यह मेरे लिए आसान था:

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

आप इसे इस तरह से उपयोग कर सकते हैं:

$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
मैंने मार्क की टिप्पणी के पहले भाग को संबोधित किया है, लेकिन जैसा कि उन्होंने बताया, यह अभी भी सुरक्षित नहीं है अगर एक टोकन :arrayक्वेरी में एक स्ट्रिंग में है।
क्रिस

4
सभी भविष्य के पाठकों के लिए एक नोट: इस समाधान का उपयोग कभी नहीं किया जाना चाहिए। उत्पादन कोड के लिए अभिप्रेत नहीं हैं
आपका कॉमन सेंस

1
वाईसीएस: फीडबैक के लिए धन्यवाद, आपकी राय के बाहर के दृष्टिकोण के बारे में आपकी राय में दिलचस्पी है।
क्रिस

1
यह विचार बहुत ही समान है, लेकिन बिना जोर के और अधिक सीधे और स्पष्ट तरीके से - केवल एक मामले के अपवाद के रूप में नहीं, बल्कि प्रत्येक क्वेरी के निर्माण के सामान्य तरीके के रूप में। प्रत्येक प्लेसहोल्डर को इसके प्रकार के साथ चिह्नित किया गया है। यह अनुमान (जैसे if (is_array($data))एक) को अनावश्यक बनाता है फिर भी डेटा प्रोसेसिंग के तरीके को अधिक सटीक बनाता है।
आपका कॉमन सेंस

1
टिप्पणियों को पढ़ने वाले किसी भी व्यक्ति को: @ योर कॉमन सेंस द्वारा उल्लिखित मुद्दा संशोधन 4 में तय किया गया है ।
user2428118

11

पीडीओ को देखते हुए : पूर्वनिर्धारित स्थिरांक कोई पीडीओ नहीं है :: PARAM_ARRAY जिसकी आपको आवश्यकता है जैसा कि PDOStatement-> bindParam पर सूचीबद्ध है

बूल PDOStatement :: bindParam (मिश्रित $ पैरामीटर, मिश्रित और $ चर [, int $ data_type [, int $ length [, मिश्रित $ driver_options]]])

इसलिए मुझे नहीं लगता कि यह प्राप्त करने योग्य है।


1
मुझे नहीं पता कि क्या काम करता है। मुझे लगता है कि फंस स्ट्रिंग उद्धृत किया जाएगा।
आत्माभिव्यक्ति

2
आप सही हैं, उद्धरण से बच गए ताकि जीत गए; काम नहीं। मैंने वह कोड हटा दिया है।

11

जब आपके पास अन्य पैरामीटर हैं, तो आप इस तरह कर सकते हैं:

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

महान जवाब के लिए धन्यवाद। यह उन सभी में से एक था जिसने वास्तव में मेरे लिए काम किया। हालाँकि, मैंने 1 गलती देखी। चर $ rs $ stmt होना चाहिए
Piet

11

मेरे लिए सेक्सियर समाधान एक गतिशील साहचर्य सरणी का निर्माण करना और उसका उपयोग करना है

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

वास्तविक परिदृश्य में इसे आज़माए बिना कुछ निश्चित होना मुश्किल है, लेकिन ठीक लगता है। + 1
अनंत सिंह --- 4

9

मुझे यह भी एहसास है कि यह धागा पुराना है, लेकिन मुझे एक अनोखी समस्या थी, जहां जल्द ही होने वाले मायस्किल ड्राइवर को पीडीओ ड्राइवर में परिवर्तित करते हुए, मुझे एक ऐसा फंक्शन बनाना था, जो सामान्य रूप से दोनों ही सामान्य पैरेम्स और आईएनएस का निर्माण कर सके। परम सरणी। इसलिए मैंने जल्दी से इसे बनाया:

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

यह अभी भी अप्रयुक्त है लेकिन तर्क वहाँ लगता है।

आशा है कि यह किसी को एक ही स्थिति में मदद करता है,

संपादित करें: कुछ परीक्षण के बाद मुझे पता चला:

  • पीडीओ को पसंद नहीं है '।' उनके नाम में (जो थोड़े बेवकूफ हैं अगर आप मुझसे पूछें)
  • bindParam गलत कार्य है, bindValue सही कार्य है।

कोड को कार्यशील संस्करण में संपादित किया गया।


8

श्नेल के कोड के बारे में थोड़ा संपादन

<?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
मुझे इसके लिए काम करने के लिए गिनती ($ आईडी) के बाद -1 को निकालना था या हमेशा एक प्लेसहोल्डर गायब था।
मार्सेल बुर्खार्ड

7

आप किस डेटाबेस का उपयोग कर रहे हैं? PostgreSQL में मैं किसी भी (सरणी) का उपयोग करना पसंद करता हूं। इसलिए अपने उदाहरण का पुन: उपयोग करें:

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

दुर्भाग्य से यह बहुत गैर पोर्टेबल है।

अन्य डेटाबेस पर आपको अपना खुद का जादू बनाने की आवश्यकता होगी जैसा कि अन्य उल्लेख कर रहे हैं। आप उस तर्क को एक कक्षा / समारोह में रखना चाहते हैं ताकि वह आपके कार्यक्रम के दौरान पुन: प्रयोज्य बन सके। mysql_queryइस परिदृश्य के विषय और उदाहरणों पर कुछ और विचारों के लिए PHP.NET पर पृष्ठ की टिप्पणियों पर एक नज़र डालें ।


4

उसी समस्या से गुजरने के बाद, मैं एक सरल समाधान पर चला गया (हालांकि अभी भी उतना सुरुचिपूर्ण नहीं PDO::PARAM_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();

... और इसी तरह

इसलिए यदि आप मिश्रित मान सरणी का उपयोग कर रहे हैं, तो आपको टाइप करने से पहले अपने मानों को परखने के लिए अधिक कोड की आवश्यकता होगी:

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

लेकिन मैंने इसका परीक्षण नहीं किया है।


4

जैसा कि मुझे पता है कि पीडीओ स्टेटमेंट में किसी सरणी को बांधने की कोई संभावना नहीं है।

लेकिन 2 सामान्य समाधान मौजूद हैं:

  1. स्थितीय प्लेसहोल्डर (?,?;?) या नामित प्लेसहोल्डर्स (: id1,: id2,: id3) का उपयोग करें

    $ जहाँ = निहित (',', array_fill (0, गिनती ($ ids), '?'));

  2. उद्धरण सरणी पहले

    $ जहाँ = array_map (सरणी ($ db, 'उद्धरण'), $ id);

दोनों विकल्प अच्छे और सुरक्षित हैं। मैं दूसरा पसंद करता हूं क्योंकि यह छोटा है और अगर मुझे इसकी आवश्यकता है तो मैं var_dump पैरामीटर कर सकता हूं। प्लेसहोल्डर्स का उपयोग करके आपको मूल्यों को बांधना होगा और अंत में आपका SQL कोड समान होगा।

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

और मेरे लिए अंतिम और महत्वपूर्ण त्रुटि से बचना है "बाध्य चर की संख्या टोकन की संख्या से मेल नहीं खाती"

सिद्धांत यह स्थैतिक प्लेसहोल्डर्स का उपयोग करने का महान उदाहरण है, केवल इसलिए कि आने वाले मापदंडों पर इसका आंतरिक नियंत्रण है।


4

यदि कॉलम में केवल पूर्णांक हो सकते हैं, तो आप संभवतः प्लेसहोल्डर्स के बिना ऐसा कर सकते हैं और आईडी को सीधे क्वेरी में डाल सकते हैं। आपको केवल सरणी के सभी मानों को पूर्णांक में डालना होगा। ऐशे ही:

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

यह किसी भी SQL इंजेक्शन के लिए असुरक्षित नहीं होना चाहिए।


3

यहाँ मेरा समाधान है। मैंने पीडीओ वर्ग भी बढ़ाया है:

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

यहाँ उपरोक्त कोड के लिए एक नमूना उपयोग है:

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

आप क्या सोचते हैं मुझे बताओ


यह उल्लेख करना भूल गए कि यह नीचे user2188977 के उत्तर पर आधारित है।
लिपाई झोल्टन

मुझे यकीन नहीं है कि getOne () क्या है, यह पीडीओ का हिस्सा नहीं लगता। मैंने इसे केवल PEAR में देखा है। यह वास्तव में क्या करता है?
लीपई जोल्तान

@YourCommonSense क्या आप अपने उपयोगकर्ता-परिभाषित फ़ंक्शन को उत्तर के रूप में पोस्ट कर सकते हैं?
अशक्तता

मेरा सुझाव है कि डेटा प्रकार को BindArrayParamसाहचर्य सरणी में पास किया जाए क्योंकि आप पूर्णांकों तक इसे सीमित कर रहे हैं।
इयान ब्रिंडले

2

पीडीओ में उस तरह के एक सरणी का उपयोग करना संभव नहीं है।

आपको प्रत्येक मान के लिए एक पैरामीटर (या उपयोग?) के साथ एक स्ट्रिंग बनाने की आवश्यकता है, उदाहरण के लिए:

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

यहाँ एक उदाहरण है:

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

यदि आप उपयोग करते रहना चाहते हैं bindParam, तो आप इसके बजाय ऐसा कर सकते हैं:

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

यदि आप ?प्लेसहोल्डर्स का उपयोग करना चाहते हैं , तो आप इसे इस तरह कर सकते हैं:

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

यदि आप नहीं जानते कि $idsक्या खाली है, तो आपको इसका परीक्षण करना चाहिए और उस मामले को तदनुसार संभालना चाहिए (खाली सरणी लौटाएं, या अशक्त वस्तु लौटाएं, या एक अपवाद फेंक दें ...)।


0

पार्म्स को बांधने के लिए प्लेसहोल्डर्स का उपयोग करने के मूल प्रश्न के उत्तर को प्राप्त करने के लिए मैंने इसे थोड़ा आगे ले लिया।

इस उत्तर को क्वेरी में उपयोग की जाने वाली सरणी के माध्यम से दो छोरों को बनाना होगा। लेकिन यह अधिक चयनात्मक प्रश्नों के लिए अन्य कॉलम प्लेसहोल्डर होने के मुद्दे को हल करता है।

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

आप पहले "?" क्वेरी में और फिर "के लिए" इस तरह से पैरामीटर भेजें:

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);
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.