আমি কি কোনও 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();
?>

এবং PDO বেঁধে রাখুন এবং অ্যারের সমস্ত মান উদ্ধৃত করুন।

এই মুহুর্তে আমি করছি:

<?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
আইএন () শর্তে একটি অ্যারে বাইন্ডিং সম্পর্কিত একটি সম্পূর্ণ গাইড , যখন আপনার প্রশ্নের অন্য স্থানধারক রয়েছে তখন মামলা সহ
আপনার সাধারণ সংবেদন

এই প্রশ্নের সদৃশ হিসাবে প্রশ্নটি বন্ধ ছিল । আমি সদৃশ পতাকাটি উল্টে দিয়েছি কারণ এই প্রশ্নটি 4 বছরের বেশি পুরানো, 4 বারের মতামত, উত্তরের সংখ্যার 3 গুণ এবং স্কোরের 12 গুণ বেশি। এটি পরিষ্কারভাবে উচ্চতর লক্ষ্য।
miken32

2020-এ যে কেউ এটিকে দেখছেন: আপনি তার জন্য github.com/morris/dop চেষ্টা করতে পারেন ।
মরিস 4

উত্তর:


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
এটি একটি আকর্ষণীয় সমাধান, এবং আমি যখন এটিগুলি আইডিগুলির উপরে পুনরাবৃত্তি করতে এবং পিডিও :: কোট () কল করার চেয়ে পছন্দ করি, তখন আমার মনে হয় 'এর সূচকটি?' স্থানধারকরা গণ্ডগোল করতে চলেছে যদি কোয়েরিতে অন্য কোনও স্থানধারক আগে উপস্থিত হয়, তাই না?
Andru

5
হ্যাঁ, সমস্যা হবে। তবে এক্ষেত্রে আপনি? এর পরিবর্তে নামকরণকৃত প্যারামিটার তৈরি করতে পারেন।
স্টেফস

9
পুরানো প্রশ্ন, তবে আমি বিশ্বাস করি যে আমি বিশ্বাস করি, এটি হ'ল $foreachএবং bindValue()প্রয়োজনীয় নয় - কেবল অ্যারের সাথে সম্পাদন করুন। উদা:$stmt->execute($ids);
ক্রিস

2
স্থানধারকগুলি তৈরি করা এইভাবে করা উচিতstr_repeat('?,', count($array) - 1). '?';
Xeoncross

8
অচেতনদের জন্য কেবলমাত্র একটি টিপ, আপনি নামযুক্ত এবং নামবিহীন পরামিতিগুলি মিশ্রিত করতে পারবেন না। সুতরাং আপনি যদি আপনার কোয়েরিতে নামযুক্ত প্যারামিটারগুলি ব্যবহার করেন তবে সেগুলিকে? এর থেকে স্যুইচ করুন এবং তারপরে আপনার বাইনডভ্যালু সূচক অফসেটটি বাড়িয়ে তুলবেন যেখানে তারা আপনার অন্যটির সাথে তুলনামূলক যেখানেই আছে তার সাথে মিলবে? প্যারাম।
justinl

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_list = substr(str_repeat(',?', count($ids)), 1);
orca

7
আপনি চেষ্টা করতে পারেন str_repeat('?,', count($ids) - 1) . '?'। একটি কম ফাংশন কল।
অরকা

5
@ স্পিলিং, এটি একটি প্রস্তুত বিবৃতি, ইঞ্জেকশনটি কোথা থেকে আসবে? আপনি যদি এর কিছু প্রকৃত প্রমাণ দিয়ে ব্যাক আপ করতে পারেন তবে কোনও সংশোধন করতে পেরে আমি বেশি খুশি হব।
ডনউভন

5
@ স্পিলিং, হ্যাঁ, এটি সঠিক, এবং পরমগুলিকে বাঁধাই ঠিক এই execute
উদাহরণগুলির মধ্যে আমরা আইডির

5
ওহ আসলে। আপনি অ্যারে পাস করছিলেন তা কোনওভাবেই মিস হয়ে গেল। এটি প্রকৃতপক্ষে নিরাপদ এবং একটি ভাল উত্তর বলে মনে হচ্ছে। আমার ক্ষমা।
এরফ্লিং

46

INবিবৃতি ব্যবহার করা কি এত গুরুত্বপূর্ণ ? বিকল্প ব্যবহার করার চেষ্টা করুন FIND_IN_SET

উদাহরণস্বরূপ, PDO তে এর মতো একটি কোয়েরি রয়েছে

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

এবং এটি সম্পন্ন হয়েছে।

ইউপিডি: কিছু লোক এই উত্তরে মন্তব্যে ইঙ্গিত করার সাথে সাথে কিছু বিষয় রয়েছে যা স্পষ্ট করে বলা উচিত।

  1. FIND_IN_SETকোনও সারণীতে সূচক ব্যবহার করে না এবং এটি এখনও কার্যকর করা হয়নি - MYSQL বাগ ট্র্যাকারে এই রেকর্ডটি দেখুন । বিজ্ঞপ্তি দেওয়ার জন্য @ বিলকারভিনকে ধন্যবাদ
  2. অনুসন্ধানের জন্য অ্যারের মান হিসাবে আপনি ভিতরে কমা দিয়ে একটি স্ট্রিং ব্যবহার করতে পারবেন না। implodeআপনি পৃথককারী হিসাবে কমা প্রতীক ব্যবহার করার পরে এই জাতীয় স্ট্রিংটিকে সঠিক উপায়ে পার্স করা অসম্ভব । নোটের জন্য @ ভোলকে ধন্যবাদ

জরিমানা, আপনি যদি সূচকের উপর খুব বেশি নির্ভরশীল না হন এবং অনুসন্ধানের জন্য কমা দিয়ে স্ট্রিং ব্যবহার না করেন তবে আমার সমাধান উপরে তালিকাভুক্ত সমাধানের চেয়ে অনেক সহজ, সহজ এবং দ্রুত হবে।


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
এটি একটি আরও ভাল সমাধান, যেহেতু এটি পরামিতিগুলির নিয়মকে আবদ্ধ করে না। এখানের কিছু অন্যান্য দ্বারা প্রস্তাবিত ইনলাইন স্কেল থাকার চেয়ে এটি অনেক বেশি নিরাপদ।
দিমিতর দারাঝাঁস্কি 21

1
বিস্ময়তাকে। মার্জিত। পারফেক্ট।
রিক্যালসিন

17

এভিলরিজি থেকে সমাধান আমার পক্ষে কাজ করে নি। পোস্টগ্রিসে আপনি অন্য একটি কাজ করতে পারেন:


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

এটি এসকিএল ইনজেকশনটি ব্লক করে?
ফ্যাবিও জাঙ্গিরোলামি

1
@ ফ্যাবিওজ্যাঙ্গিরোলামি এটি পিডিও, তাই হ্যাঁ।
এসকোবার

হ্যাঁ, পিডিও! 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));

অ্যারে_ভ্যালুগুলির ব্যবহারটি নোট করুন। এটি মূল ক্রম সংক্রান্ত সমস্যাগুলি ঠিক করতে পারে।

আমি আইডির অ্যারে মার্জ করছিলাম এবং তারপরে নকল আইটেমগুলি সরিয়েছি। আমার মতো কিছু ছিল:

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

এবং এটি ব্যর্থ ছিল।


এটি ছিল একটি দুর্দান্ত সমাধান। এটি ক্যোরির স্ট্রিং তৈরির মতো নয়, এটি বাইন্ডিং সঠিকভাবে ব্যবহার করে। আমি দৃ strongly়ভাবে এই এক সুপারিশ।
লিন্ডিলিয়াড

দ্রষ্টব্য: আপনার সমাধানটি ব্যবহার করে আপনি অ্যারের সামনের বা পিছনে আইটেমগুলি যুক্ত করতে পারেন, যাতে আপনি অন্যান্য বাইন্ডিংগুলি অন্তর্ভুক্ত করতে পারেন। $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
ওয়াইসিএস: প্রতিবেদনের জন্য ধন্যবাদ, দৃser়তার উপযুক্ততার বাইরে আপনার মতামত সম্পর্কে আগ্রহী।
ক্রিস

1
ধারণাটি একই রকম তবে ঠিক জোর দেওয়া ছাড়াও এবং আরও সহজ-সরল ও সুস্পষ্ট উপায় - কেবল কোনও একক ক্ষেত্রে ব্যতিক্রম হিসাবে নয় বরং প্রতিটি প্রশ্নের উত্থাপনের সাধারণ উপায় হিসাবে। প্রতিটি স্থানধারক এটির ধরণের চিহ্নযুক্ত। এটি অনুমান করা (যেমন if (is_array($data))একটি) অপ্রয়োজনীয় তবুও ডেটা প্রক্রিয়াকরণের উপায়টিকে আরও সঠিক করে তোলে।
আপনার প্রচলিত সংবেদন

1
যে কোনও ব্যক্তির মন্তব্য পড়ছেন: @ আপনার সাধারণ সংবেদনের দ্বারা উল্লিখিত বিষয়টি সংশোধন 4 এ স্থির করা হয়েছে ।
ব্যবহারকারী 2428118

11

এ খুঁজছি পূর্বনির্ধারিত ধ্রুবক: PDO কিছু নেই PDO :: PARAM_ARRAY যা আপনি হিসাবে তালিকাভুক্ত করা হয় প্রয়োজন হবে PDOStatement-> bindParam

বুল PDOStatement :: bindParam (মিশ্রিত $ পরামিতি, মিশ্রিত & $ ভেরিয়েবল [, int $ ডেটা_ টাইপ [, int $ দৈর্ঘ্য [, মিশ্র $ ড্রাইভার_অপশন]]]])

সুতরাং আমি এটি অর্জনযোগ্য বলে মনে করি না।


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

দুর্দান্ত উত্তরের জন্য ধন্যবাদ। এটিই ছিল কেবলমাত্র আমার জন্য যা কাজ করেছিল of তবে, আমি 1 টি ভুল দেখেছি। ভেরিয়েবল $ আরএসএমটি হতে হবে
পাইট

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।
অনন্ত সিং --- এলাইভ টু ডাই

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এই দৃশ্যের উদাহরণ এবং উদাহরণগুলি সম্পর্কে আরও কিছু চিন্তাভাবনার জন্য পিএইচপি.নেট-এর পৃষ্ঠায় দেওয়া মন্তব্যগুলি একবার দেখুন ।


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

আমি জানি যে পিডিও বিবৃতিতে অ্যারে বাঁধার কোনও সম্ভাবনা নেই is

তবে বিদ্যমান 2 সাধারণ সমাধান:

  1. অবস্থানিক স্থানধারক (?,?,?,?) বা নামযুক্ত স্থানধারক (: id1,: id2,: id3) ব্যবহার করুন

    $ যেখানেইন = ইমপ্লোড (',', অ্যারে_ফিল (0, গণনা ($ আইডস), '?'));

  2. আগে উদ্ধৃতি অ্যারে

    $ যেখানেইন = অ্যারে_ম্যাপ (অ্যারে ($ ডিবি, 'কোট'), $ আইডি);

উভয় বিকল্প ভাল এবং নিরাপদ। আমি দ্বিতীয়টি পছন্দ করি কারণ এটি সংক্ষিপ্ত এবং আমি প্রয়োজন হলে আমি পরামিতিগুলিতে var_dump করতে পারি। স্থানধারক ব্যবহার করে আপনাকে অবশ্যই মানগুলি আবদ্ধ করতে হবে এবং শেষ পর্যন্ত আপনার এসকিউএল কোডটি একই হবে।

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

এটি কোনও এসকিউএল ইঞ্জেকশনের পক্ষে ঝুঁকিপূর্ণ হওয়া উচিত নয়।


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

আমার সম্পর্কে আপনি কী মনে করেন জানি


এটি নীচে ব্যবহারকারী 2188977 এর উত্তরের উপর ভিত্তি করে উল্লেখ করতে ভুলে গেছেন।
লিপ্পাই জোল্টান

আমি নিশ্চিত না যে getOne () কী, এটি PDO এর অংশ বলে মনে হচ্ছে না। আমি এটি কেবল পিয়ারে দেখেছি। এটা ঠিক কি করে?
লিপ্পাই জোল্টান

@ ইওরকমমনসেন্স আপনি উত্তর হিসাবে আপনার ব্যবহারকারী সংজ্ঞায়িত ফাংশন পোস্ট করতে পারেন?
ন্যূনযোগ্যতা

আপনারা BindArrayParamএটির পূর্ণসংখ্যার মধ্যে সীমাবদ্ধ রাখছেন বলে মনে হচ্ছে এসোসিয়েটিভ অ্যারেতে ডেটা টাইপটি পাস করার পরামর্শ দেব ।
ইয়ান ব্রিন্ডলি

2

PDO তে এর মতো অ্যারে ব্যবহার করা সম্ভব নয়।

প্রতিটি মানের জন্য আপনাকে একটি প্যারামিটার (বা ব্যবহার?) দিয়ে একটি স্ট্রিং তৈরি করতে হবে, উদাহরণস্বরূপ:

: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

আপনি প্রথম "সংখ্যা নির্ধারণ করেন?" ক্যোয়ারীতে এবং তারপরে একটি "for" এর মাধ্যমে এই জাতীয় পরামিতি প্রেরণ করুন:

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);
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.