Tietokannan hallintajärjestelmissä valmis kysely tai parametrisoitu kysely on DBMS:n kyky esikääntää tiedoista erotettu SQL-koodi [1] . Valmisteltujen kyselyiden edut:
Valmis lause on itse asiassa esikäännetty malli, joka korvataan vakioarvoilla jokaisen suorituksen aikana, ja on yleistä käyttää SQL DML -käskyjä , kuten INSERT , SELECT tai UPDATE .
Tavallinen järjestys valmisteltujen lausuntojen käyttämiselle on:
Vaihtoehto valmiille kyselylle on kutsua SQL suoraan sovelluksen lähdekoodista koodia ja dataa yhdistävällä tavalla. Suora vastaa yllä olevaa esimerkkiä:
INSERT INTO products (nimi, hinta) VALUES ("pyörä", "10900");Kaikkia optimointeja ei voida suorittaa lausemallin käännöshetkellä kahdesta syystä: paras kyselysuunnitelma voi riippua tietyistä parametriarvoista, ja paras kyselysuunnitelma voi muuttua ajan myötä muuttuvien taulukoiden ja indeksien vuoksi [4] . Kun valmis kysely suoritetaan vain kerran, se toimii hitaammin ylimääräisen edestakaisen matkan vuoksi palvelimelle [5] . Käyttöönoton rajoitukset voivat myös johtaa suorituskyvyn heikkenemiseen; esimerkiksi jotkin MySQL-versiot eivät tallentaneet välimuistiin valmisteltujen kyselyiden tuloksia [6] . Tallennetut menettelyt , jotka myös esikäännetään ja tallennetaan palvelimelle myöhempää suorittamista varten, tarjoavat samanlaisia etuja. Toisin kuin tallennettuja proseduureja, valmisteltua kyselyä ei yleensä kirjoiteta proseduurikielellä, eikä se voi käyttää tai muokata muuttujia tai käyttää ohjausvirtarakenteita, vaan se luottaa sen sijaan deklaratiiviseen tietokantakyselykieleen. Yksinkertaisuuden ja asiakaspuolen emulointikyvyn vuoksi (jos kohde-DBMS ei tue niitä), valmistetut kyselyt ovat siirrettävissä paremmin eri DBMS-järjestelmien välillä kuin tallennettuja menettelyjä.
Melkein kaikki yleiset tietokantajärjestelmät , mukaan lukien SQLite , [7] MySQL , [8] Oracle , [9] DB2 , [10] Microsoft SQL Server [11] ja PostgreSQL [12] tukevat valmiita kyselyjä. Valmiit kyselyt kutsutaan yleensä käyttämällä erityistä binaariprotokollaa, joka näyttää lisäävän tiedonsiirtonopeutta ja jonka oletetaan edelleen suojaavan SQL-injektiota vastaan, mutta jotkin tietokantajärjestelmät, kuten esimerkiksi MySQL, sallivat virheenkorjaustarkoituksiin kutsua valmiita kyselyitä syntaksin avulla. SQL-kyselyt [13] .
Monet ohjelmointikielet tukevat valmiita kyselyitä vakiokirjastoissaan ja emuloivat niitä tapauksissa, joissa kohdetietokantajärjestelmä ei tue tätä ominaisuutta. Näitä kieliä ovat Java (käyttäen JDBC :tä [14] ), Perl (käyttäen DBI:tä (perl) [15] ), PHP (käyttäen PDO :ta [1] ) ja Python (käyttäen DB-API:tä [16] ) . Asiakaspuolen emulointi voi olla tehokkaampaa yksittäisille pyynnöille ja vähemmän tehokasta useille pyynnöille. Se auttaa myös SQL-injektioita vastaan, samoin kuin valmiiden kyselyjen suora toteuttaminen DBMS-puolella [17] .
Nämä esimerkit käyttävät Javaa ja JDBC :tä:
tuonti com.mysql.jdbc.jdbc2.optional.MysqlDataSource ; tuonti java.sql.Connection ; tuonti java.sql.DriverManager ; tuonti java.sql.PreparedStatement ; tuonti java.sql.ResultSet ; tuonti java.sql.SQLException ; tuonti java.sql.Statement ; public class Main { public static void main ( String [] args ) heittää SQLExceptionin { MysqlDataSource ds = new MysqlDataSource (); ds . setDatabaseName ( "mysql" ); ds . setUser ( "root" ); try ( Connection conn = ds . getConnection ()) { try ( Lauseke stmt = conn . createStatement ()) { stmt . executeUpdate ( "LUO TAULUKU, JOS EI OLE OLEMASSA tuotteita (nimi VARCHAR(40), hinta INT)" ); } try ( PreparedStatement stmt = conn . readyStatement ( "INSERT INTO Products VALUES (?, ?)" )) { stmt . setString ( 1 , "pyörä" ); stmt . setInt ( 2 , 10900 ); stmt . executeUpdate (); stmt . setString ( 1 , "kengät" ); stmt . setInt ( 2 , 7400 ); stmt . executeUpdate (); stmt . setString ( 1 , "puhelin" ); stmt . setInt ( 2 , 29500 ); stmt . executeUpdate (); } try ( PreparedStatement stmt = conn . readyStatement ( "SELECT * FROM products WHERE name = ?" )) { stmt . setString ( 1 , "kengät" ); ResultSet rs = stmt . executeQuery (); rs . seuraava (); Järjestelmä . ulos . println ( rs . getInt ( 2 )); } } } }Java PreparedStatementtarjoaa "setterit" ( setInt(int), setString(String), setDouble(double),jne.) kaikille tärkeimmille sisäänrakennetuille tietotyypeille.
Tässä esimerkissä käytetään PHP :tä ja PDO :ta:
<?php try { // Muodosta yhteys tietokantaan nimeltä "mysql", salasanalla "root" $connection = new PDO ( 'mysql:dbname=mysql' , 'root' ); // Suorita yhteydelle pyyntö, joka luo // taulukon "products" kahdella sarakkeella "nimi" ja "hinta" $connection -> exec ( 'CREATE TABLE IF NOT EXISTS tuotteet (nimi VARCHAR(40), hinta INT)' ); // Valmistele kysely useiden tuotteiden lisäämiseksi taulukkoon $lausunto = $yhteys -> valmistelu ( 'INSERT INTO products VALUES (?, ?)' ); $tuotteet = [ [ 'pyörä' , 10900 ], [ 'kengät' , 7400 ], [ 'puhelin' , 29500 ], ]; // Iteroi tuotteet "products"-taulukossa ja // suorita valmis lause jokaiselle tuotteelle foreach ( $products as $product ) { $lauseke -> suorita ( $tuote ); } // Valmistele uusi lauseke nimetyllä parametrilla $lausunto = $connection -> ready ( 'SELECT * FROM products WHERE nimi = :nimi' ); $lauseke -> suorita ([ ':nimi' => 'kengät' , ]); // Määritä tuotteen nimi ja hinta // vastaaviin muuttujiin [ $product , $price ] = $lausunto -> hae (); // Näytä tulos käyttäjälle echo "Tuotteen hinta { $product } on \$ { $price } ." ; // Sulje kohdistin, jotta `fetch` voidaan lopulta käyttää uudelleen $lauseke -> closeCursor (); } catch ( \Poikkeus $e ) { echo 'Tapahtui virhe:' . $e -> getMessage (); }Tämä esimerkki käyttää Perliä ja DBI :tä:
#!/usr/bin/perl -w käytä tiukkaa ; käytä DBI :tä ; my ( $db_name , $db_user , $db_salasana ) = ( 'oma_tietokanta' , 'moi' , 'Passw0rD' ); minun $dbh = DBI -> yhdistä ( "DBI:mysql:tietokanta=$db_nimi" , $db_user , $db_salasana , { RaiseError => 1 , AutoCommit => 1 }) tai die "VIRHE (main:DBI->connect) kun muodostat yhteyden tietokantaan $db_name: " . $ DBI:: errstr . "\n" ; $dbh -> do ( 'LUO TABLE JOS EI OLE tuotteita (nimi VARCHAR(40), hinta INT)' ); my $sth = $dbh -> valmistaa ( 'INSERT INTO products VALUES (?, ?)' ); $sth -> suorita ( @$_ ) foreach [ 'pyörä' , 10900 ], [ 'kengät' , 7400 ], [ 'puhelin' , 29500 ]; $sth = $dbh -> valmistaa ( "SELECT * FROM products WHERE name =?" ); $sth -> suorita ( 'kengät' ); tulosta "$$_[1]\n" foreach $sth -> fetchrow_arrayref ; $sth -> viimeistely ; $dbh -> katkaise yhteys ;Tämä esimerkki käyttää C# :a ja ADO.NET:iä :
käyttäen ( SqlCommand komento = yhteys . CreateCommand ( ) ) { komento . CommandText = "VALITSE * FROM käyttäjiltä WHERE USERNAME = @käyttäjänimi AND ROOM = @huone" ; komento . Parametrit . AddWithValue ( "@käyttäjänimi" , käyttäjänimi ); komento . Parametrit . AddWithValue ( "@huone" , huone ); käyttäen ( SqlDataReader dataReader = komento . ExecuteReader ()) { // ... } }Nämä esimerkit käyttävät Python- ja DB-API:tä:
tuo mysql.connector mysql :n kanssa . liitin . connect ( tietokanta = "mysql" , käyttäjä = "root" ) as conn : with conn . kursori ( valmis = True ) kursorina : kursori . _ execute ( "LUO TABLE JOS EI OLE tuotteita (nimi VARCHAR(40), hinta INT)" ) params = [( "pyörä" , 10900 ), ( "kengät" , 7400 ), ( "puhelin" , 29500 )] kohdistin . executemany ( "INSERT INTO products VALUES ( %s , %s )" , params ) params = ( "kengät" ,) kohdistin . execute ( "SELECT * FROM products WHERE name = %s " , parametrit ) print ( cursor . fetchall ()[ 0 ][ 1 ])