2009-09-07 32 views
19

Tôi đang sử dụng PDOStatement để truy vấn cơ sở dữ liệu. Bất cứ khi nào tôi nhận được hàng trả về, tôi muốn nó được tìm nạp vào một mảng, với mã khóa $row[0] và các phần tử tiếp theo trong hàng làm giá trị.PHP PDOStatement: Lấy một hàng, làm cột đầu tiên làm khóa của một mảng

tôi có thể, tất nhiên, hãy viết một kết hợp của foreach vòng và if điều kiện để thực hiện công việc, chẳng hạn như dưới đây:

private static function GetMySQLResult($dbname, $sqlString) { 


     $dbh = self::ConstructPDOObject($dbname); 
     $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 

     $result=array(); 
     foreach ($dbh->query($sqlString) as $row) 
     { 
      $result[$row[0]][]=$row[1]; // the simplest case for 2 columns, should add more to handle more columns 

     } 

     return $result; 

} 

nhưng tôi đang tìm kiếm một phương pháp hiện có; có phương thức như vậy đã tồn tại chưa??

+0

Mã của bạn thực sự nhóm các hàng trên một khóa không phải là duy nhất, đó cũng là yêu cầu của một câu trả lời có thể? –

Trả lời

2

Một số mẹo, bạn cần chuyển kiểu tìm nạp phù hợp sang phương thức PDOStatement->fetch() để bạn không kết thúc với dữ liệu kép (tên cột và chữ số). Giống như hàng $ [0] và $ row ['id'], cả hai đều chứa cùng một giá trị khi bạn sử dụng PDO :: FETCH_BOTH.

$result = $dbh->query($sqlString); 
while ($row = $result->fetch(PDO::FETCH_NUM)) { 
... 

Đối với câu hỏi của bạn, bạn sẽ phải tìm nạp tất cả các kết quả và tạo một hàng với giá trị là hàng và giá trị - giống như bạn đang làm . Tôi xây dựng một thư viện ORM toàn bộ xung quanh PDO và tôi không bao giờ có thể tìm thấy bất cứ điều gì để làm điều này tự động.

$result = $dbh->query($sqlString); 

$results = array(); 
while ($row = $result->fetch(PDO::FETCH_NUM)) { 
    $results[$row[0]] = $row; 
} 

return $results; 
+0

Điều này khác nhau như thế nào khi sử dụng vòng lặp foreach, đó là những gì chúng tôi đang cố gắng tránh? –

22

Tín dụng đi tới devdRew. Check the other question here.

Rõ ràng, bạn có thể như đã nêu trong câu trả lời. Tôi đã kiểm tra và nó hoạt động rất tốt.

$q = $db->query("SELECT `name` AS name, `value` AS value FROM `settings`;"); 
$r = $q->fetchAll(PDO::FETCH_KEY_PAIR); 

EDIT

câu trả lời này yêu cầu bạn chỉ định tối đa 2 cột: 1 chìa khóa và 1 giá trị. Nếu bạn cần truy xuất thêm các khóa từ cơ sở dữ liệu, hãy kiểm tra câu trả lời dưới đây và đọc nhận xét của @nullabilty. Đối với những người lười biếng, đây là phương pháp của mình:

$q->fetchAll(PDO::FETCH_GROUP|PDO::FETCH_UNIQUE|PDO::FETCH_ASSOC); 
+0

Đây là phương pháp duy nhất sẽ sử dụng cột đầu tiên làm khóa, nếu bạn cần thêm cột, CONCAT hoặc tương tự các trường bổ sung dưới dạng chuỗi phân tách cho giá trị cột thứ 2 và sử dụng 'phát nổ' để có mảng trước khi sử dụng giá trị. –

+0

@ nickl- sử dụng 'CONCAT' cho mục đích này là một ý tưởng khủng khiếp; câu trả lời này nên được sử dụng riêng cho các cặp khóa-giá trị, một cái gì đó mà nó được thiết kế để làm. –

+0

Bạn có để tiền thưởng hết hạn không? –

1

Bên cạnh những kịch bản bảng hai cột, không có gì ở cấp PDO để xử lý này là, nhưng bạn có thể viết một iterator thể tái sử dụng cho nó, như thế này:

class FirstColumnKeyIterator implements Iterator 
{ 
    private $stmt; 
    private $key; 
    private $data; 
    private $mode; 

    public function __construct(PDOStatement $stmt, $fetch_mode = PDO::FETCH_NUM) 
    { 
     $this->stmt = $stmt; 
     $this->mode = $fetch_mode; 
     $this->fetch(); 
    } 

    private function fetch() 
    { 
     if (false !== ($this->data = $this->stmt->fetch($this->mode))) { 
      $this->key = current(array_splice($this->data, 0, 1)); 
     } 
    } 

    public function rewind() 
    { 
     // nil operation 
    } 

    public function key() 
    { 
     return $this->key; 
    } 

    public function current() 
    { 
     return $this->data; 
    } 

    public function next() 
    { 
     $this->fetch(); 
    } 

    public function valid() 
    { 
     return false !== $this->data; 
    } 
} 

các nhà xây dựng phải mất một PDOStatement và một tùy chọn chế độ lấy (cột số theo mặc định, nhưng có thể được thay đổi để PDO::FETCH_ASSOC cho một mảng kết hợp) và cho phép bạn lặp qua các kết quả truy vấn sử dụng một điển hình foreach.

Cách sử dụng Ví dụ:

$dbh = new PDO(/* etc */); 

$stmt = $dbh->query('SELECT * FROM accounts'); 
foreach (new FirstColumnKeyIterator($stmt, PDO::FETCH_ASSOC) as $key => $value) { 
     echo $key, ' = ', print_r($value, true), PHP_EOL; 
} 
+0

10 điểm cho sáng tạo =) nhưng bạn sẽ tìm cách này đắt hơn sau đó kịch bản gốc. Bạn có thể cải thiện điều này bằng cách tham chiếu 'Iterator' mới đầu tiên và luôn tránh' như $ key => # value' nếu bạn có thể trợ giúp nó. Bạn sẽ thấy rằng vòng lặp for trên 'mảng_keys' được tham chiếu sẽ mang lại kết quả tốt hơn miễn là số đếm cũng được tham chiếu. 'for ($ i = 0; $ i

+0

@nickl iterators luôn đắt hơn một mảng "đơn giản" bởi vì mã phụ được thực thi tại mỗi vòng lặp mà sẽ không biến mất bằng cách tham chiếu cá thể; việc loại bỏ giá trị 'key = >' cũng không phải là một tùy chọn, vì không có cách nào để lấy khóa nếu không :) –

+0

cách khác để sử dụng trình lặp và vẫn lấy khóa có thể là do..while hoặc trong khi cho vấn đề đó và Tôi có thể nghĩ về một số cho vòng tức là. 'for ($ it = new ArrayIterator ($ data); $ it-> valid(); $ it-> next()) echo $ it-> key(). ' => '. $ it-> current(); 'nhưng tôi chắc chắn bạn cũng nghĩ về những điều này.=) –

3

Afaik, không có phương pháp hiện có mà sẽ làm điều đó trong PHP nhưng có một vài cách bạn có thể đạt được những gì bạn muốn.

Một trong những người đầu tiên được gì Xeoncross nói nhưng một chút biến đổi:

$pdostmt = $pdo->query("SELECT ... FROM your_table"); 

$res = array(); 

foreach ($pdostmt->fetchAll(PDO::FETCH_ASSOC) as $row) 
{ 
    $res[array_shift($row)] = $row; 
} 

Nếu không, bạn có thể tạo một lớp học với một phương pháp __set() để bắt biến nhiệm vụ:

class at_res 
{ 
    public $key; 
    public $values = array(); 
    protected $flag = true; 

    public function __set($var, $value) 
    { 
    if ($this->flag) 
    { 
     $this->key = $value; 
     $this->flag = false; 
    } 
    else 
    { 
     $this->values[$var] = $value; 
    } 
    } 

    public function extract() 
    { 
    return array($this->key => $this->values); 
    } 
} 


$pdo = new PDO(...); 

$pdostmt = $pdo->query("SELECT ... FROM your_table"); 

$res = $pdostmt->fetchObject('at_res'); 

var_dump($res->extract()); 

Hy vọng nó giúp .

13
$stmt->fetchAll(PDO::FETCH_GROUP|PDO::FETCH_UNIQUE); 

mặc dù một chút của một hack nhưng thực sự là cách duy nhất để làm điều này từ một người nào đó decided FETCH_KEY_PAIR nên yêu cầu 2 cột kết quả thiết lập của chỉ.

Lưu ý: cột đầu tiên được sử dụng một khóa và không được trả về trong tập hợp kết quả dưới bất kỳ hình thức nào khác.

+13

Cảm ơn, tôi đã mở rộng mỏ sang 'PDO :: FETCH_GROUP | PDO :: FETCH_UNIQUE | PDO :: FETCH_ASSOC' để có được chính xác những gì tôi cần. – nullability

+0

bổ sung tốt đẹp ở đó thx – Louis

+0

Lưu ý: cột đầu tiên được sử dụng một khóa và không được trả lại trong tập hợp kết quả dưới bất kỳ hình thức nào khác. Bạn vẫn có thể sao chép cột đầu tiên của mình bằng cách sử dụng "SELECT cột đầu tiên AS id, firstcolumn, secondcolumn ..." nếu bạn muốn lấy cột là kết quả –

Các vấn đề liên quan