0

I'm struggling to revise the following (which works) to use a prepared statement:

echo "<div class=\"debug\">
            <h4>values \$_POSTed from *LINE-ITEMS TABLE* in input.php:</h4>
            <table>";

    foreach ($_POST['date'] as $i => $value) {
        $invNum     = $_POST['invNum'];
        $date           = $_POST['date'][$i];
        $hours      = $_POST['hours'][$i];
        $rate           = $_POST['rate'][$i];
        $dateTotal  = $_POST['dateTotal'][$i];

        echo "<tr>
                    <td>".$i."</td>
                    <td>".$date."</td>
                    <td>".$hours."</td>
                    <td>".$rate."</td>
                    <td>".$dateTotal."</td>
                </tr>";

            $query = "INSERT INTO Invoice_Line_Items SET
                INVOICE_NUMBER  = '$invNum',
                DATE                = '$date',
                HOURS               = '$hours',
                RATE                = '$rate',
                DATE_TOTAL      = '$dateTotal'

                ON DUPLICATE KEY UPDATE
                INVOICE_NUMBER  = VALUES(INVOICE_NUMBER),
                DATE                = VALUES(DATE),
                HOURS               = VALUES(HOURS),
                RATE                = VALUES(RATE),
                DATE_TOTAL      = VALUES(DATE_TOTAL)
                ";

        } // END foreach
echo "</table></div>";

I've been trying to adapt the (working) prepared statement/query running above this in the same page, which inserts a single row into a different table. But this 2nd query (into a different db table) inserts data from multiple (dynamic # of) rows from a line-items table within the source form.

I've been hacking at it for hours but I can't quite sort out how to implement a prepared statement with the line-items loop. I thought it would be along these lines, but this is not inserting.

echo "<div class=\"debug\">
            <h4>values \$_POSTed from *LINE-ITEMS TABLE* in input.php:</h4>
            <table>";

// this is the line-items table in the form; don't I have to get these values before the query?
foreach ($_POST['date'] as $i => $value) {
    $invNum     = $_POST['invNum'];
    $date           = $_POST['date'][$i];
    $hours      = $_POST['hours'][$i];
    $rate           = $_POST['rate'][$i];
    $dateTotal  = $_POST['dateTotal'][$i];
    // confirm vars/values
    echo "<tr><td>".$i."</td><td>".$date."</td><td>".$hours."</td><td>".$rate."</td><td>".$dateTotal."</td></tr>";

    $stmt = $mysqli->stmt_init();
    $query = "INSERT INTO Invoice_Line_Items
        INVOICE_NUMBER  = '$invNum',
        DATE                = '$date',
        HOURS               = '$hours',
        RATE                = '$rate',
        DATE_TOTAL      = '$dateTotal'

        ON DUPLICATE KEY UPDATE
        INVOICE_NUMBER  = VALUES(INVOICE_NUMBER),
        DATE                = VALUES(DATE),
        HOURS               = VALUES(HOURS),
        RATE                = VALUES(RATE),
        DATE_TOTAL      = VALUES(DATE_TOTAL)
        ";

        if ($stmt->prepare($query)) {
            $stmt -> bind_param("ssddd", $invNum, $date, $hours, $rate, $dateTotal);
            $stmt -> execute();
            $stmt->close();
        } // if $stmt
} // END foreach

echo "</table></div>";

Can someone please shed some light? Much appreciated.

svs

user1613163
  • 127
  • 1
  • 3
  • 16
  • Have you missed `SET` in `INSERT INTO Invoice_Line_Items`? – u_mulder Sep 19 '14 at 18:06
  • @u_mulder Thx for mentioning this. In fact it seems to have no effect with or without it in the query. I wondered about this myself though because I had 'SET' in my orig queries, but when I updated the first one (single row insert) to a prepared statement, it only worked *without* 'SET'. I don't know why. In any case, it seems there's a bigger syntax/code arrangement issue causing this (2nd, multi-row) insert to fail. – user1613163 Sep 19 '14 at 18:22

1 Answers1

1

You don't need

$stmt = $mysqli->stmt_init();

You should be able to just call

$stmt = $mysqli->prepare($query);

Another problem is you're setting the query up inside your loop. You shouldn't do that. Move $stmt outside the loop and only run execute inside once you've set your variables up. Finally, you need to add ? so MySQL knows the parameters

$query = "INSERT INTO Invoice_Line_Items
    INVOICE_NUMBER  = ?,
    DATE = ?,
    HOURS = ?,
    RATE  = ?,
    DATE_TOTAL = ?

    ON DUPLICATE KEY UPDATE
    INVOICE_NUMBER  = VALUES(INVOICE_NUMBER),
    DATE                = VALUES(DATE),
    HOURS               = VALUES(HOURS),
    RATE                = VALUES(RATE),
    DATE_TOTAL      = VALUES(DATE_TOTAL)
    ";
 $invNum = $date = $hours = $rate = $dateTotal = '';
 $stmt = $mysqli->prepare($query);
 $stmt->bind_param("ssddd", $invNum, $date, $hours, $rate, $dateTotal);

foreach ($_POST['date'] as $i => $value) {
    $invNum     = $_POST['invNum'];
    $date           = $_POST['date'][$i];
    $hours      = $_POST['hours'][$i];
    $rate           = $_POST['rate'][$i];
    $dateTotal  = $_POST['dateTotal'][$i];
    $stmt->execute();
}
Machavity
  • 30,841
  • 27
  • 92
  • 100
  • On first attempt, I got 'Fatal error: Call to a member function bind_param() on a non-object ...'. Then, I restored 'SET' back into the query and that resolved it. I realized that the query in my other prepared statement is differently formatted: INSERT INTO Invoices (INVOICE_NUMBER, INVOICE_DATE, PROJECT_NUMBER, CLIENT, PROJECT_DESCRIPTION, TOTAL_HOURS, SUBTOTAL, TAX, INVOICE_TOTAL, DATE_SENT, DATE_RECEIVED, NOTES)VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). Any particular pros/cons of either syntax? Best practices, etc.? Anyway, thanks again, very much appreciated. – user1613163 Sep 19 '14 at 19:32
  • The INSERT syntax can be done either way. There's no "best practice" that I know of, I'd just be sure to do it the same way every time for consistency – Machavity Sep 19 '14 at 19:37