Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [php5]Klasa tworząca zapytania SQL - czy to ma sens?
Forum PHP.pl > Forum > PHP > Object-oriented programming
Joachim Peters
Witam,

Czy jest sens pisać klasę, która będzie tworzyć zapytania pod SQL? Nie chcę się później zatłoczyć tym w skrypcie więc pytam was o radę.

Pozdrawiam
LBO
Oczywiście, że jest... przy odrobinie pracy, można zdziałać cuda.

Spójrz na Zend_Db_Select.
domis86
Moje zdanie:
Nie ma sensu - po co? tiredsmiley.gif
Co Ci to da?
Joachim Peters
Napisałem sobie coś takiego
  1. <?php
  2. class MySQL {
  3. private $sql;
  4. private $executedQueries = array();
  5. private $executedQueriesInt  = 0;
  6.  
  7. public function query($sql) {
  8. return mysql_query($sql);
  9.  
  10. $this->executedQueries += $sql;
  11. $this->executedQueriesInt++;
  12. }
  13.  
  14. public function insert($table, $data) {
  15. if(!empty($table) && count($data)) {
  16. $sql = 'INSERT INTO '.$table.' (';
  17.  
  18. $keysInt = count($data);
  19.  
  20. foreach($data as $key => $value) {
  21. $keys++;
  22.  
  23. if($keys != $keysInt) {
  24. $sql .= "$key, ";
  25. } else {
  26. $sql .= $key;
  27. }
  28. }
  29.  
  30. $sql .= ') VALUES (';
  31.  
  32. $keys = 0;
  33.  
  34. foreach($data as $key => $value) {
  35. $keys++;
  36.  
  37. if($keys != $keysInt) {
  38. $sql .= "$value, ";
  39. } else {
  40. $sql .= $value;
  41. }
  42. }
  43.  
  44. $sql .= ')';
  45.  
  46. $this->query($sql);
  47. }
  48. }
  49.  
  50. public function update($table, $data, $where, $limit = NULL) {
  51. if(!empty($table) && count($data) && !empty($where)) {
  52. $sql = 'UPDATE '.$table.' SET ';
  53.  
  54. $keysInt = count($data);
  55.  
  56. foreach($data as $key => $value) {
  57. $keys++;
  58.  
  59. if($keys != $keysInt) {
  60. $sql .= "$key = $value, ";
  61. } else {
  62. $sql .= "$key = $value";
  63. }
  64. }
  65.  
  66. $sql .= ' WHERE '.$where;
  67. $sql .= (!empty($limit)) ? ' LIMIT '.$limit : '';
  68.  
  69. $this->query($sql);
  70. }
  71. }
  72.  
  73. public function delete($table, $where, $limit = NULL) {
  74. if(!empty($table) && !empty($where)) {
  75. $limit = (!empty($limit)) ? 'LIMIT '.$limit : '';
  76. $where = 'WHERE '.$where;
  77.  
  78. $sql = "DELETE FROM $table $where $limit";
  79.  
  80. $this->query($sql);
  81. }
  82. }
  83.  
  84. public function getQueriesInt() {
  85. return $this->executedQueriesInt;
  86. }
  87.  
  88. public function getQueries() {
  89. return $this->executedQueries;
  90. }
  91.  
  92. public function getLastQuery() {
  93. return $this->sql;
  94. }
  95. }
  96.  
  97. $db = new MySQL;
  98. ?>


klasa na razie bardzo uboga.

Przykład:
  1. <?php
  2. $array = array(
  3. 'name'  => 'Ktos',
  4. 'password'  => 'test',
  5. 'from'  => 'Poland',
  6. 'age'  => 'xx'
  7. );
  8.  
  9. $db->insert('users', $array);
  10. ?>

nie wiem czy jest sens to dalej kodować czy pozostać przy bardziej standardowych metodach wykonywania zapytań.
domis86
załóżmy ze masz pobierac dane powiązane relacjami z roznych tabel i jeszcze do tego zagniezdzone zapytania i JOINy
oplaca sie pisac do tego taką "nakladke" ? Ja mysle ze nie snitch.gif
LBO
Myślałem, że chodziło Tobie o coś mapującego do SQL... np.

Query::select(Query::ALL)->from('Users')->where('name == 'LBO');
sobstel
odpowiadając na pytanie w temacie, nie ma sensu pisać takiej klasy, ponieważ takcih rozwiązań już mamy dużo, szczególnie polecam osobny wątek o ORMach na tym forum
Mazur_pl
Ja mam pytanie jeszcze. Czy jest sens używać PDO ?
domis86
PDO to jest co innego smile.gif
Jest sens, ale zalezy do czego aarambo.gif
AcidBurnt
co do klasy tworzacej sql jaknajbardziej TAK, nawet jesli dziala ona tylko na proste inserty updaty to warto bo mozna ja napsiac tak ze mozna do niej poksojnie wyslac normalne zapytanie zlozone, przeciez fucja moze przymowac rozna liczbe parametrów, jak jest 1 czyli samo zapytanie leic od razu do bazy jak parametrów jest wiecej parsuje je i wysla zapynie do bazy

bo tak naprawde ulatwi to podstawowe operacje na bazie

bo jak czesto uzywamy mega zaawansowanych zapytan ....
Ludvik
PDO wprowadza pewną abstrakcję na źródło danych, więc raczej warto go używać. Chyba, że potrzebujesz nietypowych funkcji związanych z rozszerzeniem obsługującym bazę, tak jak zauważyli developerzy PHP:
Cytat
Issue: PHP 5.1 introduces PDO, an extension that unifies Database APIs. With this we do not "need" older extensions to access databases anymore.

Discussion: We can not remove the "old" extensions, as at least OCI8 and MySQLi provide a very rich set of features, which are not all supported by PDO. Some "old" extensions can probably be moved to PECL as they are either unmaintained, or superseded by PDO.

Conclusions:

  1. We decide on moving DB extensions out of the core later.
pawel_k
Cytat(domis86 @ 23.06.2007, 15:10:57 ) *
Moje zdanie:
Nie ma sensu - po co? tiredsmiley.gif
Co Ci to da?

jeszcze dorośniesz do odpowiedzi winksmiley.jpg
Sedziwoj
Cytat(pawel_k @ 27.06.2007, 00:22:50 ) *
jeszcze dorośniesz do odpowiedzi winksmiley.jpg


To zdanie nic nie wnosi do dyskusji, jak komentować to z argumentami.
Ja dla takiego rozwiązania nie widzę na razie, w tym co robię, potrzeby używania, nie wnikając już w ogólny sens tworzenia tego.
Cienki1980
Pisanie takiej klasy ma sens w jednym przypadku, gdy tworzysz jakąś aplikacje, którą później będziesz chciał przerobić na inną bazę danych.
Różnice w zapytaniach np między postgreSQL a MySQL są niewielkie ale jednak są ( chociażby fakt jak wstawia się limity i offsety do zapytań ).

Podczas korzystania z takiej klasy zmieniasz kod na potrzeby innej bazy w nieporównywalnie krótszym czasie niż szukanie każdego zapytania w kodzie we wszystkich skryptach.

Ale sam jestem przeciwny takiemu rozwiązaniu bo brakuje zapytań złożonych. Ja w tej chwili pracuje na takim obiekcie i mam do dyspozycji takie metody:
- wyciagnięcie wszystkich wyników z danej tabeli
- wyciągnięcie jednego wyniku z danej tabeli ( jednego wiersza )
- dodanie rekordu
- aktualizacja rekordu
- usuniecie rekordu
- wyciągniecie wszystkich wyników z wieloma warunkami
- wyciagnięcie danych z dwóch tabel ( tylko left join )

Do podstawowych skryptów wystarcza, ale miałem kilka przypadków gdy zamiast jednego zapytania wielokrotnie złożonego musiałem wykonać dwa zapytania z czego jedno w pętli.

Poza tym nie ma wpisanych wszystkich możliwości warunków ( jest równe, różne, in, not in, większe od ) a przecież SQL pozwala na dużo więcej.

Moja odpowiedź .. do prostych rzeczy można pisać taką klasę .. do bardziej zaawansowanych ( korzystających z dużych baz danych z bardzo rozbudowanymi relacjami ) mija się to z celem.
szef
Dołączam się do tego co napisał Cienki1980.Napisałem klasę do obsługi bazy danych działającą na bibliotece PDO. Jeśli chodzi o proste proste zapytania wszytsko jest ok jednak przy tych trudniejszych (LEFT JOIN, formatowanie daty itp.) klasa już nie daje rady. Więc uważam tak jak przedmówca do prostych rzeczy taka klasa się świetnie sprawdza w przeciwnym przypadku już nie.

Pozdrawiam
pawel_k
Cytat(Sedziwoj @ 27.06.2007, 08:20:41 ) *
To zdanie nic nie wnosi do dyskusji, jak komentować to z argumentami.
racja, przepraszam smile.gif
na początek wspomnę tylko że tak jak LBO myślałem że chodzi o ORM czy coś podobnego. Tworzenie klasy takiej jak załączona w którymś poście wyżej nie ma sensu, chyba że do nauki, ale to raczej marny pretekst. Takich rozwiązań jest pełno i szkoda że ludzie zamiast poświęcić chwilkę na naukę gotowca wymyślają własne imitacje nic nie wnoszące do tematu. jasne, ktoś może uważać że np. creole jest niewystarczające do jego potrzeb (w co wątpię) więc potrzebuje czegoś więcej. ale 99.9% wszystkich klas robi tylko query, limit i offset czy inne rzeczy nie wychodząc poza przyjęte standardy.
tak samo jest z orm - ludzie jadą po propelu bo nie pozwala na wygenerowanie niezwykle rozbudowanych zapytań łączących np. 4 tabele.i to jest powód do porzucenia wszystkich jego zalet i pisanie sql'a z łapy. tyle że większość z tych krytykujących takich zapytań nawet nie zobaczy we własnym projekcie, a poza tym jeśli nawet będą takie zapytania to najwyżej jedno na 20. to sorry, ale ja w takim wypadku wolę w 19/20 przypadków użyć propela w w tym jednym skorzystać z creole.

a poza tym w tej klasie załączonej jest błąd:
  1. <?php
  2. public function query($sql) {
  3. return mysql_query($sql);
  4.  
  5. $this->executedQueries += $sql;
  6. $this->executedQueriesInt++;
  7. }
  8. ?>
jak zrobisz return mysql_query($sql); to reszta metody już się nei wykona, pomijając fakt że nie możesz zrobiść czegoś takigo jak $this->executedQueries += $sql; na tablicy winksmiley.jpg
domis86
Cytat(pawel_k @ 29.06.2007, 08:47:47 ) *
...pomijając fakt że nie możesz zrobiść czegoś takigo jak $this->executedQueries += $sql; na tablicy winksmiley.jpg

A wlasnie ze mozesz cool.gif
http://www.php.net/manual/en/language.operators.array.php
pawel_k
Cytat(domis86 @ 29.06.2007, 14:57:47 ) *

a to ja mam chyba jakieś ubogie php winksmiley.jpg
  1. <?php
  2. $arr = array();
  3. $arr += '345';
  4. ?>
Cytat
Fatal error: Unsupported operand types in /var/www/test.php on line 3
bo przecież parametr $sql jest stringiem...
phpion
Może:
  1. <?php
  2. $arr = array();
  3. $arr[] = '345';
  4. $arr[] = '678';
  5. print_r($arr);
  6. ?>

?
athabus
A mi się wydaje, że dobrze jest pisać nawet takie proste klasy. Trudno mi sobie wyobrazić, że ktoś przesiada się z pisania sql "z palca" na propela. To jest po prostu naturalna ścieżka rozwoju
- piszesz wszystko sam
- wpadasz na przełomowy pomysł, że lepiej stworzyć jakąś klasę, która pozwoli ci na łatwiejsze wywoływanie zapytań, będzie się troszczyć o filtrowanie i escapowanie danych itp.
- potem odkrywasz, że jest coś co napisałeś, tylko pracowało nad tym wielu ludzi i działa znacznie lepiej, uwzględnia więcej możliwości itp.
- i wreszcie kończysz na orm'ach

Jestem w stanie założyć się, że każdy kto dziś używa propela wcześniej przeszedł coś takiego jak opisałem.

Co do istoty samej przytoczonej klasy - fakt jest mało poręczna i w prawie każdym projekcie wyjdzie, że czegoś jej brakuje, ale po pierwsze jest dobra na początek i w czasie projektu pewnie zostanie kilka razy poprawiona i przebudowana. A co najważniejsze umożliwia scentralizowane wywoływanie zapytań, a więc łatwe ich logowanie, obliczanie czasów ich wykonania itp.

Trudno mi się też zgodzić ze stwierdzeniem, że klasy "do sql" mają sens tylko, gdy korzystasz z różnych silników. Dla mnie to przede wszystkim wygoda tworzenia + to co opisałem wyżej. Powiem szczerze, że mam awersję do ręcznego pisania zapytań sql, łączenia stringów, rozbijania tablic do warunków in, dbanie o prawidłowe escapowanie daneych itp. Wolę jak większość automatycznych czynności wykona klasa za mnie.
Joachim Peters
Przeczytałem wasze wypowiedzi i doszedłem do wniosku, że budowanie klasy, która tworzy całe zapytania jest niepotrzebne, ponieważ to rozwiązanie jest mało elastyczne.
Napisałem sobie zatem, "na sucho" coś takiego:
  1. <?php
  2.  
  3. class sqlArrayBuild {
  4. public $sqlArray = array();
  5.  
  6. public function build($mode) {
  7. switch($mode) {
  8. case 'INSERT':
  9. $sql = '(';
  10. $sizeOfArray = count($this->sqlArray);
  11.  
  12. foreach($this->sqlArray as $fieldName => $fieldValue) {
  13. $size++;
  14. $sql .= ($size < $sizeOfArray) ? $fieldName.', ' : $fieldName;
  15. }
  16.  
  17. $sql .= ') VALUES (';
  18. $size = 0;
  19.  
  20. foreach($this->sqlArray as $fieldName => $fieldValue) {
  21. $size++;
  22. $sql .= ($size < $sizeOfArray) ? $fieldValue.', ' : $fieldValue;
  23. }
  24.  
  25. $sql .= ')';
  26.  
  27. return $sql;
  28. break;
  29.  
  30. case 'UPDATE':
  31. $sizeOfArray = count($this->sqlArray);
  32.  
  33. foreach($this->sqlArray as $fieldName => $fieldValue) {
  34. $size++;
  35. $sql .= ($size < $sizeOfArray) ? $fieldName.' = '.$fieldValue.', ' : $fieldName.' = '.$fieldValue;
  36. }
  37.  
  38. return $sql;
  39. break;
  40. }
  41. }
  42.  
  43. public function clearArray() {
  44. $this->sqlArray = '';
  45. }
  46. }
  47.  
  48. ?>


Przykład:

  1. <?php
  2. $sqlArrayBuild = new sqlArrayBuild;
  3.  
  4. $sqlArrayBuild->sqlArray = array(
  5. 'id'  => 2,
  6. 'test'  => 'test',
  7. 'test2' => 'test'
  8. );
  9.  
  10. $sql = 'INSERT INTO users '.$sqlArrayBuild->build('INSERT');
  11.  
  12. $sql = 'UPDATE users SET '.$sqlArrayBuild->build('UPDATE').' WHERE id = '.$sqlArrayBuild->sqlArray['id'].' LIMIT 1';
  13. $sqlArrayBuild->clearArray(); 
  14. ?>

klasa nie tworzy całych zapytań, tylko ich część. Jest to ułatwienie przy dużej ilość używanych w zapytaniu kolumn. To już coś lepszego? smile.gif
Sokal
Ja też byłem kiedyś (no, nie tak dawno) przeciwnikiem ORM-ów, ale jak dobrałem się do dokumentacji Propela to już zrozumiałem jak bardzo się myliłem.

Tobie też radzę zaznajomić się z jakimś ORM-em. Polecam Propela.
domis86
Cytat(Sokal @ 1.07.2007, 20:49:59 ) *
Ja też byłem kiedyś (no, nie tak dawno) przeciwnikiem ORM-ów, ale jak dobrałem się do dokumentacji Propela to już zrozumiałem jak bardzo się myliłem.

Tobie też radzę zaznajomić się z jakimś ORM-em. Polecam Propela.

a to ja odwrotnie - jak sie dobralem do Propela to do tej pory mam wstret do ORMów aarambo.gif
Sokal
Eee...

Zobacz:
  1. <?php
  2. $criteria = new Criteria();
  3. $criteria->add(SettingsPeer::PROPERTY, 'title');
  4.  
  5. $title = SettingsPeer::doSelectOne($criteria);
  6. echo $title->getValue();
  7. ?>

I wszystko jest przejrzyste, nawet dla osoby nie znającej SQL-a winksmiley.jpg

To samo, tyle że w SQL:
  1. SELECT value FROM settings WHERE property='title';

I do czego mieć wstręt?
domis86
Hmm, ja bym powiedzial ze samo SQL jest tu akurat 100 razy bardziej przejrzyste.

A jak uzywasz propela to i tak musisz znac SQl... blinksmiley.gif
pawel_k
Cytat(Sokal @ 1.07.2007, 21:51:57 ) *
I do czego mieć wstręt?
pewnie do tego że jest wolny, a przecież ten jeden użytkownik na godzinę musi mieć wygodę winksmiley.jpg
domis86
pawel_k: Świetny dowcip, a co powiesz na to? :
Temat: Propel relacja n do m niska wydajnosc
tiredsmiley.gif
pawel_k
Cytat(domis86 @ 2.07.2007, 15:35:52 ) *
pawel_k: Świetny dowcip, a co powiesz na to? :
Temat: Propel relacja n do m niska wydajnosc
tiredsmiley.gif

moją odpowiedź w tamtym temacie już zapewne czytałeś, poza tym do skąplikowanych zapytań czy algorytmów to masz creole a nie propela (moja odpowiedź o 19/20 zapytań)... jeszcze jakieś wątpliwości?
athabus
pawel_k ma rację - trudno oczekiwać, że propel zrobi za ciebie wszystko łącznie z praniem. Propel ułatwi rzeczy powtarzalne i sprawi, że nie będziesz musiał zajmować się "bzdetami" tylko tymi rzeczami wymagającymi trochę inwencji.
Co do wydajności - propel demonem szybkości nie jest, ale jeśli piszesz mały system to to nie musisz się tym przejmować, a jeśli piszesz duży system, to zapewne taniej będzie kupić trochę ramu i wykorzystać jego możliwości. Używam tego narzędzia od relatywnie niedawna, ale jestem nim naprawdę zachwycony.
domis86
Ram czy lepszy procek nic nie da jak masz (ogolnie mówiąc) gorszą złożoność obliczeniową algorytmu.
Jesli propel ma powiedzmy (np w relacjach n-m) zlozonosc O(n^2) a normalnie mozna uzyskac O(n) to przy n rzedu 10^7 propel sie zawiesi aarambo.gif chocbys mial nawet procka 10Ghz i 100GB ramu
pawel_k
Cytat(domis86 @ 3.07.2007, 00:33:37 ) *
Ram czy lepszy procek nic nie da jak masz (ogolnie mówiąc) gorszą złożoność obliczeniową algorytmu.
Jesli propel ma powiedzmy (np w relacjach n-m) zlozonosc O(n^2) a normalnie mozna uzyskac O(n) to przy n rzedu 10^7 propel sie zawiesi aarambo.gif chocbys mial nawet procka 10Ghz i 100GB ramu

po pierwsze jeśli pijesz do tematu który dzisiaj założył joebezucha to przejdź tam jeszcze raz i przeczytaj moją odpowiedź.
po drugie jeśli uważasz że lepiej optymalizować algorytmy (oczywiście te już dobrze zoptymalizowane) niż dokładać maszynę to jesteś w błędzie - wzmocnienie sprzętu daje nieporównywalnie większy wzrost wydajności.
po trzecie programowanie to nie tylko kod - to także ekonomia, a patrzenie przez program tylko z punktu technicznego jest mało profesjonalne.
po czwarte zachowujesz się jak troll do którego nie docierają żadne argumenty. powtórzę ostatni raz - w 19/20 przypadków propel w zupełności wystarczy, a do 1/20 przypadków masz creole. jeśli przez ten jeden przypadek chcesz tracić całą resztę funkcjonalności to pozostaje mi tylko współczuć podejścia...
domis86
stary wyluzuj snitch.gif

ok masz racje, ale
Cytat(pawel_k @ 3.07.2007, 00:44:58 ) *
po drugie jeśli uważasz że lepiej optymalizować algorytmy (oczywiście te już dobrze zoptymalizowane) niż dokładać maszynę to jesteś w błędzie - wzmocnienie sprzętu daje nieporównywalnie większy wzrost wydajności.


co do tego:
-jak są dobrze zoptymalizowane to sie ich nie optymalizuje (czyli optymalizuje sie zle zoptymalizowane) smile.gif - np tak jak pisalem wczesniej - gdy zlozonosc jest istotnie gorsza - wtedy maszyna nic nie pomoze, naprawde ! ohmy.gif
pawel_k
Cytat(domis86 @ 3.07.2007, 00:51:08 ) *
jak są dobrze zoptymalizowane to sie ich nie optymalizuje (czyli optymalizuje sie zle zoptymalizowane) smile.gif
taaa, znam maniaków którzy by chętnie robili wstawki z assemblera do php winksmiley.jpg poza tym zawsze można optymalizować - zawsze może ktoś mieć dylemat czy stosować date() czy idate(), czy zamiast rand() stosować mt_rand(). dla mnie to bez sensu. co z tego że pracownik zrobi mi super wydajny kod i nagle odejdzie. nowa osoba przychodząc straci miesiąc czy dwa na naukę jego wypocin podczas gdy korzystając z frameworków nowy pracownik jest gotowy do wydajnej pracy po 2 dniach.

i co z tego że muszę włożyć kilka tysięcy w sprzęt - dokupując maszynę podnoszę granicę po przekroczeniu której aplikacja nie obsłuży już więcej użytkowników, podczas gdy optymalizacja kodu może tylko przekroczenie opóźnić (przy założeniu że cały czas się rozwijamy i zdobywamy nowych userów)
athabus
Cytat(domis86 @ 3.07.2007, 00:33:37 ) *
Ram czy lepszy procek nic nie da jak masz (ogolnie mówiąc) gorszą złożoność obliczeniową algorytmu.
Jesli propel ma powiedzmy (np w relacjach n-m) zlozonosc O(n^2) a normalnie mozna uzyskac O(n) to przy n rzedu 10^7 propel sie zawiesi aarambo.gif chocbys mial nawet procka 10Ghz i 100GB ramu

Naprawdę czepiasz się niepotrzebnie jednego, skrajnego przypadku. Zauważ że sami twórcy propela zdają sobie sprawę, że w pewnych przypadkach ich rozwiązanie może być nieoptymalne i dają ci wiele możliwości łącznie z ręcznym tworzeniem zapytań i wypełnianiem obiektów danymi. Jeśli chodzi o standardowe zapytania typu selecty z prostymi joinami itp to nie zrobisz tego bardziej optymalnie. Jedyne spowolnienie polega na tym, że parsowane jest więcej kodu (klasy propela).
Optymalizacja jest ważna - ale w moim przekonaniu chodzi o to, aby optymalizować tylko tam gdzie jest to konieczne - jeżeli mam osiągnąć 10-15% wzrostu wydajności a wymagać to ma 2 razy więcej pracy bo muszę zrezygnować z frameworków czy orm'ów to dziękuję - wolę przejrzysty, szybko napisany kod.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.