2013-02-19 41 views
5

Sử dụng bind_param trên tất cả các truy vấn của tôi, bây giờ tôi muốn sử dụng một số IN(?) trong đó số phần tử trong danh sách có thể thay đổi.mySQL bind_param với IN (?)

Các SQLout chức năng Tôi đang sử dụng ở đây về cơ bản không một $sql_db->prepare, ->bind_param, ->execute(), ->store_result(), ->bind_result

// the code below does not work as the query only matches on element 'a': 
$locations = ('a','b','c','d','e'); 

SQLout ("SELECT Name FROM Users WHERE Locations IN (?)", 
    array('s', $locations), array(&$usrName)); 


// the code below does work as a brute-force method, 
// but is not a viable solution as I can't anticipate the number of elements in $locations going forward: 

SQLout ("SELECT Name FROM Users WHERE Locations IN (?,?,?,?,?)", 
    array('sssss', $locations[0],$locations[1],$locations[2],$locations[3],$locations[4]), array(&$usrName)); 

Có ai tìm ra một giải pháp thanh lịch nhiều đến thế này?

+0

thể trùng lặp của [PHP PDO : Tôi có thể liên kết một mảng với điều kiện IN() không?] (Http://stackoverflow.com/questions/920353/php-pdo-can-i-bind-an-array-to-an-in-condition) –

+1

PDO câu trả lời không có gì để làm với các vấn đề mysqli. PDO là thiên đường so với mysqli về xử lý số biến số của các câu lệnh đã chuẩn bị –

Trả lời

4

Đây là một trình giữ chỗ được đặt trên khuôn mặt của chúng. Trừ tự động thoát, họ gần như nghĩa đen chỉ là một operationt chuỗi thay thế trong nội bộ, có nghĩa là nếu bạn có WHERE x IN (?), và vượt qua trong 1,2,3,4, bạn sẽ nhận được tương đương với

WHERE x IN ('1,2,3,4') // note, it's a string, not individual comma-separated ints 

logic tương đương với

WHERE x = '1,2,3,4' // again, just a string 

isntead của

WHERE (x = 1) or (x = 2) or (x = 3) or (x = 4) 

các giải pháp thực tế chỉ dự kiến ​​hơn

là để xây dựng danh sách của riêng bạn của ?, ví dụ:

$placeholders = implode(array_fill(0, count($values), '?')); 
$sql = "SELECT ... WHERE x IN ($placeholders)"; 

và sau đó ràng buộc thông số của bạn là bình thường.

+0

'$ stmt-> execute ($ values)'. dễ dàng như có thể được. –

+2

Thật không may, các câu lệnh chuẩn bị liên kết trong mysqli không dễ dàng như trong PDO. Mysqli không có tính năng '$ stmt-> execute ($ values)'. Nó cũng không có phương thức bindValue (vì vậy bạn không thể liên kết trong một vòng lặp sử dụng biến lặp) mà làm cho một nhiệm vụ đơn giản như xiếc và một cơn ác mộng cùng một lúc. Đây là lý do tại sao câu trả lời này là cách không đầy đủ –

+0

Hoạt động tốt nhất cho trường hợp của tôi. Tôi sẽ phải chạy một số kiểm tra tốc độ về việc sử dụng các phần tử IN dài. – user2033684

-1

IN thường là tuyên bố chậm và không được chuẩn bị thân thiện. Giải pháp tốt hơn là xây dựng một bảng các mục có trong IN và sử dụng JOIN để có được cùng một hiệu ứng.

+0

@Your Sau đó, hãy cung cấp ví dụ về cách nhận số lượng giá trị thay đổi trong IN. –

+0

@xin vui lòng đọc http://stackoverflow.com/questions/4771183/sql-fixed-value-in-vs-inner-join-performance Vấn đề với IN là bạn không thể lập chỉ mục danh sách như bạn có thể và khi danh sách càng dài thì hiệu suất sẽ giảm nhanh. Tất nhiên nó nhanh khi danh sách ngắn. –

1

Bạn có thể "xây dựng" trong mệnh đề IN trước khi bạn chuẩn bị/ràng buộc nó.

$sql = 'SELECT Name FROM Users WHERE Locations IN (' . implode(array_fill(0, count($locations), '?')) . ')'; 

Sau đó, bạn có thể sử dụng call_user_func_array để ràng buộc các tham số mà không biết có bao nhiêu thông số.

// Parameters for SQLOut 
$params = array(
    # The SQL Query 
    $sql, 
    # The params for bind_param 
    array(str_repeat('s', count($locations))), 
    # The params for bind_result 
    array(&$usrName) 
); 

// Add the locations into the parameter list 
foreach($locations as &$loc){ 
    // not sure if this is needed, but bind_param 
    // expects its parameters to be references 
    $params[1][] = &$loc; 
} 

// Call your function 
call_user_func_array('SQLout', $params); 

Lưu ý: Đây là chưa được kiểm tra

-2

Có ai tìm ra một giải pháp thanh lịch nhiều đến thế này?

Chắc chắn. Tôi là.

Mysqli thực tế không sử dụng được với các câu lệnh đã chuẩn bị, đặc biệt là với các trường hợp phức tạp như vậy.
Vì vậy, tốt hơn là loại bỏ các báo cáo đã chuẩn bị và triển khai trình giữ chỗ của riêng bạn với sự hỗ trợ của tất cả các trường hợp thực tế thực tế đời sống nhà phát triển có thể đáp ứng.

Vì vậy, safeMysql có giải pháp bạn đang tìm kiếm (và cũng có thể giải pháp cho hàng tá cơn đau đầu khác).

Trong trường hợp cụ thể của bạn nó sẽ được dễ dàng như dòng mã này

// the code works all right: 
$locations=array('a','b','c','d','e'); 
$usrName=$db->getCol("SELECT Name FROM Users WHERE Locations IN (?a)",$locations); 

không giống như mã xấu xí bạn có thể chơi với một số chức năng PHP và API (và vẫn nhận được những cảnh báo đáng lo ngại phụ thuộc vào phiên bản PHP bạn đang sử dụng tại thời điểm này) mã này gọn gàng và có thể đọc được. Đây là vấn đề quan trọng. Bạn có thể biết mã này làm gì sau một năm trôi qua.

+0

Nó vẫn sẽ bị chậm nếu danh sách dài http://stackoverflow.com/questions/4771183/sql-fixed-value-in-vs-inner-join-performance –

2

Như Hazmat nói, bạn cần phải xây dựng các thông số và sau đó vượt qua chúng bằng cách gọi call_user_func_array trên tuyên bố chuẩn bị, nhưng hơi gần hơn để mã làm việc hơn ví dụ mình :)

//In the calling code 
$queryString = "SELECT Name FROM Users WHERE Locations IN ("; 
$queryString .= getWhereIn($locations); 
$queryString .= ")"; 

$parametersArray = array(); 

foreach($locations as $location){ 
    $parameter = array(); 
    $parameter[0] = 's'; //It's a string 
    $parameter[1] = $location; 

    $parametersArray[] = $parameter; 
} 



//This is a function in a class that wraps around the class mysqli_statement 
function bindParameterArray($parameterArray){ 

    $typesString = ''; 
    $parameterValuesArray = array(); 

    foreach($parameterArray as $parameterAndType){ 
     $typesString .= $parameterAndType[0]; 
     $parameterValuesArray[] = $parameterAndType[1]; 
    } 

    $finalParamArray = array($typesString); 
    $finalParamArray = array_merge($finalParamArray, $parametersArray); 
    call_user_func_array(array($this->statement, "bind_param"), $finalParamArray); 
} 

function getWhereIn($inArray){ 
    $string = ""; 
    $separator = ""; 
    for($x=0 ; $x<count($inArray) ; $x++){ 
     $string .= $separator."?"; 
     $separator = ", "; 
    } 
    return $string; 
} 
Các vấn đề liên quan