2011-01-11 13 views
10

Próbuję zmienić niektóre zakodowane zapytania w celu użycia sparametryzowanych danych wejściowych, ale napotkam problem: Jak sformatować dane wejściowe dla sparametryzowanych insertów zbiorczych?Wielkoformatowe wkładki sparametryzowane

Obecnie kod wygląda następująco:

$data_insert = "INSERT INTO my_table (field1, field2, field3) "; 
$multiple_inserts = false; 
while ($my_condition) 
{ 
    if ($multiple_inserts) 
    { 
     $data_insert .= " UNION ALL "; 
    } 

    $data_insert .= " SELECT myvalue1, myvalue2, myvalue3 "; 
} 

$recordset = sqlsrv_query($my_connection, $data_insert); 

Potencjalnym rozwiązaniem (modyfikowany How to insert an array into a single MySQL Prepared statement w/ PHP and PDO) wydaje się być:

$sql = 'INSERT INTO my_table (field1, field2, field3) VALUES '; 
$parameters = array(); 
$data = array(); 
while ($my_condition) 
{ 
    $parameters[] = '(?, ?, ?)'; 
    $data[] = value1; 
    $data[] = value2; 
    $data[] = value3; 
} 

if (!empty($parameters)) 
{ 
    $sql .= implode(', ', $parameters); 
    $stmt = sqlsrv_prepare($my_connection, $sql, $data); 
    sqlsrv_execute($stmt); 
} 

Czy istnieje lepszy sposób, aby osiągnąć zbiorczego wkładkę parametryzowane zapytania?

+1

Potencjalnym rozwiązaniem, specyficzne dla sporządzanych sprawozdań , jest "jedno przygotowanie, wielokrotne wykonywanie" –

+0

Próbowałem uniknąć tego, aby ograniczyć potrzebę obsługi transakcji. Jeśli którakolwiek z wstawek się nie powiedzie, cała operacja powinna zakończyć się niepowodzeniem. –

+0

jaka transakcja? –

Odpowiedz

5

Masz trzy opcje.

  1. Zbuduj raz - wykonaj wiele. Zasadniczo przygotowuje się wstawkę jeden raz dla jednego wiersza, a następnie pętlę nad wykonującymi ją wierszami. Ponieważ rozszerzenie SQLSERVER nie obsługuje ponownego wiązania zapytania po jego przygotowaniu (musisz wykonać dirty hacks with references), może to nie być najlepsza opcja.

  2. Zbuduj raz - wykonaj raz. Zasadniczo, budujesz jedną wielką wkładkę, jak powiedziałeś w twoim przykładzie, wiążąc ją raz i wykonując ją. Jest to trochę brudne i pomija niektóre korzyści, które daje przygotowywane zapytanie. Jednak ze względu na wymóg odniesienia z Opcji 1, zrobiłbym to. Myślę, że zbudowanie gigantycznej kwerendy jest czystsze niż zależne od zmiennych odniesień.

  3. Zbuduj wiele - wykonaj wiele. Zasadniczo, weź metodę, którą robisz, i dostosuj ją, aby ponownie przygotować zapytanie co tylu rekordów. Zapobiega to nadmiernie dużym zapytaniom i "partiom" zapytań. Więc coś takiego:

    $sql = 'INSERT INTO my_table (field1, field2, field3) VALUES '; 
    $parameters = array(); 
    $data = array(); 
    
    $execute = function($params, $data) use ($my_connection, $sql) { 
        $query = $sql . implode(', ', $parameters); 
        $stmt = sqlsrv_prepare($my_connection, $query, $data); 
        sqlsrv_execute($stmt); 
    } 
    
    while ($my_condition) { 
        $parameters[] = '(?, ?, ?)'; 
        $data[] = value1; 
        $data[] = value2; 
        $data[] = value3; 
        if (count($parameters) % 25 == 0) { 
         //Flush every 25 records 
         $execute($parameters, $data); 
         $parameters = array(); 
         $data = array(); 
        } 
    } 
    if (!empty($parameters)) { 
        $execute($sql, $parameters, $data); 
    } 
    

metoda Albo wystarczy. Rób to, co uważasz za najlepsze, aby spełnić Twoje wymagania ...

+1

Po prostu dla wyjaśnienia: zarówno w Opcjach 2, jak i 3, instrukcja SQL wyglądałaby tak (jeśli miała być wydrukowana na ekranie): 'INSERT INTO mytable (field1, field2, field3) VALUES (?,?,?) , (?,?,?), (?,?,?), itp., które należy wypełnić tablicą przekazaną do niego. Czy to jest poprawne? –

+0

@Zac: Tak, zgadza się. Trzeci może mieć najwyżej 25 grup (można to zmienić w zależności od rozmiaru danych). Drugi miałby tyle, ile masz wierszy ... – ircmaxell

+0

Wszystkie wartości są wstawiane jako 'PDO :: PARAM_STR', czyż nie? Jak określić typy? –

2

Dlaczego nie wystarczy użyć metody "przygotuj raz, wykonaj wiele". Wiem, że chcesz to albo wszystkie zawieść lub wszystkie prace, ale to nie jest dokładnie trudno poradzić z transakcji:

http://www.php.net/manual/en/pdo.begintransaction.php

http://www.php.net/manual/en/pdo.commit.php

http://www.php.net/manual/en/pdo.rollback.php

+0

To nie jest trudne, ale dodaje poziom złożoności do tego kodu, który nie jest naprawdę potrzebny. Bulk Inserts to najbardziej eleganckie rozwiązanie mojego problemu, a to tylko kwestia składni, której nie byłem pewien. –

+0

Dodatkowo jest to natywne rozszerzenie 'sqlsrv', które nie jest najsmaczniejszą rzeczą na świecie (jeśli korzystał z PDO, prawdopodobnie, ale natywne rozszerzenie sqlsrv brakuje w wielu obszarach) ... – ircmaxell

+1

jeśli punkt z tego jest przejście do paramatyzacji zapytań, dlaczego nie przenieść się do PDO w tym samym czasie? co do "złożoności", nie jest trudno dodać kontrolę, jeśli wywołanie metody execute() nie powiedzie się, a jeśli tak, to można użyć funkcji rollback(), a następnie dowolnej innej obsługi błędów. – Stephen

Powiązane problemy