PHP - PDO का उपयोग IN में क्लाज सरणी के साथ


82

मैं पीडीओ का INउपयोग उस खंड के साथ एक कथन को निष्पादित करने के लिए कर रहा हूं जो अपने मूल्यों के लिए एक सरणी का उपयोग करता है:

$in_array = array(1, 2, 3);
$in_values = implode(',', $in_array);
$my_result = $wbdb->prepare("SELECT * FROM my_table WHERE my_value IN (".$in_values.")");
$my_result->execute();
$my_results = $my_result->fetchAll();

उपरोक्त कोड पूरी तरह से ठीक काम करता है, लेकिन मेरा सवाल यह है कि यह क्यों नहीं है:
 $in_array = array(1, 2, 3);
    $in_values = implode(',', $in_array);
    $my_result = $wbdb->prepare("SELECT * FROM my_table WHERE my_value IN (:in_values)");
    $my_result->execute(array(':in_values' => $in_values));
    $my_results = $my_result->fetchAll();

यह कोड उस आइटम को लौटाएगा जिसका my_valueपहला आइटम $in_array(1) में बराबर है , लेकिन सरणी (2, और 3) में शेष आइटम नहीं हैं।


देखें इस । देखें कि क्या यह मदद कर सकता है।
भाविक शाह Shah

एक API के लिए github.com/morris/dop देखें जो सरणी पैरामीटर (और अधिक, जैसे NULL और SQL टुकड़े) को संभालने में सक्षम है।
morris4

जवाबों:


114

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

$in  = str_repeat('?,', count($in_array) - 1) . '?';
$sql = "SELECT * FROM my_table WHERE my_value IN ($in)";
$stm = $db->prepare($sql);
$stm->execute($in_array);
$data = $stm->fetchAll();

यदि क्वेरी में अन्य प्लेसहोल्डर हैं, तो आप निम्नलिखित दृष्टिकोण का उपयोग कर सकते हैं (कोड मेरे पीडीओ ट्यूटोरियल से लिया गया है ):

आप array_merge()सभी चर को एक सरणी में शामिल करने के लिए फ़ंक्शन का उपयोग कर सकते हैं , सरणियों के रूप में अपने अन्य चर को जोड़ते हुए, जिस क्रम में वे आपकी क्वेरी में दिखाई देते हैं:

$arr = [1,2,3];
$in  = str_repeat('?,', count($arr) - 1) . '?';
$sql = "SELECT * FROM table WHERE foo=? AND column IN ($in) AND bar=? AND baz=?";
$stm = $db->prepare($sql);
$params = array_merge([$foo], $arr, [$bar, $baz]);
$stm->execute($params);
$data = $stm->fetchAll();

यदि आप नामित प्लेसहोल्डर का उपयोग कर रहे हैं, तो कोड थोड़ा अधिक जटिल होगा, क्योंकि आपको नामित प्लेसहोल्डर्स का एक क्रम बनाना होगा, जैसे :id0,:id1,:id2। तो कोड होगा:

// other parameters that are going into query
$params = ["foo" => "foo", "bar" => "bar"];

$ids = [1,2,3];
$in = "";
$i = 0;// we are using an external counter 
// because the actual array keys could be dangerous
foreach ($ids as $item)
{
    $key = ":id".$i++;
    $in .= "$key,";
    $in_params[$key] = $item; // collecting values into a key-value array
}
$in = rtrim($in,","); // :id0,:id1,:id2

$sql = "SELECT * FROM table WHERE foo=:foo AND id IN ($in) AND bar=:bar";
$stm = $db->prepare($sql);
$stm->execute(array_merge($params,$in_params)); // just merge two arrays
$data = $stm->fetchAll();

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


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

2
क्या आप बता सकते हैं कि इसके -1बाद क्या है count()?
रॉबर्ट रोचा

2
@RobertRocha मुझे लगता है कि प्लेसहोल्डर एरे को जेनरेट करने का एक साफ-सुथरा तरीका हो सकता है $in = implode(',', array_fill(0, count($in_array), '?'));- किसी भी अजीब ऑफ-बाय या स्ट्रिंग
समवर्ती

1
@YourCommonSense यह इस तरह के एक सामान्य मुद्दे का सबसे अच्छा जवाब है, धन्यवाद!
डिजिटै

1
-1 के बिना$in = rtrim(str_repeat('?,', count($array)), ',');
बॉसमैन

15

पीडीओ तैयार बयानों में परिवर्तनीय प्रतिस्थापन सरणियों का समर्थन नहीं करता है। यह एक के लिए एक है।

आप सरणी की लंबाई के आधार पर आवश्यक प्लेसहोल्डर्स की संख्या को उत्पन्न करके उस समस्या को हल कर सकते हैं।

$variables = array ('1', '2', '3');
$placeholders = str_repeat ('?, ',  count ($variables) - 1) . '?';

$query = $pdo -> prepare ("SELECT * FROM table WHERE column IN($placeholders)");
if ($query -> execute ($variables)) {
    // ...
}

क्यों count ($variables) - 1) . '?';क्यों बस नहींcount($variable)
रॉबर्ट रोचा

2
@ रोबर्ट रोचा क्योंकि आपको चर की तुलना में एक कम अल्पविराम की आवश्यकता है
गॉर्डन

मैंने सरणी का उपयोग करके कथन निष्पादित करने में एक और चर जोड़ने की कोशिश की है लेकिन यह काम नहीं कर रहा है।
उस्मा अहमद

4

चूंकि पीडीओ एक अच्छा समाधान प्रदान नहीं करता है, इसलिए आप डीबीएएल का उपयोग करने पर विचार कर सकते हैं, जो ज्यादातर पीडीओ के एपीआई का अनुसरण करता है, लेकिन साथ ही कुछ उपयोगी विशेषताएं भी जोड़ता है http://docs.doctrine-project.org/projects/doctrine-dbal/ en / नवीनतम / संदर्भ / डेटा-पुनः प्राप्ति और जोड़-तोड़। html # सूची-के-मापदंडों-रूपांतरण

$stmt = $conn->executeQuery('SELECT * FROM articles WHERE id IN (?)',
    array(array(1, 2, 3, 4, 5, 6)),
    array(\Doctrine\DBAL\Connection::PARAM_INT_ARRAY)
);

वहाँ शायद कुछ अन्य पैकेज हैं जो जटिलता को नहीं जोड़ते हैं और डेटाबेस के साथ बातचीत को अस्पष्ट नहीं करते हैं (जैसे अधिकांश ओआरएम करते हैं), लेकिन एक ही समय में छोटे ठेठ कार्यों को थोड़ा आसान बनाते हैं।


2

क्लोजर का उपयोग करके PHP Delusions (@ your-common-sense) का एक वैकल्पिक संस्करण:

$filter      = ["min_price" => "1.98"];
$editions    = [1,2,10];

$editions = array_combine(
    array_map(function($i){ return ':id'.$i; }, array_keys($editions)),
    $editions
);
$in_placeholders = implode(',', array_keys($editions));
$sql = "SELECT * FROM books WHERE price >= :min_price AND edition IN ($in_placeholders)";
$stm = $pdo->prepare($sql);
$stm->execute(array_merge($filter,$editions));
$data = $stm->fetchAll();

0

जैसा कि मैं समझता हूं कि यह इसलिए है क्योंकि पीडीओ एक सामग्री के रूप में $ in_values ​​सामग्री का इलाज करेगा और इसके अनुसार काफी होगा। पीडीओ 1,2,3 को एक स्ट्रिंग के रूप में देखेगा ताकि क्वेरी कुछ इस तरह दिखाई देगी

चयन करें * तालिका से कहाँ my_value IN ("1,2,3")

आप सोच सकते हैं कि उद्धरण और अल्पविराम लगाने के लिए आघात को बदलना इसे ठीक कर देगा, लेकिन यह नहीं होगा। पीडीओ उद्धरणों को देखेगा और यह बदलेगा कि यह स्ट्रिंग को कैसे उद्धृत करता है।

जैसे कि आपकी क्वेरी पहले मान से मेल क्यों खाती है, मेरे पास कोई स्पष्टीकरण नहीं है।


0

मैं अभी इस समस्या के खिलाफ आया हूं और एक छोटे आवरण को कोडित किया है। यह सबसे अच्छा या सबसे अच्छा कोड नहीं है जो मुझे यकीन है, लेकिन यह किसी व्यक्ति की मदद कर सकता है इसलिए यह यहाँ है:

function runQuery(PDO $PDO, string $sql, array $params = [])
{
    if (!count($params)) {
        return $PDO->query($sql);
    }

    foreach ($params as $key => $values) {
        if (is_array($values)) {
            // get placeholder from array, e.g. ids => [7,12,3] would be ':ids'
            $oldPlaceholder  = ':'.$key;
            $newPlaceholders = '';
            $newParams = [];
            // loop through array to create new placeholders & new named parameters
            for($i = 1; $i <= count($values); $i++) {
                // this gives us :ids1, :ids2, :ids3 etc
                $newKey = $oldPlaceholder.$i;
                $newPlaceholders .= $newKey.', ';
                // this builds an associative array of the new named parameters
                $newParams[$newKey] = $values[$i - 1];
            }
            //trim off the trailing comma and space
            $newPlaceholders = rtrim($newPlaceholders, ', ');

            // remove the old parameter
            unset($params[$key]);

            // and replace with the new ones
            $params = array_merge($params, $newParams);

            // amend the query
            $sql = str_replace($oldPlaceholder, $newPlaceholders, $sql);
        }
    }

    $statement = $PDO->prepare($sql);
    $statement->execute($params);
    return $statement;
}

जैसे, इनमें से गुजरना:

SELECT * FROM users WHERE userId IN (:ids)

array(1) {
  ["ids"]=>
  array(3) {
    [0]=>
    int(1)
    [1]=>
    int(2)
    [2]=>
    int(3)
  }
}

बन जाता है:

SELECT * FROM users WHERE userId IN (:ids1, :ids2, :ids3)

array(3) {
  [":ids1"]=>
  int(1)
  [":ids2"]=>
  int(2)
  [":ids3"]=>
  int(3)
}

यह बुलेटप्रूफ नहीं है, लेकिन मेरी जरूरतों के लिए एक एकमात्र देव के रूप में यह ठीक काम करता है, अब तक वैसे भी।


0

यहाँ अनाम प्लेसहोल्डर्स (?) के लिए एक समाधान है। यदि आप "A =? और B IN (?)" जैसे $ चिह्न के साथ $ sql पास करते हैं और $ args जहां कुछ तत्व सरणियों जैसे हैं [1, [1,2,3]] तो यह SQL स्ट्रिंग को उचित संख्या के साथ लौटाएगा प्लेसहोल्डर्स की - "A =? और B IN (?;?)?" । इसे खोजने के लिए केवल $ args पैरामीटर की आवश्यकता है कि कौन सा तत्व सरणी है और कितने प्लेसहोल्डर को इसकी आवश्यकता है। आप इस विधि से छोटी पीडीओ एक्सटेंशन क्लास पा सकते हैं जो आपकी क्वेरी चलाएगी: https://github.com/vicF/pdo/blob/master/src/PDO.php

public function replaceArrayPlaceholders($sql, $args)
{
    $num = 0;
    preg_match_all('/\?/', $sql, $matches, PREG_OFFSET_CAPTURE);  // Captures positions of placeholders
    //echo $matches[0][1][1];
    $replacements = [];
    foreach($args as $arg) {
        if(is_array($arg)) {
            $replacements[$matches[0][$num][1]] = implode(',',array_fill(0, count($arg), '?')); // Create placeholders string
        }
        $num++;
    }
    krsort($replacements);
    foreach($replacements as $position => $placeholders) {
        $sql = substr($sql, 0, $position).$placeholders.substr($sql, $position+1); // Replace single placeholder with multiple
    }
    return $sql;
}

0

यहाँ मेरा पूरा कोड है, मेरी बेवकूफ कोडिंग, खराब संरचना और टिप्पणी लाइनों के लिए खेद है। शायद किसी ने मेरा बेवकूफ कोड फिर से बनाया :)

कक्षा में भेजना:

$veri_sinifi = new DB_Connect;
                          $veri_sorgu_degerleri=array(
                            "main_user_id" => (int)$_SESSION['MM_UserId'],
                            "cari_grup_id" => [71,72,73],
                            "cari_grup_adi" => ['fatih','ahmet','ali']                       
                          );                              
                          $siteler =$veri_sinifi->query("Select cari_grup_adi,cari_grup_id FROM m_cari_gruplar WHERE main_user_id= :main_user_id and cari_grup_id in (:cari_grup_id) and cari_grup_adi in (:cari_grup_adi)",$veri_sorgu_degerleri) ; 

वर्ग इस वर्ग प्राप्त करें:

Select cari_grup_adi,cari_grup_id FROM m_cari_gruplar WHERE main_user_id= :main_user_id and cari_grup_id in (:cari_grup_id) and cari_grup_adi in (:cari_grup_adi) 

वर्ग इस sql को इसे रूपांतरित करता है।

Select cari_grup_adi,cari_grup_id FROM m_cari_gruplar WHERE main_user_id= :main_user_id and cari_grup_id in (:cari_grup_id0,:cari_grup_id1,:cari_grup_id2) and cari_grup_adi in (:cari_grup_adi0,:cari_grup_adi1,:cari_grup_adi2)

क्लास बाइंडिंग परमेस:

 Select cari_grup_adi,cari_grup_id FROM m_cari_gruplar WHERE main_user_id= 1 and cari_grup_id in (71,72,73) and cari_grup_adi in ('fatih','ahmet','ali')

कोड:

class DB_Connect{
var $dbh;
function __construct(){
    $host = "";
    $db = "";
    $user = "";
    $password = "";
    $this -> dbh = $this -> db_connect($host, $db, $user, $password);
}
public function getDBConnection(){
    return $this -> dbh;
}
protected function db_connect($host, $db, $user, $password){
    //var_dump($host, $db, $user, $password);exit();
    try {
        $dbh = new PDO("mysql:host=$host;dbname=$db", $user, $password);
    }
    catch(PDOException $err) {
        echo "Error: ".$err->getMessage()."<br/>";
        die();
    }
    return $dbh;
}
public function query($statement,$bind_params){
    $keyword = substr(strtoupper($statement), 0, strpos($statement, " ")); // sql in en başındaki kelimeye bakıyor SELECT UPDATE vs gibi ordaki ilk boşluğa kadar olan kelimeyi alıyor.
  //echo $keyword;
    $dbh = $this->getDBConnection();        
    if($dbh){
        try{
            $sql = $statement;
            /*GELEN PARAMETRELERE BAKIP İÇİNDE ARRAY VAR İSE SQL STATEMENT KISMINI ONA GÖRE DEĞİŞTİRİYORUZ.
            Alttaki döngünün yaptığı işlem şu. Eğer alttaki gibi bir sorgu değerleri gönderilirse
            $veri_sorgu_degerleri=array(
                                    "main_user_id" => (int)$_SESSION['MM_UserId'],
                                    "cari_grup_id" => [71,72,73],
                                    "cari_grup_adi" => ['fatih','ahmet','ali']                       
                                  );    
            burada main_user_id tek bir değer diğerleri sise array olarak gönderiliyor. Where IN sorgusu birden fazla değer alabileceği için bunları PDO kabul ederken string olarak kabul ediyor yani yukardaki 71,72,73 değerini tırnak içine tek değermiş gib '71,72,73' şeklinde alıyor yapılması gereken sorgunun değiştirilmesi. bu döngü ile 

            Select cari_grup_adi,cari_grup_id FROM m_cari_gruplar WHERE main_user_id= :main_user_id and cari_grup_id in (:cari_grup_id) and cari_grup_adi in (:cari_grup_adi) 

            şeklindeki sorgu in kısımları değiştirilerek

            Select cari_grup_adi,cari_grup_id FROM m_cari_gruplar WHERE main_user_id= :main_user_id and cari_grup_id in (:cari_grup_id0,:cari_grup_id1,:cari_grup_id2) and cari_grup_adi in (:cari_grup_adi0,:cari_grup_adi1,:cari_grup_adi2)

            halini alıyor bir sonraki foreach de ise yine benzer yapı ile arary olarak gelen değerler inin tek tek bind ediliyor, normal gelen değerler ise normal bind yapılıyor.


            */
            foreach($bind_params as $paramkey => $param_value) {
              //echo "Key=" . $paramkey ."-".($param_value)."-, Value=" . $param_value;
              //echo "<br>";                 
              //echo "is_numeric($param_value)>".is_numeric($param_value)."<br>";
              //echo "is_string($param_value)>".is_string($param_value)."<br>";
              //echo "is_array($param_value)>".is_array($param_value)."<br>";
              $in_key="";
              $in_parameters="";
              if (is_array($param_value)) // Gelan parametre array ise yeniden yapılandır.
              {
              foreach ($param_value as $i => $item)
                {
                    $in_key = ":$paramkey".$i;
                    //echo "<br>$in_key = ".$paramkey.".$i";
                    $in_parameters .= "$in_key,";
                    //echo "<br>$in_parameters = ".$in_key;
                }
                $in_parameters = rtrim($in_parameters,","); // :id0,:id1,:id2
                //echo "<br>in_parameters>$in_parameters";
                $sql = str_replace(":".$paramkey, $in_parameters,$sql);
                //echo "<br>oluşan sql>".$sql."<br>"; 
               }
            }
            $sql = $dbh->prepare($sql);
            foreach($bind_params as $paramkey => $param_value) {
              //echo "Key=" . $paramkey ."-".($param_value)."-, Value=" . $param_value;
              //echo "<br>";                 
              //echo "is_numeric($param_value)>".is_numeric($param_value)."<br>";
              //echo "is_string($param_value)>".is_string($param_value)."<br>";
              //echo "is_array($param_value)>".is_array($param_value)."<br>";
              if (is_numeric($param_value)==1)  // gelen veri  numerik ise
                {
                    $param_value = (int)$param_value;
                    $pdo_param_type = PDO::PARAM_INT;
                } 
              elseif (is_string($param_value)==1)// gelen veri  string ise
                {$pdo_param_type = PDO::PARAM_STR; }
              if (is_array($param_value)) // gelen veri array tipinde ise
              {
              foreach ($param_value as $i => $param_array_value) // bu döngünün açıklaması yukardaki döngü için yazılan açıklama içinde mevcut
                {
                    $in_key = ":$paramkey".$i;
                                if (is_numeric($param_array_value)==1)  // gelen veri  numerik ise
                                    {
                                        $param_array_value = (int)$param_array_value;
                                        $pdo_param_type = PDO::PARAM_INT;
                                    } 
                                  elseif (is_string($param_array_value)==1)// gelen veri  string ise
                                    {$pdo_param_type = PDO::PARAM_STR; }
                                    $sql->bindValue($in_key, $param_array_value, $pdo_param_type );
                    //echo "<br>oldu1";
                    //echo "<br> -$in_key-";
                }
                //$sql = str_replace(":".$paramkey, $in_parameters, $sql);
                //echo "oluşan sql>".$sql."<br>"; 
               }
              else // array değilse aşağıdaki şekilde bind yap.
                {
                  //echo "<br>oldu2";
                  $sql->bindValue(":$paramkey", $param_value, $pdo_param_type ); // bindparam foreach içinde kullanılmaz çünkü execute esnasında bind yaptığı için yani anlık olarak değerleri atamaddığı için for döngüsünde en sonda value değişkeni neyse tüm parametrelere onu atıyor, bu sebeple bindvalue kullanıyoruz.PDO::PARAM_INT
                }
            } // foreach                
            $exe = $sql->execute();
            $sql->debugDumpParams();
            //echo $exe;

        }
        catch(PDOException $err){
            return $err->getMessage();
        }

        //BU KISMA AİT AÇIKLAMA AŞAĞIDAIR.
        switch($keyword){ // sorgu çalıştıktan sonra sorgu sonucuna göre gerekli işlemler yapılıyor.
            case "SELECT":  // Sorgu select sorgusu ise                
                $result = array(); //sonuçları diziye aktaracak.
                while($row = $sql->fetch(PDO::FETCH_ASSOC)){     // sonuç satırlarını tek tek okuyup                   
                    //echo $row;
                    $result[] = $row; // her bir satırı dizinin bir elemanına aktarıyor.bu değer diziden nasıl okunur açıklaması aşağıda                      
                }
                return $result; // sorgudan dönen diziyi doğrudan ana programa aktarıyor orada dizi olarak okunabilir.                
                break;
            default: 
                return $exe;
                break;
        }
    }
    else{
        return false;
    }
}

}

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