Zend_Db_Select jest narzędziem pomagającym w budowaniu zapytań SQL SELECT w sposób niezależny od rodzaju bazy danych. Oczywiście nie może to być perfekcyjne, ale pomaga w tym, aby zapytania były przenośne pomiędzy różnymi systemami bazodanowymi. Dodatkowo pomaga to w uodpornieniu zapytań na ataki SQL injection.
Najprostszy sposób utworzenia instancji Zend_Db_Select to użycie metody Zend_Db_Adapter::select().
<?php require_once 'Zend/Db.php'; $params = array ( 'host' => '127.0.0.1', 'username' => 'malory', 'password' => '******', 'dbname' => 'camelot' ); $db = Zend_Db::factory('PDO_MYSQL', $params); $select = $db->select(); // $select jest teraz obiektem Zend_Db_Select skonfigurowanym do użycia z adapterem PDO_MYSQL. ?>
Wtedy konstruujesz zapytanie SELECT używając tego obiektu i jego metod, a następnie generujesz łańcuch znaków który przekazujesz spowrotem do obiektu Zend_Db_Adapter w celu wykonania zapytania.
<?php // // SELECT round_table.* // FROM `round_table` round_table // WHERE `noble_title` = 'Sir' // ORDER BY `first_name` // LIMIT 10 OFFSET 20 // // możesz użyć stylu iteracyjnego... $select->from('round_table'); $select->where('noble_title = ?', 'Sir'); $select->order('first_name'); $select->limit(10,20); // ...lub stylu łańcuchowego: $select->from('round_table') ->where('noble_title = ?', 'Sir') ->order('first_name') ->limit(10,20); // pobieramy dane: $sql = $select->__toString(); $result = $db->fetchAll($sql); // druga alternatywa: możesz przekazać sam obiekt $select; $result = $db->fetchAll($select); // trzecia alternatywa: tworzysz obiekt Zend_Db_Statement // lub PDOStatement bezpośrednio z obiektu $select: $stmt = $select->query(); $result = $stmt->fetchAll(); ?>
Możesz także użyć parametrów wstawianych w miejsce nazwanych znaczników, zamiast cytowania parametrów po kolei.
<?php // // SELECT round_table.* // FROM `round_table` round_table // WHERE noble_title = 'Sir' // ORDER BY `first_name` // LIMIT 10 OFFSET 20 // $select->from('round_table', '*') ->where('noble_title = :title') ->order('first_name') ->limit(10,20); // pobieramy wyniki używająć parametrów wstawianych w miejsce znaczników $params = array('title' => 'Sir'); $result = $db->fetchAll($select, $params); ?>
Aby wybrać kolumny z określonej tabeli, użyj metody from(), określając tabelę oraz kolumny których potrzebujesz. Możesz użyć aliasów dla tabel oraz kolumn, i możesz używać metody from() tyle razy ile potrzebujesz.
<?php // tworzymy obiekt $db, zakładając, że adapter to Mysql $select = $db->select(); // SELECT some_table.`a`, some_table.`b`, some_table.`c` // FROM `some_table` some_table $select->from('some_table', array('a', 'b', 'c')); // SELECT bar.`col` // FROM `foo` bar $select->from(array('foo' => 'bar'), 'col'); ?>
Drugi argument do metody from() jest wartością skalarną dla
pojedynczej nazwy kolumny, lub tablicą dla wielu nazw kolumn.
Wartość skalarna lub element tablicy może być łańcuchem znaków,
który jest interpretowany jako prosta nazwa kolmny i jest ona
cytowana, a na początek nazwy dołączany jest alias tabeli. Jeśli
pominiesz drugi argument, przyjęta zostanie jego domyślna wartość
'*'
, co nie jest cytowane, ale do tej wartości też
zostanie dołączony alias tabeli. Jeśli nie chcesz by kolumny z tej
tabeli znajdowały się w zestawie wyników, użyj pustej tablicy
array()
.
Nie określaj wielu kolumn jako pojedynczego łańcucha znaków z nazwami kolumn oddzielonymi przecinkami. Taka składnia była używana we wcześniejszych wydaniach Zend_Db i nie jest ona już obsługiwana. Użyj zamiast tego tablicy.
Alias tabeli jest dołączany do każdego elementu będącego łańcuchem znaków znajdującym się w drugim argumencie, ale jeśli element jest obiektem typu Zend_Db_Expr, to jego wartość w postaci łańcucha znaków jest używana bez cytowania oraz dodawania alisu tabeli.
<?php $select = $db->select(); // SELECT foo.col AS col1, bar.col AS col2 // FROM foo, bar $select->from('foo', array( new Zend_Db_Expr('foo.col AS col1'), new Zend_Db_Expr('CURDATE()') ); $select->from('bar', new Zend_Db_Expr('bar.col AS col2')); ?>
Użyj tablicy asocjacyjnej aby zadeklarować aliasy dla tabel. Klucz
tablicy jest nazwą tabeli, a wartośc jest aliasem. Jeśli zamiast
tego określisz nazwę tabeli jako zwykły łańcuch znaków, a nie jako
asocjacyjną tablicę, to Zend_Db_Select wygeneruje alias dla tabeli.
Domyślnie generowany jest alias o tej samej nazwie jak tabela, czyli
tak jak na przykład w zapytaniu SQL
"SELECT foo.* FROM `foo` foo
". Jeśli dodasz tę samą
tabelę więcej niż raz, na przykład w złączeniu SELF JOIN,
Zend_Db_Select zadeklaruje unikalny alias dla każdej instancji
tabeli, jak np. "foo_1
", "foo_2
", itd.
Aby wybrać kolumny używając złączonych tabel, użyj metody join(). Wpierw określ nazwę złączanej tabeli, następnie wyrażenie łączące, a na końcu kolumny które potrzebujesz dołączyć. Możesz użyć metody join() tyle razy ile potrzebujesz.
<?php // tworzymy obiekt $db, zakładając, że adapter to Mysql $select = $db->select(); // SELECT foo.*, bar.* // FROM `foo` foo // JOIN `bar` bar ON foo.id = bar.id $select->from('foo'); $select->join('bar', 'foo.id = bar.id'); ?>
Pierwszy argument dla metody join() określa tabelę. Działa to analogicznie jak pierwszy argument metody from(), w którym nazwa tabeli może być łańcuchem znaków lub asocjacyjną tablicą mapującą nazwę tabeli do aliasu.
Drugi argument dla metody join() jest wyrażeniem tworzącym warunek złączenia. Możesz tu użyć aliasów tabel, ale pamiętaj, że jeśli nie określiłeś aliasów tabel, to Zend_Db_Select sam je wygeneruje. Jeśli pominiesz warunek złączenia, będzie to odpowiadało użyciu złączenia krzyżowego CROSS JOIN lub iloczynu kartezjańskiego.
Trzeci argument dla metody join()jest listą kolumn ze złączonej
tabeli, które mają być dołączone do listy wyników. Działa to
analogicznie jak drugi argument dla metody from(), w którym może
być wartość skalarna z nazwą tabeli, lub tablica wartości
skalarnych w celu wybrania wielu kolumn. Każda wartość skalarna może
być łańcuchem znakow lub obiektem typu Zend_Db_Expr. Jeśli pominiesz
ten argument, jako wartość domyślna zostanie przyjęty znak
'*'
. Jeśli nie chcesz by kolumny z dołączonej
tabeli znajdowały się w zestawie wyników, użyj pustej tablicy
array()
.
Nie określaj wielu kolumn jako pojedynczego łańcucha znaków z nazwami kolumn oddzielonymi przecinkami. Taka składnia była używana we wcześniejszych wydaniach Zend_Db i nie jest ona już obsługiwana. Użyj zamiast tego tablicy.
Obsługiwane są następujące typy złączeń:
INNER JOIN za pomocą metody
join()
lub joinInner()
.
Wszystkie rodzaje RDBMS obsługują ten typ złączeń.
LEFT JOIN za pomocą metody
joinLeft()
.
Wszystkie rodzaje RDBMS obsługują ten typ złączeń.
RIGHT JOIN za pomocą metody
joinRight()
.
Niektóre rodzaje RDBMS nie obsługują tego typu złączeń.
FULL JOIN za pomocą metody
joinFull()
.
Niektóre rodzaje RDBMS nie obsługują tego typu złączeń.
CROSS JOIN za pomocą metody
joinCross()
.
Nie ma żadnego parametru dla tej metody do określania
warunku złączenia.
Niektóre rodzaje RDBMS nie obsługują tego typu złączeń.
NATURAL JOIN za pomocą metody
joinNatural()
.
Nie ma żadnego parametru dla tej metody do określania
warunku złączenia; przy złączeniu naturalnym zakładane jest,
że jest tworzone równościowe złączenie kolumn o tej samej
nazwie w obu tabelach.
Obsługiwane jest jedynie złączenie NATURAL INNER JOIN.
Aby dodać warunki WHERE, użyj metody where(). Możesz przekazać zwykły łańcuch znaków lub możesz przekazać łańcuch znaków ze znacznikiem w postaci znaku zapytania oraz wartość która ma być zacytowana. (wartość będzie zacytowana za pomocą metody Zend_Db_Adapter::quoteInto).
Kolejne wywołania where() będą łączyć warunki za pomocą AND; jeśli chcesz je złączyć za pomocą OR, użyj metody orWhere().
<?php // tworzymy obiekt $db, a następie odbieramy narzędzie SELECT. $select = $db->select(); // SELECT r.* // FROM `round_table` r // WHERE noble_title = 'Sir' // AND favorite_color = 'yellow' $select->from(array('round_table' => 'r')); $select->where("noble_title = 'Sir'"); // osadzona wartość $select->where('favorite_color = ?', 'yellow'); // cytowana wartość // SELECT foo.* // FROM `foo` foo // WHERE bar = 'baz' // OR id IN('1', '2', '3') $select->from('foo'); $select->where('bar = ?', 'baz'); $select->orWhere('id IN(?)', array(1, 2, 3)); ?>
Zend_Db_Select nie stosuje cytowania oraz aliasów tabeli dla nazwanych kolumn w wyrażeniach WHERE. Jeśli zmiennych PHP używasz do tworzenia łańcucha znaków dla wyyrażenia WHERE, powinienes użyć metody Zend_Db_Adapter quoteIdentifier() aby ochronić twoje zapytania przed niedozwoloną składnią.
<?php ... $columnName = 'bar'; // lub ustawione przez niezaufane źródło $whereExpr = $db->quoteIdentifier($columnName) . ' = ?'; $select->where($whereExpr, 'baz'); ?>
Aby grupować wiersze użyj metody group() tyle razy ile potrzebujesz.
<?php // tworzymy obiekt $db, a następie odbieramy narzędzie SELECT. $select = $db->select(); // SELECT COUNT(id) // FROM `foo` foo // GROUP BY `bar`, `baz` $select->from('foo', new Zend_Db_Expr('COUNT(id)')); $select->group('bar'); $select->group('baz'); // wywołanie metody group(): $select->group(array('bar', 'baz')); ?>
Nie określaj wielu kolumn jako pojedynczego łańcucha znaków z nazwami kolumn oddzielonymi przecinkami. Taka składnia była używana we wcześniejszych wydaniach Zend_Db i nie jest ona już obsługiwana. Użyj zamiast tego tablicy.
Cytowanie jest stosowane do każdego elementu będącego łańcuchem znakow, znajdującym się argumencie dla group(), ale jeśli element ten jest obiektem typu Zend_Db_Expr, jego wartość jest używana bez cytowania.
Aby dodać warunki HAVING dla wybranych wyników użyj metody having(). Ta metoda jest identyczna w użyciu jak metoda where().
Kolejne wywołania having() będą łączyć warunki za pomocą AND; jeśli chcesz je złączyć za pomocą OR, użyj metody orHaving().
<?php // tworzymy obiekt $db, a następie odbieramy narzędzie SELECT. $select = $db->select(); // SELECT COUNT(id) AS count_id // FROM `foo` foo // GROUP BY `bar`, `baz` // HAVING count_id > '1' $select->from('foo', new Zend_Db_Expr('COUNT(id) AS count_id')); $select->group(array('bar', 'baz')); $select->having('count_id > ?', 1); ?>
Zend_Db_Select does not apply quoting or table aliases to columns named in HAVING clauses. If you combine PHP variables into the string for a HAVING expression, you should use the Zend_Db_Adapter quoteIdentifier() method to protect against illegal syntax.
<?php ... $columnName = 'count_id'; // lub ustawione przez niezaufane źródło $havingExpr = $db->quoteIdentifier($columnName) . ' > ?'; $select->having($havingExpr, 1); ?>
Aby sortować dane użyj metody order() tyle razy ile potrzebujesz.
<?php // tworzymy obiekt $db, a następie odbieramy narzędzie SELECT. $select = $db->select(); // SELECT r.* // FROM `round_table` r // ORDER BY `noble_title` DESC, `first_name` ASC $select->from('round_table'); $select->order('noble_title DESC'); $select->order('first_name'); // wywołanie metody order(): $select->order(array('noble_title DESC', 'first_name')); ?>
Nie określaj wielu kolumn jako pojedynczego łańcucha znaków z nazwami kolumn oddzielonymi przecinkami. Taka składnia była używana we wcześniejszych wydaniach Zend_Db i nie jest ona już obsługiwana. Użyj zamiast tego tablicy.
Cytowanie jest stosowane do każdego elementu będącego łańcuchem znakow, znajdującym się argumencie dla order(), ale jeśli element ten jest obiektem typu Zend_Db_Expr, jego wartość jest używana bez cytowania.
Zend_Db_Select oferuje obsługę bazodanowej składni LIMIT. Dla wielu baz danych, np. MySQL czy PostgreSQL, jest to relatywnie proste, ponieważ obsługują one składnię "LIMIT :count [OFFSET :offset]".
Dla niektórych innych baz danych, nie jets to takie proste, ponieważ nie obsługują one składni LIMIT. Microsoft SQL Server posiada składnię TOP, która daje taki sam rezultat. Oracle oraz DB2 wymagają zapytań napisanych w specjalny sposób aby emulować składnię LIMIT. Zend_Db_Select może przepisać zapytanie SELECT odpowiednio dla każdego ze sterowników bazy danych aby umożliwiać obsługę funkcjonalności LIMIT.
Aby limitować zwracane wyniki na podstawie ilości i offsetu użyj metody limit() podając ilość oraz opcjonalny offset.
<?php // na początek prosty "LIMIT :count" $select = $db->select(); $select->from('foo'); $select->order('id'); $select->limit(10); // W MySQL/PostgreSQL/SQLite odpowiada to zapytaniu: // // SELECT foo.* // FROM "foo" foo // ORDER BY "id" ASC // LIMIT 10 // // A w Microsoft SQL Server odpowiada to zapytaniu: // // SELECT TOP 10 foo.* // FROM [foo] foo // ORDER BY [id] ASC // a teraz bardziej złożony "LIMIT :count OFFSET :offset" $select = $db->select(); $select->from('foo', '*'); $select->order('id'); $select->limit(10, 20); // W MySQL/PostgreSQL/SQLite odpowiada to zapytaniu: // // SELECT foo.* // FROM "foo" foo // ORDER BY "id" ASC // LIMIT 10 OFFSET 20 // // Microsoft SQL Server nie obsługuje offset, więc odpowiada to zapytaniu: // // SELECT * FROM ( // SELECT TOP 10 * FROM ( // SELECT TOP 30 * // FROM [foo] foo // ORDER BY [id] DESC // ) ORDER BY id ASC // ) // // Zend_Db_Adapter automatycznie tłumaczy zapytanie. ?>
Zend_Db_Select oferuje limitowanie wyników oparte na stronach. Jeśli chcesz pobrać pewną stronę wyników, użyj metody limitPage(); wpierw przekaż numer strony którą potrzebujesz, a nąstępnie ilość wierszy jaka ma się pojawiać na każdej ze stron.
<?php // budujemy podstawowe zapytanie select... $select = $db->select(); $select->from('foo'); $select->order('id'); // ... i limitujemy do strony 3 gdzie każda strona ma 10 wierszy $select->limitPage(3, 10); // W MySQL/PostgreSQL/SQLite, odpowiada to zapytaniu: // // SELECT foo.* // FROM `foo` foo // ORDER BY `id` ASC // LIMIT 10 OFFSET 20 ?>
Metoda distinct() pozwala dodać słowo kluczowe DISTINCT do twojego zapytania SQL.
<?php // SELECT DISTINCT foo.`non_unique_column` // FROM `foo` foo $select = $db->select(); $select->distinct(); $select->from('foo', 'non_unique_column'); ?>
Metoda forUpdate() pozwala dodać ci słowa kluczowe FOR UPDATE do twojego zapytania SQL.
<?php // SELECT FOR UPDATE foo.* // FROM `foo` foo $select = $db->select(); $select->forUpdate(); $select->from('foo'); ?>
Metoda query() działa podobnie jak metoda query() obiektu klasy Zend_Db_Adapter. Zwraca ona obiekt typu Zend_Db_Statement lub PDOStatement, zależnie od typu używanego sterownika.
<?php $select = $db->select(); $select->from('foo'); $stmt = $select->query(); $result = $stmt->fetchAll(); // Jest to równoznaczne z poniższym: $select = $db->select(); $select->from('foo'); $stmt = $db->query($select); $result = $stmt->fetchAll(); ?>
Metoda getPart() zwraca dane, ktore przypisałeś do części zapytania SQL. Klasa Zend_Db_Select zawiera definicje stałych, których możesz użyć dla części zapytania SQL.
<?php // SELECT foo.* // FROM `foo` foo // ORDER `keyColumn` $select = $db->select(); $select->from('foo'); $select->order('keyColumn'); print_r( $select->getPart( Zend_Db_Select::ORDER ) ); ?>
Metoda reset() pozwala ci na wyczyszczenie jednej określonej części zapytania SQL, lub na wyczyszczenie wszystkich części zapytania SQL, jeśli pominiesz argument podczas wywołania.
<?php // SELECT foo.* // FROM `foo` foo // ORDER BY `column1` $select = $db->select(); $select->from('foo'); $select->order('column1'); // Chcemy zmienić kryteria sortowania // // SELECT foo.* // FROM `foo` foo // ORDER BY `column2` // Czyścimy jedną część aby zdefiniować ją ponownie $select->reset( Zend_Db_Select::ORDER ); $select->order('column2'); // Czyścimy wszystkie części zapytania $select->reset(); ?>