Avatar billede chrisrj Forsker
13. januar 2020 - 13:04 Der er 9 kommentarer og
1 løsning

prepared statement retunerer kun een række

Hejsa

Jeg har en funktion der hente noget af en tabel til listevisning.
Men den nægter at returnere mere end een række, trods sql'en kørt direkte i db'en sagtens kan finde alle rækker.

Hvad overser jeg???
Det mest mærkelige er, at jeg bruger samme funktion andre steder uden nogen problemer...

//put data in the database
if (!($statement = $mysqli->prepare('SELECT SQID, Type, Question, NextQuestion, AlternativeNextQuestion, PageNumber
                                            FROM '.QuestionsTable.'
                                            WHERE SQID IN (?)'))) {
$objLog->LogIt(array('LogType' => '3', 'LogText' => __FUNCTION__.': Prepare failed: ('.$mysqli->errno.') '.$mysqli->error));
    throw new Exception($mysqli->error, $mysqli->errno);
    exit();
}
       
if (!($statement->bind_param('s', $strQID))) {
    $objLog->LogIt(array('LogType' => '3', 'LogText' => __FUNCTION__.': bind_param failed: ('.$statement->errno.') '.$statement->error));
    throw new Exception($statement->error, $statement->errno);
    exit();
}

if (!$statement->execute()) {
    $objLog->LogIt(array('LogType' => '3', 'LogText' => __FUNCTION__.': Execute failed: ('.$statement->errno.') '.$statement->error));
    throw new Exception($statement->error, $statement->errno);
    exit();
}
       
if (!$statement->store_result()) {
    $objLog->LogIt(array('LogType' => '3', 'LogText' => __FUNCTION__.': store_result failed: ('.$statement->errno.') '.$statement->error));
    throw new Exception($statement->error, $statement->errno);
    exit();
}
       
// If the Question exists get variables from result.
if($statement->bind_result($SQID, $Type, $Question, $NextQuestion, $AlternativeNextQuestion, $PageNumber)) {
    // remember to actually GET the data!
    if ($statement->fetch()) {
        $output = array();
        $output[] = array('SQID'=>$SQID, 'Type'=>$Type, 'Question'=>$Question, 'NextQuestion'=>$NextQuestion, 'AlternativeNextQuestion'=>$AlternativeNextQuestion, 'PageNumber'=>$PageNumber);
        while ($statement->fetch()) {
            $output[] = array('SQID'=>$SQID, 'Type'=>$Type, 'Question'=>$Question, 'NextQuestion'=>$NextQuestion, 'AlternativeNextQuestion'=>$AlternativeNextQuestion, 'PageNumber'=>$PageNumber);
            echo $SQID."<br>";
        }
               
    } else {
        $objLog->LogIt(array('LogType' => '3', 'LogText' => __FUNCTION__.': fetch failed: ('.$statement->errno.') '.$statement->error));
        throw new Exception($statement->error, $statement->errno);
        exit();
    }
} else {
    $objLog->LogIt(array('LogType' => '3', 'LogText' => __FUNCTION__.': bind_result failed: ('.$statement->errno.') '.$statement->error));
    throw new Exception($statement->error, $statement->errno);
    exit();
}
$statement->close();
       
return json_encode($output);
Avatar billede chrisrj Forsker
13. januar 2020 - 13:09 #1
Nå, ja. SQL'en der virker fint:
SELECT SQID, Type, Question, NextQuestion, AlternativeNextQuestion, PageNumber FROM PoC_Questions WHERE SQID IN (5,6,7)
Avatar billede arne_v Ekspert
13. januar 2020 - 15:19 #2
Prepared statement er genialt til næsten alt.

En af de meget få undtagelser er IN.

IN (?) virker fint til at sætte 1 værdi men virker ikke med 2 værdier

IN (?,?) virker fint til at sætte 2 værdier men virker ikke med 1 værdi
Avatar billede arne_v Ekspert
13. januar 2020 - 15:20 #3
Avatar billede chrisrj Forsker
13. januar 2020 - 15:25 #4
Hmmm...hvad gør man så hvis man har et variabelt antal op til 10?
Avatar billede arne_v Ekspert
13. januar 2020 - 15:41 #5
Tja.

Måske et array med 10 strenge.

Måske den gammeldags måde med check/escape af indhold og streng konkatanering. I langt de fleste tilfælde bruges IN() med integers og saa er det nemmere at checke om de kun indeholder tal.
Avatar billede chrisrj Forsker
13. januar 2020 - 15:44 #6
Hmmm...ingen guru-ekspert-super løsning? /skuffet ;)

Tja, det må vel være måden.

Tak. :)
Avatar billede arne_v Ekspert
13. januar 2020 - 17:07 #7
Problemet er almindeligt.

Hvis du googler vil du finde masser af spørgsmål og de samme svar igen og igen.
Avatar billede chrisrj Forsker
13. januar 2020 - 18:36 #8
Ja, jeg prøvede. Men så ingen løsninger. :)

Den fik jeg så af dig istedet. :)
Avatar billede arne_v Ekspert
13. januar 2020 - 20:36 #9
Jeg tror at det er bedre at bygge parameternavnene op dynamisk end at bruge antal parametre som indeks ind i aray.

Så:


<?php

function get_connection() {
    $con = new PDO('mysql:host=localhost;dbname=Test', 'root', '');
    $con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $con->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
    return $con;
}

function display_result($stmt) {
    while($row = $stmt->fetch()) {
        echo $row['f1'] . ' ' . $row['f2'] . "\r\n";
    }
}

function test_hardcoded() {
    $con = get_connection();
    $stmt = $con->prepare('SELECT f1,f2 FROM t1 WHERE f1 IN (2,3)');
    $stmt->execute(array());
    display_result($stmt);
}

function test_oldway($a) {
    $con = get_connection();
    foreach($a as $i) {
        if(!is_int($i)) throw new Exception('Go away evil hacker');
    }
    $stmt = $con->prepare('SELECT f1,f2 FROM t1 WHERE f1 IN (' . implode(',', $a) . ')');
    $stmt->execute(array());
    display_result($stmt);
}

function test_dynamic($a) {
    $con = get_connection();
    $formalparam = array();
    $actualparam = array();
    for($i = 0; $i < count($a); $i++) {
        $paramnam = ":p$i";
        $formalparam[] = $paramnam;
        $actualparam[$paramnam] = $a[$i];
    }
    $sqlstr = 'SELECT f1,f2 FROM t1 WHERE f1 IN (' . implode(',', $formalparam) . ')';
    $stmt = $con->prepare($sqlstr);
    $stmt->execute($actualparam);
    display_result($stmt);
}

test_hardcoded();
test_oldway(array(2,3));
test_dynamic(array(2,3));

?>
Avatar billede arne_v Ekspert
14. januar 2020 - 01:19 #10
Den dynamiske kan laves pænere med brug af positions parametre fremfor navngivne parametre:


<?php

function get_connection() {
    $con = new PDO('mysql:host=localhost;dbname=Test', 'root', '');
    $con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $con->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
    return $con;
}

function display_result($stmt) {
    while($row = $stmt->fetch()) {
        echo $row['f1'] . ' ' . $row['f2'] . "\r\n";
    }
}

function test_hardcoded() {
    $con = get_connection();
    $stmt = $con->prepare('SELECT f1,f2 FROM t1 WHERE f1 IN (2,3)');
    $stmt->execute(array());
    display_result($stmt);
}

function test_oldway($a) {
    $con = get_connection();
    foreach($a as $i) {
        if(!is_int($i)) throw new Exception('Go away evil hacker');
    }
    $stmt = $con->prepare('SELECT f1,f2 FROM t1 WHERE f1 IN (' . implode(',', $a) . ')');
    $stmt->execute(array());
    display_result($stmt);
}

function test_dynamic($a) {
    $con = get_connection();
    $formalparam = array();
    $actualparam = array();
    for($i = 0; $i < count($a); $i++) {
        $paramnam = ":p$i";
        $formalparam[] = $paramnam;
        $actualparam[$paramnam] = $a[$i];
    }
    $sqlstr = 'SELECT f1,f2 FROM t1 WHERE f1 IN (' . implode(',', $formalparam) . ')';
    $stmt = $con->prepare($sqlstr);
    $stmt->execute($actualparam);
    display_result($stmt);
}

function test_dynamic2($a) {
    $con = get_connection();
    $param = substr(str_repeat('?,', count($a)), 0, -1);
    $sqlstr = 'SELECT f1,f2 FROM t1 WHERE f1 IN (' . $param . ')';
    $stmt = $con->prepare($sqlstr);
    $stmt->execute($a);
    display_result($stmt);
}

test_hardcoded();
test_oldway(array(2,3));
test_dynamic(array(2,3));
test_dynamic2(array(2,3));

?>
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Vi tilbyder markedets bedste kurser inden for webudvikling

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester