Working With TSQLQuery/pl: what changed
Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.
Title: Working With TSQLQuery/pl
| Old | New | Line | |
|---|---|---|---|
| 1 | + | Praca z TSQLQuery | |
| 2 | + | ||
| 3 | + | ## Informacje ogólne | |
| 4 | + | ||
| 5 | + | TSQLQuery to obiekt, który może zawierać zbiór danych pochodzący z bazy danych (RDBMS wykorzystujący SQL, taki jak Firebird, MS SQL Server, Oracle...). Poprzez użycie instrukcji SELECT SQL we właściwości SQL TSQLQuery, możesz określić, jakie dane są pobierane z bazy danych do zestawu danych. Gdy zestaw danych zostanie zmieniony przez program (lub użytkownika), zmiany można przesłać z powrotem do bazy danych. | |
| 6 | + | ||
| 7 | + | TSQLQuery można również użyć do bezpośredniej modyfikacji danych: jeśli określisz żądaną instrukcję SQL jak INSERT, UPDATE, DELETE itp. we właściwości SQL i wywołasz metodę ExecSQL TSQLQuery, obiekt zapytania wyśle SQL do bazy danych bez pobierania jakichkolwiek wynikiów. | |
| 8 | + | ||
| 9 | + | Możesz używać klasy TSQLQuery w FPC, ale Lazarus dostarcza również komponent: [[TSQLQuery]]  | |
| 10 | + | ||
| 11 | + | ## Oficjalna dokumentacja | |
| 12 | + | ||
| 13 | + | Zobacz [dokumentację TSQLQuery](http://www.freepascal.org/docs-html/fcl/sqldb/tsqlquery.html) | |
| 14 | + | ||
| 15 | + | Wiele dokumentacji kontekstowej jest teraz dostępnych w Lazarusie. Niestety TSQLQuery nie pojawia się w indeksie pomocy Lazarusa 1.0. Jeśli umieścisz kursor na metodach i właściwościach TSQLQuery, spróbuj nacisnąć klawisz F1, aby sprawdzić, czy ten kod jest udokumentowany; np. to zadziała: | |
| 16 | + | ||
| 17 | + | ``` pascal | |
| 18 | + | var | |
| 19 | + | Q: TSQLQuery | |
| 20 | + | ... | |
| 21 | + | Q.Open; //<--- umieść kursor na Open i naciśnij F1 | |
| 22 | + | ``` | |
| 23 | + | ||
| 24 | + | ## Powszechnie używane kontrolki | |
| 25 | + | ||
| 26 | + | Zestaw danych zwrócony przez TSQLQuery może być wygodnie *wyświetlany* za pomocą kontrolki [[TDBGrid]], ale nie jest ona zbyt dobra do *edycji* danych w poszczególnych polach i komórkach. W tym celu należy umieścić w formularzu niektóre kontrolki jednopolowe obsługujące dane, takie jak [[TDBEdit]], i ustawić ich właściwość DataSource na używane źródło danych. Właściwość DataField powinna mieć ustawioną nazwę pola (np. 'IDENTITY') lub jakieś wyrażenie, które zwraca odpowiedni ciąg znaków. | |
| 27 | + | ||
| 28 | + | Dodanie paska narzędzi [[TDBNavigator]] ułatwia poruszanie się po rekordach i wybieranie rekordów do edycji. Po wybraniu rekordu za pomocą paska narzędzi lub przesuwania myszy po siatce danych, dane dla odpowiedniego wiersza i kolumny pojawiają się w polu TDBEdit, a po kliknięciu przycisku 'Edit' zawartość w polu Edycji może być modyfikowana. Kliknięcie przycisku 'Post' potwierdza zmianę, a kliknięcie przycisku 'Cancel' anuluje zmiany. | |
| 29 | + | ||
| 30 | + | Ogólnie proces wygląda następująco: | |
| 31 | + | ||
| 32 | + | 1. Upuść [[TSQLQuery]] na formularz/moduł danych i ustaw odpowiednie właściwości *Database*, *Transaction* i zapytanie SQL w *SQL*. | |
| 33 | + | 2. Upuść komponent [[TDataSource]] i ustaw jego właściwość *DataSet* na instancję TSQLQuery. | |
| 34 | + | 3. Upuść [[TDBGrid]] na formularzu i ustaw jego właściwość *DataSource* na instancję TDataSource. | |
| 35 | + | 4. Opcjonalnie upuść instancję TDBNavigator na formularzu i ustaw jej właściwość *DataSource* na instancję TDataSource. | |
| 36 | + | ||
| 37 | + | Następnie można ustawić właściwość *Active* na *True* i powinno być możliwe wyświetlenie danych pobranych przez zapytanie. (pod warunkiem, że składniki *TSQLConnection* i *TSQLTransaction* są aktywne) | |
| 38 | + | ||
| 39 | + | ## Aktualizacja danych | |
| 40 | + | ||
| 41 | + | Jeśli chcesz mieć możliwość USUWANIA lub modyfikowania rekordów, to twoja tabela bazy danych powinna: | |
| 42 | + | ||
| 43 | + | 1. zawierać jedną kolumnę PRIMARY KEY. | |
| 44 | + | 2. mieć zestaw pól, które jednoznacznie określają rekord. Zwykle powinny być częścią unikalnego indeksu. Nie jest to wymagane, ale znacznie przyspieszy zapytania. | |
| 45 | + | ||
| 46 | + | Jeśli nie ma pola podstawowego lub pól, które jednoznacznie określają twój rekord, należy dodać pole klucza podstawowego. Najlepiej robi się to, gdy struktura tabeli jest projektowana poleceniem CREATE, ale można ją dodać w późniejszym czasie. | |
| 47 | + | ||
| 48 | + | Na przykład poniższy przykładowy kod w twoim kliencie MySQL doda unikalny indeks do tabeli: | |
| 49 | + | ||
| 50 | + | ``` sql | |
| 51 | + | ALTER TABLE testrig | |
| 52 | + | ADD COLUMN autoid INT | |
| 53 | + | PRIMARY KEY AUTO_INCREMENT; | |
| 54 | + | ``` | |
| 55 | + | ||
| 56 | + | Dodanie tego pola nie zaszkodzi, a pozwoli aplikacjom na aktualizację innych pól. | |
| 57 | + | ||
| 58 | + | ## Aktualizacje z pamięci podręcznej | |
| 59 | + | ||
| 60 | + | Komponent *TSQLQuery* buforuje wszystkie aktualizacje. Oznacza to, że aktualizacje nie są wysyłane natychmiast do bazy danych, ale są przechowywane w pamięci do momentu wywołania metody *ApplyUpdates*. W tym momencie aktualizacje zostaną przekształcone w instrukcje aktualizacji SQL i zostaną zastosowane w bazie danych. Jeśli nie wywołasz „ApplyUpdates”, baza danych nie zostanie zaktualizowana o lokalne zmiany. | |
| 61 | + | ||
| 62 | + | ## Pola klucza podstawowego | |
| 63 | + | ||
| 64 | + | Podczas aktualizowania rekordów *TSQLQuery* musi wiedzieć, które pola składają się na klucz podstawowy, którego można użyć do aktualizacji rekordu, i które pola należy zaktualizować: na podstawie tych informacji konstruuje polecenie SQL UPDATE, INSERT lub DELETE. | |
| 65 | + | ||
| 66 | + | Konstrukcja instrukcji SQL jest kontrolowana przez właściwości *UsePrimaryKeyAsKey* i *ProviderFlags*. | |
| 67 | + | ||
| 68 | + | Właściwość *ProviderFlags* to zestaw 3 flag: | |
| 69 | + | ||
| 70 | + | pfInkey | |
| 71 | + | To pole jest częścią klucza podstawowego | |
| 72 | + | ||
| 73 | + | pfInWhere | |
| 74 | + | To pole powinno być używane w klauzuli WHERE instrukcji SQL. | |
| 75 | + | ||
| 76 | + | pfInUpdate | |
| 77 | + | To pole powinno być zawarte podczas aktualizacji lub wstawiania rekordu. | |
| 78 | + | ||
| 79 | + | Domyślnie *ProviderFlags* ustawione jest zawsze na *pfInUpdate*. | |
| 80 | + | ||
| 81 | + | Jeśli Twoja tabela ma klucz podstawowy (jak opisano powyżej), wystarczy ustawić właściwość *UsePrimaryKeyAsKey* na *True* i wszystko zostanie dla ciebie zrobione. To ustawi flagę *pfInKey* dla pól klucza podstawowego. | |
| 82 | + | ||
| 83 | + | Jeśli tabela nie ma indeksu klucza podstawowego, ale zawiera pola, których można użyć do jednoznacznej identyfikacji rekordu, to możesz ustawić opcję *pfInKey* we właściwości *ProviderFlags* dla wszystkich pól, które jednoznacznie określają rekord. | |
| 84 | + | ||
| 85 | + | Następna właściwość *UpdateMode* określa, które dokładnie pola zostaną użyte w klauzuli WHERE: | |
| 86 | + | ||
| 87 | + | upWhereKeyOnly | |
| 88 | + | Gdy *TSQLQuery* musi utworzyć klauzulę WHERE dla aktualizacji, zbierze wszystkie pola, które mają flagę *pfInKey* we właściwości *ProviderFlags* i użyje wartości do utworzenia Klauzula WHERE, która jednoznacznie określa rekord do aktualizacji — zwykle jest to potrzebne tylko w przypadku instrukcji UPDATE lub DELETE. | |
| 89 | + | ||
| 90 | + | upWhereChanged | |
| 91 | + | Oprócz pól, które mają *pfInKey* we właściwości *ProviderFlags*, w klauzuli WHERE uwzględnione zostaną także wszystkie pola, które mają ustawione *pfInWhere* we właściwości *ProviderFlags* i które uległy zmianie. | |
| 92 | + | ||
| 93 | + | upWhereAll | |
| 94 | + | Oprócz pól, które mają *pfInKey* we właściwości *ProviderFlags*, w klauzuli WHERE uwzględnione zostaną także wszystkie pola, które mają ustawione *pfInWhere* we właściwości *ProviderFlags*. | |
| 95 | + | ||
| 96 | + | ## Kontrola aktualizacji | |
| 97 | + | ||
| 98 | + | Możliwe jest określenie, które pola powinny zostać zaktualizowane. Jak wspomniano powyżej, tylko pola, które mają właściwość *pfInUpdate* we właściwości *ProviderOptions* zostaną uwzględnione w instrukcjach SQL UPDATE lub INSERT. Domyślnie „pfInUpdate” jest zawsze zawarty we właściwości *ProviderOptions*. | |
| 99 | + | ||
| 100 | + | ## Dostosowywanie SQL w TSQLQuery | |
| 101 | + | ||
| 102 | + | Normalnie TSQLQuery użyje ogólnych instrukcji SQL opartych na właściwościach, które omówiono powyżej. Jednak ogólny kod SQL utworzony przez sqldb może nie być poprawny w danej sytuacji. TSQLQuery pozwala na dostosowanie instrukcji SQL używanych do różnych działań, aby działały najlepiej w Twojej sytuacji z bazą danych. W tym celu używa się właściwości *SQL*, *InsertSQL*, *UpdateSQL* i *DeleteSQL*. | |
| 103 | + | ||
| 104 | + | Wszystkie te właściwości są typu TStringList, lista ciągów, która akceptuje wiele wierszy SQL. Wszystkie cztery są wyposażone w edytor właściwości w IDE. W środowisku IDE wybierz właściwość i otwórz edytor, klikając przycisk z wielokropkiem. W tym edytorze ([[Database metadata|TSQLQuery narzędzie metadanych]]) możesz również wyszukać informacje z tabeli itp. | |
| 105 | + | ||
| 106 | + | W kodzie użyj na przykład `InsertSQL.Text` lub `InsertSQL.Add()`, aby ustawić lub dodać wiersze instrukcji SQL. Jedna instrukcja może obejmować kilka wierszy i kończyć się średnikiem. | |
| 107 | + | ||
| 108 | + | Ponadto wszystkie cztery właściwości akceptują parametry wyjaśnione poniżej. | |
| 109 | + | ||
| 110 | + | ### SQL - Podstawowe dostosowywanie SQL | |
| 111 | + | ||
| 112 | + | Właściwość SQL jest zwykle używana do pobierania danych z bazy danych. Ogólny kod SQL dla tej właściwości to `SELECT * FROM fpdev`, gdzie `fpdev` jest istniejącą tabelą w bazie danych. | |
| 113 | + | ||
| 114 | + | Zestaw danych zwrócony przez ogólną instrukcję SQL będzie dość szorstki. Jeśli pokażesz wynik w TDBGrid, kolejność rekordów może wydawać się losowa, kolejność kolumn może nie być taka, jak chcesz, a nazwy pól mogą być poprawne technicznie, ale nieprzyjazne dla użytkownika. Korzystając z dostosowanego języka SQL, możesz to poprawić. Dla tabeli o nazwie fpdev z kolumnami id, UserName i InstEmail, możesz zrobić coś takiego: | |
| 115 | + | ||
| 116 | + | ``` sql | |
| 117 | + | SELECT id AS 'ID', UserName AS 'User', InstEmail AS 'e-mail' FROM fpdev ORDER BY id; | |
| 118 | + | ``` | |
| 119 | + | ||
| 120 | + | Zestaw danych, który wynika z powyższego zapytania, wykorzystuje nazwy pól podane w zapytaniu (ID, Użytkownik i e-mail), kolejność kolumn podaną w zapytaniu, a rekordy są sortowane według ich id. | |
| 121 | + | ||
| 122 | + | ### InsertSQL, UpdateSQL i DeleteSQL - Podstawy użycia parametrów | |
| 123 | + | ||
| 124 | + | Kiedy przypiszesz zapytanie SELECT do właściwości **SQL** w SQLQuery, to SQLQuery wie, jak pobrać dane z bazy danych. Jednak w przypadku korzystania z kontrolek powiązanych z danymi, takich jak DBGrid, SQLQuery będzie również musiało mieć możliwość wstawiania, aktualizowania i usuwania wierszy z bazy danych na podstawie działań użytkownika. | |
| 125 | + | ||
| 126 | + | Aby przyspieszyć rozwój, SQLQuery może próbować wydedukować wymagane instrukcje SQL. Jeśli właściwość SQL istnieje, a właściwość **ParseSQL** ma wartość true (jest to wartość domyślna), SQLQuery spróbuje wygenerować te instrukcje, analizując właściwość **SQL**. SQLDB przechowuje te instrukcje we właściwościach „InsertSQL”, „UpdateSQL” i „DeleteSQL”. | |
| 127 | + | ||
| 128 | + | Jednak czasami wygenerowane instrukcje nie będą działać (np. przy wstawianiu do tabel z automatycznym przyrostem/autonumerowaniem kluczy podstawowych) lub będą bardzo wolne. W razie potrzeby można ręcznie przypisać zestawienia. | |
| 129 | + | ||
| 130 | + | Instrukcje we właściwościach *InsertSQL*, *UpdateSQL* i *DeleteSQL* akceptują parametry reprezentujące pola w zestawie danych. Obowiązują następujące zasady: | |
| 131 | + | ||
| 132 | + | - Nazwy parametrów muszą być dokładnie takie same jak nazwy pól używane w zestawie danych. Nazwy pól w zestawie danych mogą różnić się od nazw kolumn w tabeli, w zależności od użytej instrukcji select (patrz powyżej). | |
| 133 | + | - Podobnie jak parametry w innych zapytaniach SQLDB, nazwy parametrów muszą być poprzedzone dwukropkiem. | |
| 134 | + | - Aby parametry użyć w instrukcjach aktualizacji/usuwania, poprzedź nazwę pola zestawu danych przedrostkiem **OLD_** (**bezwzględnie wielkimi literami**, przynajmniej w Lazarus v. 1.0), aby uzyskać wartość rekordu przed jego edytowaniem zamiast nowej wartości. | |
| 135 | + | ||
| 136 | + | Jeśli masz tabelę o nazwie fpdev i kolumnach id, UserName i InstEmail, połączoną z zestawem danych z polami ID, User i e-mail (patrz przykład w instrukcji SELECT), możesz napisać to zapytanie **InsertSQL**: | |
| 137 | + | ||
| 138 | + | ``` sql | |
| 139 | + | INSERT INTO fpdev(id, UserName, InstEmail) VALUES(:ID,:User,:e-mail); | |
| 140 | + | ``` | |
| 141 | + | ||
| 142 | + | Ta instrukcja wstawi wartości `ID`, `User` i `e-mail` z bieżącego rekordu zbioru danych do odpowiednich pól tabeli `fpdev`. | |
| 143 | + | ||
| 144 | + | Ta przykładowa instrukcja jest w rzeczywistości mniej więcej tym, co sama baza danych SQLDB wygeneruje automatycznie. Podana instrukcja może skutkować błędami, gdy pole `id` jest polem automatycznego przyrostu w unikalnym kluczu. Różne bazy danych na różne sposoby rozwiązują ten problem. Na przykład poniższe działa dla MySQL. | |
| 145 | + | ||
| 146 | + | ``` sql | |
| 147 | + | INSERT INTO fpdev(id, UserName, InstEmail) VALUES(0,:User,:e-mail) | |
| 148 | + | ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(); | |
| 149 | + | ``` | |
| 150 | + | ||
| 151 | + | Powyższa instrukcja próbuje wstawić nowy rekord używając 0 (zero) dla kolumny `id`. Jeśli zero jest już używane jako klucz, to wykrywany jest duplikat i `id` jest aktualizowany tak, aby używał ostatnio wstawionego identyfikatora. Czyli, id o jeden przyrost wyższy niż ostatnio użyty. | |
| 152 | + | ||
| 153 | + | W przypadku Firebirda, jeśli emulujesz klucze autoinkrementacji [1](http://www.firebirdfaq.org/faq29/), powinno działać coś takiego: | |
| 154 | + | ||
| 155 | + | ``` sql | |
| 156 | + | INSERT INTO fpdev(UserName, InstEmail) VALUES(:User,:e-mail);( | |
| 157 | + | ``` | |
| 158 | + | ||
| 159 | + | Instrukcja wstawia wszystko poza kluczem podstawowym i pozwala Firebirdowi przed wyzwalaczem wstawiania użyć generatora/sekwencji do wstawienia wartości `id` dla Ciebie. | |
| 160 | + | ||
| 161 | + | W przypadku instrukcji `INSERT` możesz chcieć użyć bieżących wartości pól wybranego rekordu. W przypadku instrukcji `UPDATE` warto użyć wartości pól, które były przed edycją w klauzuli `WHERE`. Jak wspomniano wcześniej, wartości pól przed edycją muszą być zapisane jako nazwa pola poprzedzona **OLD_** (**bezwzględnie wielkimi literami**, przynajmniej w Lazarus v. 1.0). Weźmy na przykład to zapytanie: | |
| 162 | + | ||
| 163 | + | ``` sql | |
| 164 | + | UPDATE fpdev SET UserName=:User, InstEmail=:e-mail WHERE UserName=:OLD_User; | |
| 165 | + | ``` | |
| 166 | + | ||
| 167 | + | Powyższa instrukcja aktualizuje kolumny `UserName` i `InstEmail` wszystkich rekordów, w których `User` jest równy starej wartości `User`. | |
| 168 | + | ||
| 169 | + | Czytelnikowi pozostawiamy ćwiczenie, jak użyć bieżących wartości pól i starych wartości pól w instrukcjach DELETE. | |
| 170 | + | ||
| 171 | + | Zobacz także oficjalną dokumentację: | |
| 172 | + | ||
| 173 | + | - [dokumentacja InsertSQL](http://www.freepascal.org/docs-html/fcl/sqldb/tsqlquery.insertsql.html) | |
| 174 | + | - [dokumentacja UpdateSQL](http://www.freepascal.org/docs-html/fcl/sqldb/tsqlquery.updatesql.html) | |
| 175 | + | - [dokumentacja DeleteSQL](http://www.freepascal.org/docs-html/fcl/sqldb/tsqlquery.deletesql.html) | |
| 176 | + | ||
| 177 | + | ### Parametry w TSQLQuery.SQL | |
| 178 | + | ||
| 179 | + | W większości sytuacji właściwość SQL TSQLQuery będzie zawierać instrukcję SELECT, która najczęściej nie wymaga parametrów. Może je jednak zawierać. Pozwala to na bardzo łatwy i skuteczny sposób filtrowania Twoich rekordów. | |
| 180 | + | ||
| 181 | + | Parametry mają następujące zalety: | |
| 182 | + | ||
| 183 | + | - nie ma potrzeby formatowania danych jako tekst SQL, data itp. (tzn. nie trzeba pamiętać, jak formatować datę dla MySQL, która może różnić się od implementacji Firebird; nie ma potrzeby ucieczki danych tekstowych, takich jak *O'Malley's*SQL Przerażenie"'' | |
| 184 | + | - prawdopodobnie zwiększona wydajność | |
| 185 | + | - ochrona przed atakami typu SQL injection | |
| 186 | + | ||
| 187 | + | Użycie parametrów może pomóc w wydajności bazy danych. Większość baz danych obsługuje gotowe zestawienia, co oznacza, że zestawienie jest przygotowywane i buforowane w bazie danych. Przygotowana instrukcja może być użyta więcej niż jeden raz i nie wymaga parsowania i planowania zapytań za każdym razem, gdy jest używana, tylko parametry są zmieniane przy każdym użyciu. W sytuacjach, w których to samo stwierdzenie jest używane wiele razy (gdy różnią się tylko wartości parametrów), przygotowane zestawienia mogą znacznie poprawić wydajność. Dodatkowo ataki typu SQL injection można złagodzić za pomocą parametrów. | |
| 188 | + | ||
| 189 | + | Właściwości *InsertSQL*, *UpdateSQL* i *DeleteSQL* mają wstępnie zdefiniowane parametry dla bieżących i starych wartości pól. Jednak właściwość *SQL* nie. Ale możesz tworzyć własne parametry we właściwości *Params*. | |
| 190 | + | ||
| 191 | + | #### Przykład zapytania SELECT | |
| 192 | + | ||
| 193 | + | Ten przykład pokazuje, jak wybrać dane za pomocą parametrów. Pokazuje również użycie aliasów (... AS ...) w SQL. | |
| 194 | + | ||
| 195 | + | ``` pascal | |
| 196 | + | sql_temp.sql.text := 'SELECT id AS ''ID'', UserName AS ''User'', InstEmail AS ''e-mail'' FROM fpdev WHERE InstEmail=:emailsearch;' | |
| 197 | + | ... | |
| 198 | + | //Spowoduje to utworzenie parametru o nazwie emailsearch. | |
| 199 | + | ||
| 200 | + | //Jeśli chcemy, możemy jawnie ustawić, jaki to jest typ parametry... co może być też konieczne, gdy FPC odgadnie źle: | |
| 201 | + | //sql_temp.params.parambyname('emailsearch').datatype:=ftWideString | |
| 202 | + | ||
| 203 | + | //Możemy teraz uzupełnić wartość parametru: | |
| 204 | + | sql_temp.params.parambyname('emailsearch').asstring := 'mvancanneyt@freepascal.org'; | |
| 205 | + | ... | |
| 206 | + | //Następnie użyj swojego zwykłego sposobu na pobieranie danych, | |
| 207 | + | //opcjonalnie zmień wartość parametru i uruchom go ponownie | |
| 208 | + | ``` | |
| 209 | + | ||
| 210 | + | #### Przykład zapytania INSERT | |
| 211 | + | ||
| 212 | + | Ten przykład pokazuje, jak wstawić nowy rekord do tabeli za pomocą parametrów: | |
| 213 | + | ||
| 214 | + | ``` pascal | |
| 215 | + | sql_temp.sql.text := 'insert into PRODUCTS (ITEMNR,DESCRIPTION) values (:OURITEMNR,:OURDESCRIPTION)' | |
| 216 | + | ... | |
| 217 | + | sql_temp.Params.ParamByName('OURITEMNR').AsString := 'XXXX'; | |
| 218 | + | sql_temp.Params.ParamByName('OURDESCRIPTION').AsString := 'description'; | |
| 219 | + | sql_temp.ExecSQL; | |
| 220 | + | SQLTransaction1.Commit; //lub ewentualnie CommitRetaining, w zależności od konfiguracji aplikacji | |
| 221 | + | ``` | |
| 222 | + | ||
| 223 | + | Innym sposobem na zrobienie tego jest coś takiego: | |
| 224 | + | ||
| 225 | + | ``` pascal | |
| 226 | + | tsqlquery1.appendrecord(['XXXX', 'description']) | |
| 227 | + | tsqltransaction1.commit; //lub CommitRetaining | |
| 228 | + | ``` | |
| 229 | + | ||
| 230 | + | ### Zapytanie z funkcją Format | |
| 231 | + | ||
| 232 | + | Korzystanie z zapytań parametrycznych jest preferowanym podejściem, ale w niektórych sytuacjach alternatywą może być funkcja Format. (patrz ostrzeżenie poniżej). Przykładowo, parametry nie mogą być używane podczas wykonywania instrukcji za pomocą procedury ExecuteDirect (*oczywiście można równie dobrze użyć zapytania, aby uruchomić daną instrukcję SQL*). Wtedy może się przydać to: | |
| 233 | + | ||
| 234 | + | ``` pascal | |
| 235 | + | procedure InsertRecord | |
| 236 | + | var | |
| 237 | + | aSQLText: string; | |
| 238 | + | aSQLCommand: string; | |
| 239 | + | begin | |
| 240 | + | aSQLText:= 'INSERT INTO products(item_no, description) VALUES(%d, %s)'; | |
| 241 | + | aSQLCommand:= Format(aSQLText, [strtoint(Edit1.Text), Edit2.Text]); | |
| 242 | + | aConnection.ExecuteDirect(aSQLCommand); | |
| 243 | + | aTransaction.Commit; | |
| 244 | + | end; | |
| 245 | + | ``` | |
| 246 | + | ||
| 247 | + | Wartości zmiennych mogą się zmieniać, a wartości zapytań będą się zmieniać wraz z nimi, tak jak w przypadku zapytań parametrycznych. | |
| 248 | + | ||
| 249 | + | Parametr %d jest używany dla liczb całkowitych, %s dla łańcuchów; itp. Szczegółowe informacje można znaleźć w dokumentacji funkcji Format. | |
| 250 | + | ||
| 251 | + | > **Warning:** Pamiętaj, że przy użyciu tej techniki możesz napotkać problemy z tekstem zawierającym ' i daty! | |
| 252 | + | ||
| 253 | + | ## Uruchamianie własnego SQL i uzyskiwanie metadanych | |
| 254 | + | ||
| 255 | + | Jeśli chcesz po prostu sprawdzić niektóre instrukcje SQL, rozwiązać problemy lub pobrać metadane (np. listę tabel) z bazy danych, możesz to zrobić z poziomu IDE. W swoim programie, z T*Connection, transakcją, obiektem Query itp. ustawionym w czasie projektowania, przejdź do właściwości SQL obiektu zapytania, a następnie kliknij przycisk ... | |
| 256 | + | ||
| 257 | + | Zobaczysz okno z kodem SQL i możesz uruchomić kilka instrukcji, takich jak | |
| 258 | + | ||
| 259 | + | ``` sql | |
| 260 | + | SELECT * FROM EMPLOYEE | |
| 261 | + | ``` | |
| 262 | + | ||
| 263 | + | poprzez naciśniecie ikony play: | |
| 264 | + | ||
| 265 | + |  | |
| 266 | + | ||
| 267 | + | Możesz również uzyskać metadane: nazwy tabel, nazwy kolumn itp. (jeśli złącze sqldb to obsługuje, ale większość z nich obecnie to robi): | |
| 268 | + | ||
| 269 | + |  | |
| 270 | + | ||
| 271 | + | (Zobacz także: [[Database metadata|Database metadata#Lazarus Narzedzie metadanych TSQLQuery]]) | |
| 272 | + | ||
| 273 | + | ## Rozwiązywanie problemów | |
| 274 | + | ||
| 275 | + | ### Logowanie, rejestrowanie | |
| 276 | + | ||
| 277 | + | Zobacz tutaj: [[SqlDBHowto/pl|Rozwiązywanie problemów: rejestrowanie TSQLConnection]], aby uzyskać więcej informacji. | |
| 278 | + | ||
| 279 | + | ### Słaba wydajność | |
| 280 | + | ||
| 281 | + | - Upewnij się, że zapytania do bazy danych są zoptymalizowane (użyj odpowiednich indeksów itp.). Użyj do tego swoich narzędzi bazodanowych (np. zapewnienie planów zapytań). | |
| 282 | + | - Zobacz #Błędy braku pamięci poniżej, aby poznać możliwe ulepszenia wydajności podczas przechodzenia do przodu przez SQLQuery. | |
| 283 | + | ||
| 284 | + | ### Komunikaty o błędach | |
| 285 | + | ||
| 286 | + | ### Błędy braku pamięci | |
| 287 | + | ||
| 288 | + | TSQLQuery jest potomkiem BufDataset, zestawu danych, który buforuje otrzymane dane w pamięci. Jeśli pobierzesz wiele rekordów (np. podczas przeglądania ich w pętli w celu wyeksportowania), pamięć sterty może się zapełnić (z rekordami, przez które już przeszłaś pętlę) i wyeliminujesz błędy pamięci. | |
| 289 | + | ||
| 290 | + | Chociaż ta sytuacja uległa poprawie w wersji rozwojowej FPC, obejściem jest wydanie do BufDataset komendy odrzucenia rekordów, które już zostały przeczytane, poprzez ustawienie właściwości UniDirectional na true przed otwarciem zapytania: | |
| 291 | + | ||
| 292 | + | ``` pascal | |
| 293 | + | MySQLQuery.UniDirectional:=True; | |
| 294 | + | ``` | |
| 295 | + | ||
| 296 | + | Może to również poprawić wydajność. | |
| 297 | + | ||
| 298 | + | ### Zbiór danych DataSet jest tylko do odczytu | |
| 299 | + | ||
| 300 | + | Może się to zdarzyć, jeśli określisz zapytanie, o którym Ty wiesz, że można zaktualizować dane, ale FPC o tym nie wie. | |
| 301 | + | ||
| 302 | + | Przykład: | |
| 303 | + | ||
| 304 | + | ``` sql | |
| 305 | + | SELECT p.dob, p.surname, p.sex FROM people p; | |
| 306 | + | ``` | |
| 307 | + | ||
| 308 | + | Parser SQL w FPC jest dość uproszczony i kiedy znajdzie przecinek lub spację w części FROM, bierze pod uwagę wiele tabel i ustawia zestaw danych tylko do odczytu. Dla bezpieczeństwa, aliasowanie tabel nie jest zwykle wykonywane, gdy w grę wchodzi tylko jedna tabela. Rozwiązanie: przepisz zapytanie lub określ własne zapytania `InsertSQL`, `UpdateSQL` i `DeleteSQL`. | |
| 309 | + | ||
| 310 | + | --- | |
| 311 | + | *From the Free Pascal wiki, page "Working With TSQLQuery/pl", as it stood on 2022-10-02 after a change by Slawek, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).* |
