Vienkāršs SQL Select teikums

SELECT teikums

Pārējos rakstus var lasīt SQL pamatos.

SQL Select teikums ir pats izplatītākais SQL teikums un veids kā dabūt ārā datus no datubāzes jūsu programmā, klienta rīkā vai vienalga kur citur. Praktiski visi dati, kur apakšā dziļumā sēž datubāze un jums kaut ko rāda uz ekrāna no šīs datubāzes, ir iegūti izmantojot tādu vai citādu Select teikumu.

Sākumā nedaudz teorija un pāris termini no relāciju algebras.
Iedomājamies tabulu datubāzē, kuru grafiski var attēlot šādi:

       
       
       
       


Tādā gadījumā Projekcija (Projection) ir kolonu izvēle, kuras mums ir nepieciešamas no tabulas.
Grafiski tas izskatās šādi:

       
       
       
       


Atlase (Selection) ir ierakstu izvēle, kuri mums ir nepieciešami no tabulas.
Grafiski tas izskatās šādi:

       
       
       
       

Protams, vispārīgā gadījumā vienā vaicājumā var izmantot gan Projekciju, gan Atlasi, gan citas operācijas, tas viss ir atkarīgs no prasībām un konkrētās nepieciešamības.
Vienkārša Select teikuma (šis ir mans absolūti brīvs un voluntārs termins, tas nav nekas tāds vispārpieņemts) galvenās sastāvdaļas ir šādas:

SELECT <atlases saraksts>
FROM <tabula>
WHERE <nosacījumi>
GROUP BY <grupēšanas izteiksme>
HAVING <nosacījumi>
ORDER BY <kārtošanas izteiksme>

Tagad sīkāk par katru teikuma sadaļu atsevišķi.

SELECT <atlases saraksts>

Bez šī atslēgas vārda nekas nenotiek. Tiesa gan tas var arī nebūt pirmais SELECT teikumā, jo SELECT teikums vispārīgi sākas ar vaicājuma sadalīšanas (query factoring) jeb tabulas kopējās izteiksmes (common table expression) klauzu, t.i. atslēgvārdu WITH. Atlases saraksts nosaka izvēlētās kolonas un atbilst Projekcijai, kas paskaidrota un vizuāli redzama augstāk.

  • <atlases sarakstā> raksta konstantes, izteiksmes un pats galvenais – atlasāmās kolonas, kuras atdala ar komatu.
  • DISTINCT – izmantojot atslēgas vārdu DISTINCT var atlasīt tikai unikālās vērtības.
  • * – Zvaigznītes “*” simbolu var lietot, kā aizstājēju visām kolonām.
  • kolonām var piešķirt citu vārdu izmantojot atslēgvārdu AS vai vienkārši jauno vārdu rakstot aiz pauzes.

FROM <tabula>

Šeit jau sākās pirmās datubāzu atšķirības. Dažās datubāzēs (piemēram, Oracle) šī klauza ir obligāta, dažās (piemēram, MSSQL), ja tiek atlasītas tikai konstantes un izteiksmes, bez tabulu kolonu argumentiem, tad bez šīs klauzas var iztikt, piemēram, vienkārši rakstot
SELECT ‘konstante’

  • <tabula> – raksta tabulas nosaukumu. Tabulai var piešķirt citu nosaukumu gluži tāpat kā kolonai, bet, piemēram, Oraclē AS atslēgas vārds nedrīkst būt.

Daži vaicājumu piemēri. Tabulas definīcija un tās dati ir šādi:

CREATE TABLE personas (
prs_personas_kods VARCHAR2(11) NOT NULL PRIMARY KEY,
prs_vards VARCHAR2(40),
prs_uzvards VARCHAR2(40));
INSERT INTO personas VALUES ('11111112345', 'JĀNIS', 'BĒRZIŅŠ');
INSERT INTO personas VALUES ('12121212345', 'PĒTERIS', 'SŪNIŅŠ');
INSERT INTO personas VALUES ('13131312345', 'RŪDIS', 'BĒRZIŅŠ');
COMMIT;
Piemērs 1. Atlasa konstanti, vārda garumu un vārdu no tabulas.
SQL> SELECT 1, length(prs_vards), prs_vards
  2  FROM personas;
         1 LENGTH(PRS_VARDS) PRS_VARDS
---------- ----------------- ---------------
         1                 5 JĀNIS
         1                 7 PĒTERIS
         1                 5 RŪDIS
Piemērs 2. Atlasa unikālos uzvārdus no tabulas.
SQL> SELECT DISTINCT prs_uzvards FROM personas;
PRS_UZVARDS
----------------------------------------
SŪNIŅŠ
BĒRZIŅŠ
Piemērs 3. Atlasa konstanti un visus laukus no tabulas izmantojot aizstājējvārdu tabulai un zvaigznītes simbolu.
SQL> SELECT 1, p.* FROM personas p;
         1 PRS_PERSONA PRS_VARDS          PRS_UZVARDS
---------- ----------- ------------------ -------------
         1 11111112345 JĀNIS              BĒRZIŅŠ
         1 12121212345 PĒTERIS            SŪNIŅŠ
         1 13131312345 RŪDIS              BĒRZIŅŠ
Piemērs 4. Atlasa personas kodu un uzvārdu no tabulas izmantojot kolonu aizstājējvārdus ar un bez atslēgvārda AS.
SQL> SELECT prs_personas_kods AS pk, prs_uzvards uzvārds
  2  FROM personas;
PK          UZVĀRDS
----------- ----------------------------------------
11111112345 BĒRZIŅŠ
12121212345 SŪNIŅŠ
13131312345 BĒRZIŅŠ

WHERE <nosacījumi>

Šī klauza, kā jau to var redzēt no iepriekšējiem piemēriem, ir neobligāta. Tās uzdevums ir ierobežot atlasāmo datu kopu – tiek atlasīti tikai tie dati, kas atbilst WHERE klauzas nosacījumiem, t.i, kur nosacījumu izpildes rezultāts ir Patiess (True), nevis Aplams (False) vai Null. Ja WHERE klauzas nav, tad atlasa visus ierakstus no tabulas, kas ir minēta FROM klauzā. Nosacījumus var kombinēt izmantojot loģiskos operatorus AND, OR, NOT. Šī klauza nodrošina Atlases implementēšanu, kas paskaidrota un vizuāli redzama augstāk.

Daži piemēri:

Piemērs 5. Atlasa visas kolonas, kam kolona vārds ir JĀNIS.
SQL> SELECT * FROM personas
  2  WHERE prs_vards = 'JĀNIS';
PRS_PERSONA PRS_VARDS               PRS_UZVARDS
----------- ----------------------- -----------------------------------
11111112345 JĀNIS                   BĒRZIŅŠ
Piemērs 6. Atlasa vārdu no tabulas, kur vārda garums ir 5 simboli.
SQL> SELECT prs_vards FROM personas
 2  WHERE length(prs_vards) = 5;
PRS_VARDS
------------------------------------
JĀNIS
RŪDIS

GROUP BY <grupēšanas izteiksme>

Ja tiek izmantota šī klauza, tad vaicājums atgriež datus, kas ir grupēti pa kādām kolonām vai izteiksmēm no šīm kolonām. Parasti līdz ar grupētām kolonām tiek izmantota viena vai vairākas grupēšanas funkcijas. Ja kāda no grupēšanā izmantotajām kolonām ir NULL, tad tā tiek uzskatīta kā atsevišķa rindiņa un visas šādas kolonas tiek uzskatītas kā līdzvērtīgas, t.i., grupētas kopā.
Biežāk izmantojamās grupēšanas funkcijas ir:

  • count(izteiksme) – ierakstu skaits grupā, kur izteiksme atgriež NE NULL rezultātu – parasti vienkāršai saskaitīšanai izmanto count(*).
  • sum(izteiksme) – summa grupai.
  • min(izteiksme) – minimālā vērtība grupā.
  • max(izteiksme) – maksimālā vērtība grupā.
  • avg(izteiksme) – vidējā vērtība grupā.

Daži piemēri:

Piemērs 7. Atlasa tabulas ierakstu skaitu.
SQL> SELECT count(*) FROM personas;
COUNT(*)
----------
         3
Piemērs 8. Atlasa uzvārdus un to izmantošanas reižu skaitu tabulā.
SQL> SELECT count(*), prs_uzvards
  2  FROM personas
  3  GROUP BY prs_uzvards;
COUNT(*)   PRS_UZVARDS
---------- ---------------------------------
         1 SŪNIŅŠ
         2 BĒRZIŅŠ
Piemērs 9. Atlasa visu vārdu garumu summu.
SQL> SELECT sum(length(prs_vards)) FROM personas;
SUM(LENGTH(PRS_VARDS))
----------------------
                    17

HAVING <nosacījumi>

Lai uzliktu nosacījumus tālāk uz jau sagrupētajiem datiem, var izmantot HAVING klauzu. Tā tiek pielietota vaicājumam pēc GROUP BY klauzas izpildes. Ja šī klauza netiek lietota, tad vaicājums atgriež visus grupētos datus, kas ir iegūti GROUP BY rezultātā. Gluži tāpat kā WHERE klauzai arī šeit, protams, nosacījumus ir iespējams kombinēt izmantojot loģiskos operatorus.
Piemērs:

Piemērs 10. Atlasa uzvārdus un to izmantošanas reižu skaitu tabulā, ja to izmantošanas reižu skaits ir lielāks nekā 1.
SQL> SELECT count(*), prs_uzvards
  2  FROM personas
  3  GROUP BY prs_uzvards
  4  HAVING count(*) > 1
  5  /
COUNT(*)   PRS_UZVARDS
---------- ----------------------
         2 BĒRZIŅŠ

ORDER BY <kārtošanas izteiksme>

Ar šo izteiksmi, kā to vēsta jau pats nosaukums, dati tiek sakārtoti noteiktā secībā.

  • <kārtošanas izteiksme> var sastāvēt no vienas vai vairākām gan atlasītajām, gan neatlasītājām kolonām.
  • Atlasītās kolonas var aizvietot arī ar to kārtas numuriem atlases sarakstā, tomēr ja kolonu skaits ir liels, tad ir jāpārdomā vai vaicājums tādā gadījumā būs lasāms un saprotams.
  • Katru atsevišķo izteiksmi vai kolonu var kārtot augošā (noklusētais variants) vai dilstošā secībā. To norāda ar atslēgas vārdu ASC (augošā secībā) vai DESC (dilstošā secībā) aiz katras konkrētās izteiksmes. Kā jau teikts ASC var nerakstīt.

Daži piemēri.

Piemērs 11. Atlasa visas kolonas un ierakstus no tabulas tos sakārtojot pēc uzvārda un vārda.
SQL> SELECT * FROM personas
  2  ORDER BY prs_uzvards, prs_vards;
PRS_PERSONA PRS_VARDS                                PRS_UZVARDS
----------- ---------------------------------------- -------------
11111112345 JĀNIS                                    BĒRZIŅŠ
13131312345 RŪDIS                                    BĒRZIŅŠ
12121212345 PĒTERIS                                  SŪNIŅŠ
Piemērs 12. Atlasa personas kodu no tabulas sākārtojot pēc atlases sarakstā neesošām kolonām uzvārda dilstošā secība un vārda augošā secībā.
SQL> SELECT prs_personas_kods pk FROM personas
  2  ORDER BY prs_uzvards desc, prs_vards;
PK
-----------
12121212345
11111112345
13131312345

Dažas piezīmes ar uzturamību, ātrdarbību un funkcionalitāti

  • Izvēlieties savas SQL objektu nosaukšanas un SQL teikumu rakstīšanas vadlīnijas. Un pielietojiet tās. Ir ļoti grūti saprast SQL teikumus, kas ir rakstīti haotiski, tiek dinamiski kaut kādā haotiskā veidā uzkonstruēti kodā vai paslēpti tajā kā teksta mainīgie, kas nekādi neizceļas uz pārējo mainīgo vērtību piešķiršanas fona.
  • Ar uzmanību jālieto *. Laika gaitā tabulu struktūra mēdz mainīties un jāsaprot, ka pieliekot klāt kolonu, * attēlos arī to. No ātrdarbības viedokļa jācenšas atlasīt tikai tās kolonas, kas patiesi ir nepieciešams, nevis visas, kaut gan tā it kā ir ērtāk.
  • DISTINCT jālieto tikai tad, ja patiešām tas ir nepieciešams. Unikālo vērtību atrašana prasa liekus resursus, laiku un maldina uzturētājus, ja patiesībā visas vērtības jau tāpat ir unikālas.
  • Kolonām vai tabulām piešķirot aizstājvārdu (alias) arī būtu jāseko kaut kādām saprātīgām vadlīnijām, jo tabulas aizstājot ar a, b, c un kolonas ar col1, col2 rezultātā var iegūt absolūti nelasāmu SQL teikumu.
  • Rakstot WHERE klauzu, vienmēr jādomā par potenciālo ātrdarbību, jo tā ir primārā vieta, kas iespaidos jūsu vaicājuma izpildes ātrumu. Vai jūsu vaicājums vispār atlasa to, ko vajag? Vai jūsu vaicājums vienmēr skatīs cauri visu tabulu? Vai uz atlases kritērijos biežāk izmantotajām kolonām ir indeksi? Vai atlases nosacījumi ir tādi, ka indeksus ir iespējams izmantot? Piemēram, datu tipu (ne)sakritība; daži salīdzināšanas operatori (<>, =>, =<); LIKE ‘%teksta fragments%’; kritēriji nevis uz kolonām pa tiešo, bet izmantojot funkcijas ir tikai dažas no šaubīgajām lietām.
  • Jāsaprot, ka GROUP BY, lai gan parasti atgriež relatīvi mazu ierakstu skaitu, vairumā gadījumu skanē cauri visu tabulu vai vismaz lielu daļu no tās (atbilstoši WHERE klauzas nosacījumiem, protams). Attiecīgi jāsaprot, ka, lai iegūtu skaitu, summu vai jebko tamlīdzīgu, VISI atbilstošie ieraksti ir arī jāatrod un jāizpilda prasītā grupēšana funkcija.
  • Ja dati ir nepieciešami noteiktā kārtībā, tad vienmēr ir jālieto ORDER BY klauza. SQL standarts nosaka, ka bez šīs klauzas atgrieztā kopa ir sakārtojumā, kas ir implementācijas specifisks. Tas nozīmē, ka sakārtojums ir patvaļīgs un piedevām var mainīties no vienas un tās pašas datubāzes versijas uz versiju. Piemēram Oracle negarantē nekādu sakārtojumu bez ORDER BY klauzas un izpildot vienreiz vaicājumu tas var būt vienā sakārtojumā, bet nākošajā reizē pavisam citā sakārtojumā.

Tālākā lasāmviela

Pilna SELECT sintakses dokumentācija:

4 Responses to Vienkāršs SQL Select teikums

  1. Janekuss says:

    Kas domāts ar šo: “Unikālo vērtību atrašana prasa liekus resursus, laiku un maldina uzturētājus, ja patiesībā visas vērtības jau tāpat ir unikālas.” ?

  2. Gints Plivna says:

    >prasa liekus resursus un laiku
    Te ir pāris lietas, ko ir vērts atcerēties.
    1. Pieņemsim, ka mums ir saraksts ar 1000 ierakstiem. Ja mēs vienkārši gribam attēlot šos ierakstus, tad tiklīdz kā db atrod pirmo ierakstu tā db var uzreiz to sūtīt prom uz klientu (patiesība jau nu gan parasti klienta programma pieprasa pa vairākiem ierakstiem reizē, jo tā dzenāties pa tiklu 1000 reizes vienādi otrādi ir ļoti neefektīvi), lai tas ar šo ierakstu kaut ko dara. Ja mēs esam vaicājumā pieprasījuši unikālās vērtības, tādā gadījumā vispirms vismaz Oraclē un esmu pārliecināts ka arī vismaz dažās citās db tiek nolasīti dati, tad veic unikālo vērtību atrašanu un tās laikā tika sāk dot ārā ierakstus. Līdz ar to pirmkārt paiet ilgāks laiks kopš mēs sākam ierakstus dabūt.
    2. Padomā kā būtu, ja no grāmatas vienkārši ir jānoraksta 1000 vārdu vai arī pirms tam jāpārliecinās, ka vārds vēl ne reizi nav bijis uzrakstīts?
    Ir vairāki veidi kā tehniski dabūt no ierakstu kopas ārā tikai unikālos ierakstus, piemēram, ierakstus vispirms sakārtojot un tad atlasot tikai unikālās vērtības vai arī lietojot hešingu. Abi šie veidi prasa laiku, noslogo procesoru un diskus (ja datu kopa nesaiet atmiņā). Ja mēs zinām, ka datu kopā ir, piemēram, primārā atslēga un katrs ieraksts ir vienu reizi vai arī tajā ir kāds unikāls kārtas numurs vai kaut kas tamlīdzīgs tad DISTINCT dara darbu, kas ir pilnīgi lieks un aizņem resursus, ko kāds cits iespējams būtu izlietojis lietderīgāk.
    >maldina uzturētājus
    DISTINCT vaicājumos norāda, ka izejas kopā dati var būt neunikāli. Man personīgi kaut ko tādu redzot tūlīt rodas jautājums – kāpēc? Jo sevišķi, ja tā ir parasta tabulu kombinēšana (join) vai arī kolonas no vienas tabulas ieskaitot tādas, kas izskatās pēc primārās atslēgas. Un jautājumam ir pamats, jo normalizētā datu modelī DISTINCT nav pārāk bieža operācija, savukārt, ja tas tiek izmantots katrā otrajā vaicājumā, tad rodas šaubas vai datu modelis ir OK un vai tam nav potenciālas problēmas. Kopsavilkumā – DISTINCT ir normāla operācija tāpāt kā daudzas citas, bet to ir jālieto tad un tikai tad, kad tā patiesi ir nepieciešama, nevis tā kā dažkārt ir nācies redzēt – drošības pēc piemetam klāt, ja nu kas…

  3. andrisp says:

    “Kolonām vai tabulām piešķirot aizstājvārdu (alias) arī būtu jāseko kaut kādām saprātīgām vadlīnijām, jo tabulas aizstājot ar a, b, c un kolonas ar col1, col2 rezultātā var iegūt absolūti nelasāmu SQL teikumu.”

    Attiecībā tieši uz tabulu aliasiem. Man tieši liekas daudz pārskatāmāk, ja aliasus definē pēc iespējas īsākus. Kaut gan nevis vienkārši alfabētiski (a, b, c, …) bet gan izvēloties attiecīgāku burtu, tas ir, piemēram, ja man ir products tabula ar speciālu tabulu attēliem images, tad būs “p” un “i”. Nu kaut kā tā. Ja, piemēram, būtu tabula prices, tad to es sauktu “r” vai “pr”.

    PS. To “Piemēri ir balstīti uz šādu tabulu un datiem.” varbūt vajadzētu likt raksta sākumā. Savādāk cilvēks iziet cauri visam rakstam, pēta kverijus, un tikai beigās atklāj, ka viņš taču arī viegli viņus varēja izmēģināt, bet nu jau raksts izlasīts, otreiz negribas.🙂

  4. Gints Plivna says:

    >Attiecībā tieši uz tabulu aliasiem
    Nu Tevis izstāstītā metode jau zināmā mērā ir vadlīnijas, varbūt neformalizētas, bet tomēr. Tas, kas man personīgi ļoti nepatīk, ka cilvēki rīkojas haotiski un vienā vaicājumā tabulu aliaso ar vienu, otrā ar citu aliasu un attiecīgi veidojas bardaks. Pie tam ļoti īsiem alisaiem ir problēma, ja tiek kombinētas daudzas tabulas vienā vaicājumā, tad jau nākas galvā paturēt šīs daudzās attiecības un, ja tās neliekas pietiekami dabiskas, tad tas ir papildus slogs🙂
    >PS. To “Piemēri ir balstīti uz šādu tabulu un datiem.” varbūt vajadzētu likt
    >raksta sākumā
    Nu it kā jau tur bija pieminēts, ka tabula un dati ir beigās pat ar visu linku, bet OK pierunāji, iespējams, ka tas nebija tomēr pietiekami labi pamanāms🙂

Komentēt

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Mainīt )

Twitter picture

You are commenting using your Twitter account. Log Out / Mainīt )

Facebook photo

You are commenting using your Facebook account. Log Out / Mainīt )

Google+ photo

You are commenting using your Google+ account. Log Out / Mainīt )

Connecting to %s

%d bloggers like this: