SQL-kielen perusteet
© Jouni Huotari & Tapani Äijänen
1999-2006, viimeisin päivitys 12.9.2006
Kalvot perustuvat osin Ari Hovin SQL-oppaaseen (Docendo 2004)

1. Johdanto
Huom. Relaatiomalli ym. tietokantojen perusteet on esitetty erillisillä kalvoilla

SQL - Structured Query Language
SQL on tietokantojen käsittelyyn kehitetty kieli
Yleisimmät kielellä hoidettavat toiminnot:
Tietokannan rakenteen määrittely ja muuttaminen
Kyselyt tietokantaan ja laskenta tietokannan datalla
Tietojen ylläpito: lisäykset, muutokset ja poistot
Valtuuksien käsittely
Tapahtumankäsittelyn ohjaaminen
Lisäksi SQL:n käyttö ohjelmoinnissa
”Upotettu” SQL; SQL:n käyttö muiden kielien sisältä
API-rajapinnat ohjelmointikieliin

SQL
SQL on luonteeltaan ei-proseduraalinen kieli, jossa kerrotaan mitä halutaan tehdä (ei miten)
SQL perustuu relaatioalgebraan ja joukko-oppiin
SQL:stä useita versioita, mm. SQL-92 eli SQL2, SQL'99 eli SQL3 ja SQL:2003
Kielestä on eri valmistajilla toisistaan poikkeavia versioita (murteita)
SQL-kieltä voidaan käyttää useissa SQL-tuotteissa vuorovaikutteisesti antamalla SQL-käskyjä omaan ikkunaan, jolloin tulokset saadaan välittömästi (toiseen ikkunaan)

SQL-kielen historiaa
Alun perin SEQUEL (Structured English QUEry Language)
1. versio kehitettiin IBM:n tutkimuskeskuksessa 1970-luvulla (E.F. Coddin relaatiomalliin pohjautuen)
1. kaupallinen versio esiteltiin v. 1979 (Oracle)
SQL:n ANSI-standardi julkistettiin v. 1986
1989 lisättiin viite-eheysmääritykset
1992 liitossyntaksi, tapahtumanhallinta ym.
1999 mm. herättimet, talletetut proseduurit ja oliolaajennuksia + CLI (Call Level Interface)
2003 lisää olio-ominaisuuksia, XML, SQL/OLB ym.

Näissä kalvoissa esiintyvät SQL-käskyt
Noudattavat pääosin SQL2-standardia
Suurin osa on testattu Oraclella, OCELOTilla ja MS Accessilla; näistä vain OCELOT on täysin SQL-standardin (SQL2 ja osin SQL3) mukainen
Kalvoissa on mainittu, jos käskystä on jokin standardista poikkeava tuotekohtainen ratkaisu
Rakenne (käskyjen esitysjärjestys) on Ari Hovin kirjaa mukaileva

DDL ja DML
Data Definition Language (DDL): tietokannan rakenteen määrittely
Perus-SQL:ssä CREATE, ALTER ja DROP TABLE, CREATE ja DROP VIEW, CREATE ja DROP INDEX
Käyttökelpoisia esimerkiksi silloin kun on tarve luoda uudestaan taulut ja sarakkeet
Lisäksi mm. auktorisointikäskyt (GRANT ja REVOKE)
Data Manipulation Language (DML): tietokannan käsittely
Kyselyihin SELECT, koostefunktiot (mm. SUM ja COUNT) ym.
Tietojen ylläpitoon UPDATE, DELETE ja INSERT
Muutosten vahvistus ja peruutus (COMMIT ja ROLLBACK)
Lisäksi mm. Oraclessa on ohjauskäskyt transaktioille, sessiolle ja järjestelmälle, esim. ANALYZE, AUDIT ja COMMENT

SQL ohjelmoinnissa
”Upotettu” SQL: SQL-käskyt muiden kielien sisältä
SQL-käskyt voidaan laittaa ohjelmiin sellaisenaan
ohjelma linkitetään relaatiokantaan API-rajapinnoilla (Application Programming Interface), esim. ODBC ja JDBC
Dynaaminen SQL: (jonkin muuttujan arvoksi sijoitettu) SQL-käsky käännetään ja suoritetaan ajoaikana

2. Peruskyselyt
SELECT-käskyn eri muodot

SELECT-käsky
SQL-kielen keskeinen toiminto on kyselyiden tekeminen tietokantaan
Kyselyissä SQL-kielen perusrakenne käsittää kolme avainsanaa, joista SELECT ja FROM ovat pakollisia:
SELECT <attribuuttilista> valitsee listan mukaiset sarakkeet (attribuutit) kyselyyn
FROM <taululista> määrittelee haettavat taulut
WHERE <ehdot> määrittelee ehdot haettaville riveille (monikoille)
SELECT * hakee kaikki sarakkeet
SELECT ilman WHERE-ehtoa hakee kaikki rivit

SQL-käskyn esitystapa ja rakenne
SQL-kyselyn yleinen muoto:
SELECT [A1, A2, … AN] -- valittavat sarakkeet
FROM [T1, T2 … TM] -- valittavat taulut
WHERE [L1] -- kyselyn ehto
GROUP BY [L2] -- ryhmittelyehto
HAVING [L3] -- ryhmittely hakuehto
ORDER BY [L4] -- lajitteluehto
Kommentit alkaa yleensä kahdella viivalla: --
(ei toimi Accessissa; vanhassa MySQL:ssä pitää olla välilyönti viivojen jälkeen)
/* Tällä tavoin voidaan merkitä pidempi kommentti monissa tuotteissa (mm. MySQL, Oracle, SQL Server) */
Monissa tuotteissa käskyn lopussa on puolipiste, mikä kertoo tuotteelle käskyn päättymisestä

SQL-esimerkkejä
Hae kaikki henkilöt, jotka ovat syntyneet v. 1975:
SELECT *
FROM henkilo
WHERE syntvuosi = 1975
DISTINCT, mikäli mahdolliset toistot halutaan poistaa:
SELECT DISTINCT myyja FROM tuotteet
SELECT-lause voi sisältää sarakkeisiin kohdistuvia operaatioita (laskentaa) ja sarakkeelle voidaan antaa nk. Aliasnimi (AS-sidesanalla), esim.
SELECT hinta, hinta * 1.22 AS HintaSisALV, nimi
FROM tuote
Monissa tuotteissa AS-sidesana voidaan jättää pois

SQL-hakuesimerkkejä; lajittelu
Haetaan kaikki tuotetiedot, lajittelu nimen mukaan:
SELECT *
FROM tuotteet
ORDER BY nimi  -- oletus = nouseva eli ASC, laskeva = DESC
Kysely, joka lajittelee ensisijaisesti sukunimen mukaan, mutta näyttää kuitenkin ensin etunimen:
SELECT etunimi, sukunimi, kunta, tutkinto, palkka
FROM henkilo
ORDER BY sukunimi, etunimi

Rivien valinta: WHERE-ehto
WHERE-ehto voi sisältää
vertailuoperaattoreita <, >, <>, <=, >=, !=, !>, !<)
BETWEEN -määreen
IN -määreen
LIKE -määreen
IS NULL tai IS NOT NULL -ehdon
AND, OR ja NOT -operaattoreita
Merkkijonohaut:
% = mikä tahansa merkkijono (Accessissa *)
_  = joku merkki (Accessissa ?)
Kirjainkoolla on väliä (paitsi MS:n tuotteissa ja MySQL:ssä)

WHERE-esimerkkejä
SELECT nimi, hinta
FROM tuotteet
WHERE hinta BETWEEN 100 AND 1000;
SELECT  nimi FROM tuotteet
WHERE nimi LIKE '%86%';
SELECT nimi, hinta FROM tuotteet
WHERE nimi NOT IN ('pentium' , 'K6');

Koostefunktiot
Viisi standardifunktiota:
AVG -- keskiarvo
MIN -- pienin arvo
MAX -- suurin arvo
SUM -- summa
COUNT -- lukumäärä
Esim. montako henkilöä on henkilo-taulussa:
SELECT Count(*) AS Lkm
FROM henkilo;

Koostefunktioiden käyttö
Koostefunktioita käytetään SELECT-lauseen sarakeluettelossa ja HAVING-lauseessa
SELECT MAX(hinta), MIN(hinta) -- suurin ja pienin hinta
FROM tuote;
WHERE-lauseessa koostefunktioita ei voi käyttää (vaan ne on laitettava HAVING-lauseeseen), esim. Haetaan myyjät, joiden myymien tuotteiden hinta yhteensä on yli 5000:
SELECT myyja, SUM(hinta) -- tuotteiden hintojen summa
FROM tuote;
GROUP BY myyja -- ryhmittely myyjän mukaan
HAVING SUM(hinta) > 5000;
DISTINCT-rajaus toimii muissa tuotteissa paitsi Accessissa:
SELECT COUNT(DISTINCT city) -- monestako kaupungista
FROM authors; -- kirjailijoita

Ryhmittely - Group By
GROUP BY -ehdolla tiedot ryhmitellään jonkin sarakkeen tai sarakkeiden mukaan ryhmiin
GROUP BY -ehdon ryhmiin kohdistetaan yleensä jokin summafunktio
kaikki SELECT-listan lauseet, joissa ei ole funktiota, on lueteltava GROUP BY –lauseessa!
Esim. kunkin myyjän tuotteiden hintojen keskiarvo:
SELECT myyja, AVG(hinta) FROM tuote
GROUP BY myyja;
Kunkin myyjän tuotetyyppien määrä
SELECT myyja, COUNT(myyja) FROM tuote
GROUP BY myyja;

Ryhmittely - Having
Sekä HAVING- että WHERE-lauseella voidaan ryhmittelyn tulosta rajata:
SELECT myyja, COUNT(*)  -- myös NULL kelpaa
FROM tuote
WHERE tuoteHinta > 100
GROUP BY myyja -- hae myyjät joilla
HAVING COUNT(*) >2; -- vähintään 3 tuotetta
Tulosjoukkoa voidaan siis rajata eri tasoilla:
rajataan ensiksi ryhmiteltävä joukko WHERE-lausekkeella
tästä syntynyt tulos ryhmitellään GROUP BY-määrittelyllä
lopuksi ryhmiteltyä joukkoa voidaan vielä rajata HAVING-lauseella

Muita funktioita
Pyöristys useimmissa tuotteissa ROUND-funktiolla, esim.
SELECT palkka, round(palkka*1.1,0) AS uusipalkka
FROM emp;
Päivämääräfunktiot, ks. Hovi s. 56 – 65
Tuotekohtaiset maa-asetukset huomioitava
ANSI-standardissa CURRENT_DATE: tämä päivä
Tuotekohtaisista eroista on hyvä yhteenveto:
http://troels.arvin.dk/db/rdbms/#functions

Merkkijonofunktioita
Merkkitiedon käsittely
standardissa merkkijono saadaaan funktiolla SUBSTRING(mjono FROM mista FOR pituus)
monissa tuotteissa on kuitenkin SUBSTR(mjono,mista,mihin)
-funktio (Accessissa Mid-funktio), esim.:
SELECT sukunimi, ‘, ‘,  SUBSTR(etunimi,1,1), ‘.’
FROM nimet
Tuloksena lista: Aaltonen, M. …
Muita merkkijonofunktioita:
CHAR_LENGTH -- merkkien määrä (Oraclessa LENGTH)
UPPER(nimi) -- merkit isoiksi (Accessissa UCase)
LOWER(nimi) -- merkit pieniksi (Accessissa LCase)
LEFT(nimi, n) -- merkkijono vasemmalta (n merkkiä)
RIGHT(nimi, n) -- merkkijono oikealta (n merkkiä)

Vielä merkkijonojen käsittelystä
Merkkijonojen yhdistäminen (konkatenointi)
standardia noudattavat Oracle ja DB2, jossa merkkijonot yhdistetään kahdella pystyviivalla, esim.:
SELECT sukunimi || ', ' || etunimi AS Nimi
FROM HENKILO;
MS:n tuotteissa käytetään + -merkkiä ja MySQL:ssä CONCAT-funktiota
Tietotyypin muuntaminen:
eksplisiittisesti numeerisen ja merkkimuotoisen välillä, esim. ANSI-standardin CAST-funktiolla tai Oraclessa TO_CHAR (n, [format [,lang]]);
muutoin implisiittisesti

SQL:2003-standardin uusia funktioita
Nk. skalaarifunktiot: LN (), EXP (), POWER (), SQRT (), FLOOR (), CEIL[ING] (), WIDTH_BUCKET()
Koostefunktiot: STDDEV_POP (), STDDEV_SAMP (), VAR_POP (), VAR_SAMP () ym.
Nk. taulukkofunktiot: RANK () OVER ..., DENSE_RANK () OVER ..., PERCENT_RANK () OVER ..., CUME_DIST () OVER ..., ROW_NUMBER () OVER ...
Muitakin on ...

Liitokset - haut useaan tauluun
Tavallisin liitos on valintaliitos
ehtona =, !=, <, <=, >=, >
yhtäläisyysliitos (=) yleisin (vrt. Inner join)
taulut liitetään toisiinsa yleensä avaimilla (perus- ja viiteavain)
Esim.
SELECT nimi, tilausnumero
FROM asiakas INNER JOIN tilaus
ON asiakas.asiakastunnus = tilaus.asiakastunnus;
 Kvalifiointi: taulun nimi sarakenimen eteen
pakollista, jos saman niminen sarake kahdessa taulussa

Perinteinen liitos
Liitosehto WHERE-lauseessa
Esim. hae yrityksen nimi, ko. yrityksen henkilöiden nimet ja palkat yli 2500 tienaavista:
SELECT Yrtun, Nimi,      -- Hae yrityksen tunnus, nimi
Sukunimi, Etunimi, Palkka -- ja henkilön nimi + palkka
FROM YRITYS, HENKILO -- näistä tauluista
WHERE YRITYS.Yrtun = HENKILO.Yrtun -- Liitosehto!
AND Palkka > 7500 -- Hakuehto palkalle
ORDER BY Nimi; -- Lajittelu

Uusi liitossyntaksi (suositeltavampi vaihtoehto)
Liitosehto FROM-lauseessa
Hae yrityksen nimi, ko. yrityksen henkilöiden nimet ja palkat yli 2500 tienaavista:
SELECT Yrtun, Nimi,      -- Hae yrityksen tunnus, nimi
Sukunimi, Etunimi, Palkka -- henkilön suku- ja etunimi + palkka
FROM YRITYS -- YRITYS –taulusta,  joka
INNER JOIN HENKILO -- liitetään HENKILO-tauluun
ON YRITYS.Yrtun = HENKILO.Yrtun -- Liitosehto
WHERE Palkka > 7500 -- Hakuehto palkalle
ORDER BY Nimi; -- Lajittelu
Standardin mukaan voidaan myös käyttää NATURAL JOIN –liitosta, jos liitossarakkeet ovat samannimiset

Liitokset: ulkoliitos (outer join)
Outer Join ottaa mukaan myös ne rivit, jotka eivät täytä join-ehtoa; esim.:
haetaan myös ne asiakkaat, joille ei löydy tilauksia:
SELECT nimi, tilausnumero
FROM asiakas
LEFT OUTER JOIN tilaus
ON asiakas.asiakastunnus = tilaus.asiakastunnus;
vanha syntaksi:
SELECT nimi, tilausnumero
FROM asiakas, tilaus
WHERE asiakas.asiakastunnus (+) = tilaus.asiakastunnus;
OUTER-sana voidaan jättää pois SQL-standardissa

Liitos itseensä
Liitos itseensä: tarvitaan korrelaationimeä (alias)
Esim. haetaan JAMKin eri yksiköt:
SELECT a.nimi
FROM asiakas a, asiakas b
WHERE a.emoyritystunnus = b.asiakastunnus
AND b.nimi = 'JAMK';
Joissakin tuotteissa pitää käyttää AS-sidesanaa korrelaationimen edessä, joissakin pitää olla välilyönti
Kun korrelaationimi on otettu käyttöön, ei alkuperäistä nimeä saa käyttää sarakkeen kvalifioinnissa (esim. edellisessä käskyssä SELECT asiakas.nimi antaisi virheilmoituksen

Yhdiste (UNION)
Kaksi taulua (tai useampia) yhdistetään samantyyppisen tiedon avulla
Esim. opettajien ja opiskelijoiden puhelinnumerot:
SELECT OpeNimi AS Nimi, PuhNro, ’opettaja’
FROM OPETTAJA
UNION
SELECT OpiskNimi AS Nimi, PuhNro, ’opiskelija’
FROM OPISKELIJA
ORDER BY 1;

Alikysely
Voidaan käyttää SELECT, INSERT, UPDATE ja DELETE -komennoissa
Sisin kysely suoritetaan ensiksi
Voi palauttaa vain yhden sarakkeen ja sille yhden tai useamman arvon
vertailuoperaattori “=“: alikysely voi palauttaa vain yhden arvon
IN-operaattori tai vertailuoperaattori ANY tai ALL -ehdon kanssa sallii alikyselyn palauttavan useita arvoja
Oltava aina suluissa ja haettavana saa olla vain yksi sarake
Käyttää automaattisesti distinct-määrettä

Alikyselyt – esimerkki1: =
Hae sen henkilön nimi, joka myy solmioita:
SELECT HenkNimi
FROM HENKILO
WHERE HenkID =
(SELECT MyyjaID
FROM TUOTE
WHERE TuoteNimi = ‘Solmio');
Aika usein alikyselyssä etsitään arvoa koostefunktiolla (palauttaa aina yhden arvon)

Alikyselyt – esimerkki 2: IN
Hae niiden tuotteiden nimet ja hinnat, joita myy laiteosastolla olevat henkilöt:
SELECT TuoteNimi, hinta
FROM tuote
WHERE myyja IN
(SELECT myyja
FROM myyjat
WHERE osasto = 'laite');
Myös NOT IN on käyttökelpoinen, kun halutaan sulkea pois alikyselyn palauttama tulosjoukko

Alikyselyt – esimerkki 3: ANY, ALL ja EXISTS
Jos käytetään vertailuoperaattoria > tai <, niin IN ei käy
SELECT nimi, hinta, myyja
FROM tuote -- hakuehto:
WHERE hinta > ANY -- ne myyjät
(SELECT hinta -- jotka myyvät
FROM tuote -- kalliimpia tuotteita
WHERE myyja = ‘Pekka'); -- kuin Pekka
ANY: jos alikyselyn mikä tahansa arvo täyttää ehdon
ALL: jos alikyselyn jokainen yksittäinen arvo täyttää ehdon
EXISTS: tosi, jos alikysely palauttaa ainakin yhden rivin

3. Taulujen määrittely ja muuttaminen
DDL: Taulujen luonti, muutos ja poisto
DML: taulujen tietojen ylläpito
Tapahtumien (transaktioiden) hallinta
Näkymät, synonyymit ja muut tietokantaobjektit

Taulujen perustaminen
Taulun perustajalla täytyy olla valtuudet (GRANT) tietokantaan
Kullekin taulun sarakkeelle annetaan nimi ja tietotyyppi (+ maksimipituus ja mahdolliset desimaalit)
Tarvittaessa määritetään rajoitteita (NOT NULL, PRIMARY KEY, FOREIGN KEY, UNIQUE, DEFAULT ja CHECK)

SQL-esimerkki: taulun luonti
Taulu luodaan CREATE TABLE –käskyllä:
CREATE TABLE YRITYS
(YritysID smallint NOT NULL,
 YritysNimi varchar (80),
 Toimialakoodi char (10),
 YrLisaysPvm date,
 PRIMARY KEY (YritysID))
Viite-eheys REFERENCES-määreellä, ks. Rajoitteet
CONSTRAINT fk_toimiala FOREIGN KEY (Toimialakoodi)
REFERENCES TOIMIALA (Toimialakoodi)

Muutamia SQL-92-standardin tietotyyppejä
CHAR [(pit.), kiinteä, oletuspit. 1]
VARCHAR [(pit.), vaihtuvanmitt. merkkijono]
NUMERIC [(koko pituus [,desimaaliosa])]
INTEGER [kokonaisluku, pit. tuotekoht.]
DATE [vuosi (0001-9999), kk ja päivä]
TIME [(pit.), tunti, minuutti ja sekuntti]
BLOB [SQL-99, binary large object]

Ocelot-tietokantatuote sis. SQL2:n ja osan SQL3:n tietotyypeistä

SQL:2003 – muutokset aikaisempaan standardiin
Uudet tietotyypit:
BIGINT (tarkkuus tuotekohtainen, kuitenkin aina
BIGINT >= INTEGER >= SMALLINT)
MULTISET (voidaan luoda ARRAY-tyyppinen kokoelma)
Kaksi tietotyyppiä poistettu:
BIT
BIT VARYING
Sequence
CREATE TABLE LIKE …
Ym.

Oraclen tietotyypit
CHAR [255 tavua, kiinteäpituuksinen]
VARCHAR2 [2 kt (4 kt Oracle 8:ssa)]
NUMBER [numeerinen 1x10-130 – 9,99x10125]
LONG [2 Gt]
RAW [255 tavua, binaarinen]
LONG RAW [2 Gt, binaarinen]
DATE [pvm ja aika, kiinteäpituuksinen]
ROWID [rivin ID:n muuttujatyyppi]

Muita Oraclen tietotyyppejä
NCHAR ja NVARCHAR2: kansallisen kielen tietotyyppi
CLOB: yksitavuinen, NCLOB: yksi- tai monitavuinen, 4 Gt
BLOB: binaarinen, 4 Gt
BFILE: osoitin tallennettuun ulkoiseen bin.tiedostoon
Oraclen oma (esim. SDO_GEOMETRY for Oracle Spatial)
Käyttäjän määrittämä tietotyyppi (voidaan tehdä INTYPE File Assistant -ohjelmalla)

SQL-esimerkki: taulun muutos
Taulu muutetaan ALTER TABLE –käskyllä,
esim. sarakkeen lisäys (loppuun)
ALTER TABLE YRITYS
ADD COLUMN Maa char (20)
ALTER TABLE tuli osaksi SQL-standardia vasta SQL3:ssa
Katso tuotekohtaisesti, voidaanko lisätä kerralla useita sarakkeita tai sarake johonkin väliin
Sarakkeen muutos: ALTER COLUMN ja poisto: DROP COLUMN, ks. oma tuotteesi, esim.
ALTER TABLE YRITYS
DROP COLUMN Maa CASCADE

Eheysvaatimukset
Tietokantaan kohdistuu kolmen tyyppisiä eheysvaatimuksia:
Avaineheys: taululla tulee olla perus- eli pääavain (PK)
Viite-eheys: viiteavaimelle tulee löytyä arvo viitattavan taulun pääavaimesta
Attribuuttieheys: attribuuttien tulee kuulua sallittuun joukkoon
Määritetään nk. rajoitteella (ks. seur. kalvo)
Palvelin tarkistaa eheysvaatimusten toteutumisen

Rajoitteet eli pakotteet (constraints)
Määritellään CREATE TABLE tai ALTER TABLE -komennoissa
Rajoitteita voidaan määritellä sarakkeille tai tauluille
Rajoitteita ovat:
avaimet: PRIMARY KEY, FOREIGN KEY ja UNIQUE
oletusarvot ja raja-arvotarkistukset: DEFAULT ja CHECK
esimerkkejä:
ALTER TABLE DEPT
ADD CONSTRAINT pk_deptno PRIMARY KEY (deptno),
ADD priority SMALLINT DEFAULT 1
ADD CONSTRAINT chk_sukup CHECK (sukupuoli IN (‘M’,’N’))

Primary Key, Unique ja Foreign key
Primary Key (CONSTRAINT pk_sarake PRIMARY KEY (sarakenimi1 [,sarakenimi2])
Yksiköi taulun rivit
Sarakkeiden tulee olla Not Null -tyyppisiä
Käytetään hyväksi viite-eheyttä luotaessa
Unique (CONSTRAINT sarakenimi UNIQUE)
Luo yksilöivän indeksin (oletus on ei klusteroitu)
Sarakkeet voivat sisältää Null-arvoja
Voi olla useita / taulu
Foreign Key (CONSTRAINT fk_sarake FOREIGN KEY (sarakenimi) REFERENCES vanhempi (perusvain) )
Luo viite-eheyden taulujen välille
Voi sisältää useita sarakkeita

Viiteavaimen lisäys
Viite-eheys voidaan määritellä taulua luotaessa tai jälkeenpäin ALTER TABLE -käskyllä
Esim. Puhelin-taulu, jonka vanhempi on Henkilo; jos henkilö poistetaan niin myös henkilön puhelimet poistetaan (ON DELETE CASCADE)
ALTER TABLE Puhelin
ADD CONSTRAINT FK_HenkiloID
FOREIGN KEY (HenkiloID)
REFERENCES Henkilo (HenkiloID)
ON DELETE CASCADE
Viisi vaihtoehtoa: CASCADE, SET DEFAULT, SET NULL, NO ACTION, RESTRICT, joista kaksi viimeistä estävät poiston, jos vanhemmalla on lapsia
Myös päivitykset voidaan vyöryttää: ON UPDATE CASCADE

Laskuri: automaattisesti kasvava sarake
Taululle voidaan määritellä sarake, joka on automaattisesti kasvava numero
Määrittelyssä annetaan alkuarvo ja lisäys
Standardin mukaan laskuri luodaan joko IDENTITY- tai SEQUENCE-käskyllä
Ominaisuus voidaan luoda myös CREATE TABLE, ALTER TABLE tai SELECT INTO –komennon yhteydessä
Laskuri toimii usein perusavaimena

Laskurin luonti
Esimerkki 1:
CREATE TABLE tuotteet (
TUOTE_ID INTEGER
GENERATED ALWAYS AS IDENTITY
START WITH 100
INCREMENT 1
MINVALUE 100
NO MAXVALUE
NO CYCLE,
... )
Esimerkki 2:
CREATE SEQUENCE osanumero AS INTEGER
START WITH 1
INCREMENT BY 1
MAXVALUE 100000
MINVALUE 1

SQL:2003 - GENERATED ALWAYS
Esimerkki:
CREATE TABLE EMPLOYEES (
EMP_ID INTEGER,
SALARY DECIMAL(7,2),
BONUS DECIMAL(7,2),
TOTAL_COMP GENERATED ALWAYS AS (
SALARY + BONUS ),
HR_CLERK GENERATED ALWAYS AS (
CURRENT_USER )
)

Taulun poisto
Taulun poisto tapahtuu DROP TABLE -käskyllä, esim.
DROP TABLE TEMP;
Tällöin vyörytetään poistot, jos CASCADE DELETE on lapsitauluun määritetty, muutoin poisto estetään (jos viite-eheys on asetettu)
Samalla poistuu taulussa olevat tiedot (olihan siis backup tallessa?)

DML
Tietojen lisäys, muutos ja poisto
Tapahtumien eli transaktioiden hallinta

Tietojen lisääminen
INSERT INTO taulu VALUES (arvot);
Esim.
INSERT INTO prosessorit(cpu, hinta)
VALUES ('AMD', 700);
Sarakkeiden nimiä ei tarvitse luetella, jos kaikille annetaan arvo tai niillä on oletusarvo tai ne sallivat Null-arvon; on kuitenkin suositeltavaa luetella ne!
Taulusta toiseen:
INSERT INTO taulu1 SELECT s1, s2 FROM taulu2;
MySQL:ssä voidaan antaa useita lisättäviä rivejä yhdessä käskyssä

Tietojen muuttaminen
Olemassa olevien tietojen päivittäminen
UPDATE tuotteet SET hinta = 1200
WHERE tuote_nimi = 'lelu';
Tai esim. 10 %:n hinnan lisäys:
UPDATE tuotteet SET hinta = hinta * 1.1
Useaan tauluun perustuva päivitys
UPDATE tuotteet SET määrä = 10
FROM tuotteet t, myyjat m
WHERE t.myyja = m.myyja;

Tietojen poistaminen
Rivien poistaminen taulusta
DELETE {FROM} [taulun nimi] WHERE [ehto poistettaville riveille]:
DELETE FROM tuote WHERE nimi = 'auto';
Poisto alikyselyn avulla
DELETE asiakas WHERE asiakastunnus
NOT IN  (SELECT asiakastunnus FROM TILAUS);

Tapahtumien eli transaktioiden hallinta
Tapahtuma on yleensä useamman käskyn kokonaisuus, joka suoritetaan joko kokonaan tai ei ollenkaan
Esim. maalitilaston päivitys:
BEGIN TRANSACTION
INSERT INTO ottelu (joukkue1ID, joukkue2ID, kotimaalit, vierasmaalit) VALUES (3, 8, 4, 2);
UPDATE joukkue
SET maalisaldo = maalisaldo + :kotimaalit - :vierasmaalit
WHERE joukkueID = :joukkue1ID;
UPDATE joukkue
SET maalisaldo = maalisaldo + :vierasmaalit - :kotimaalit
WHERE joukkueID = :joukkue2ID;
COMMIT;
COMMIT hyväksyy, ROLLBACK peruuttaa tapahtuman

SQL-92 eristyvyystasot
Eristyvyystaso ilmaisee transaktion eristyvyyttä eli riippumattomuutta muista samanaikaisista transaktioista
Tavoitteena ehkäistä samanaikaisuuden ongelmia:
1 Hukatun päivityksen ongelma (lost update): päällekirjoitus
2 Keskeneräisen käsittelyn ongelma (uncommitted dependency)
a) luetaan peruutettava
b) päivitetään peruutettava
3 Ristiriitaisen tulkinnan ongelma (inconsistent analysis)
a) eritahtinen päivitys
uusien rivien ongelma (phantom rows)
Katso esimerkit erillisestä kalvosetistä (J. Rantanen)
http://data.hamk.fi/materiaalit/tiedonhallinta2/ccr/eristyvyys.pps

Eristyvyystasot
Komennolla
SET TRANSACTION ISOLATION LEVEL
voidaan asettaa neljä eri eristyvyystasoa:

Muita tietokantaobjekteja
Näkymät, synonyymit, indeksointi, valtuudet ja systeemihakemisto

Näkymät
Näkymä (view) on looginen näyte tietokannan tauluista tai näkymistä
Näkymä ei voi sisältää SELECT INTO, ORDER BY tai COMPUTE -ehtoja
Ei voi viitata väliaikaisiin tauluihin
Tarvitaan SELECT-oikeus tauluihin
Esim:
CREATE VIEW Hinnasto
AS SELECT nimi, hinta FROM tuote;
Käyttö:
SELECT * FROM Hinnasto;

Näkymän käyttö
Näkymän kautta voidaan päivittää tai lisätä tietoja, mutta yleensä vain yhteen tauluun ja silloinkin on useita ehtoja, mm. näkymässä ei saa olla DISTINCT-määrettä, GROUP BY tai HAVING-lausetta eikä alikyselyä
Näkymä poistetaan DROP VIEW -komennolla
Jos näkymässä on laskettuja sarakkeita, view-määrittelyn nimen jäljessä täytyy luetella sarakkeiden nimet:
CREATE VIEW ALVhinnasto(nimi, ALVhinta)
AS SELECT nimi, hinta*1.22
FROM TUOTE;

Esimerkki laskentaosasto-näkymästä
CREATE VIEW Accounting AS
SELECT dname, loc, empno, ename, job
FROM dept, emp
WHERE dept.deptno = emp.deptno
AND dept.deptno = 10; -- 10: ACCOUNTING-osasto
SELECT * FROM Accounting;
DROP VIEW Accounting;

Vinkkejä näkymien luontiin
Testaa ensin kysely ja luo vasta sitten näkymä
Jos taulun nimi muuttuu, luo kysely jossa on alkuperäisen taulun kentät; tällä tavoin sinun ei tarvitse muuttaa olemassa olevia SELECT- ym. käskyjä
Näkymillä voit suojata tietoja käyttäjäryhmittäin
Voit rakentaa näkymän toisen näkymän päälle, mutta se voi vaikeuttaa ymmärtämistä

Synonyymit
Helpottavat viittaamista tauluun antamalla tauluviittaukselle jokin kuvaava nimi
Esim. jos toinen käyttäjä (Pekka) on antanut SELECT-oikeuden omaan tauluunsa (kurssi), voidaan tiedot hakea komennolla SELECT * FROM Pekka.kurssi
Luomalla synonyymi (CREATE SYNONYM kurssit FOR Pekka.kurssi) voidaan em. kysely tehdä käskyllä SELECT * FROM kurssit
Tarkista tuki synonyymille omasta tuotteestasi

Valtuudet
Tavoitteena tietojen suojaus
Tiedot voidaan suojata käyttäjä- ja taulukohtaisesti
Käyttäjiä luodaan useimmissa tuotteissa CREATE USER –käskyllä ja salasana määritetään samalla, esim. CREATE USER jouni IDENTIFIED BY jh1
Joissain tuotteissa salasana luodaan CREATE PASSWORD -käskyllä
Käyttöoikeudet voidaan niputtaa nk. rooliin (voi olla myös yksittäinen henkilö) ja luoda CREATE ROLE –käskyllä, esim. CREATE ROLE opettaja
Valtuudet myönnetään GRANT-käskyllä, esim. GRANT SELECT ON kirjat TO jouni tai kaikki oikeudet GRANT ALL -käskyllä
Valtuudet poistetaan REVOKE-käskyllä ja käyttäjä DROP USER -käskyllä

Indeksit
Tauluille voidaan perustaa sarakekohtaisia hakemistoja eli indeksejä
Indeksien käytön tarkoituksena on mm. nopeuttaa tietokantaan tapahtuvia hakuja
Yksilöivä (unique) indeksi voi toimia myös perusavaimena
CREATE UNIQUE INDEX i ON taulu(sarake)

Indeksien käyttö
Indeksoinnin etuja:
hakujen, liitosten, ryhmittelyjen ja lajittelujen nopeutuminen
pakottaa yksilöimään rivit
Kannattaa indeksoida:
perusavaimet ja viiteavaimet
sarakkeet, joita haetaan tai järjestetään usein
Indeksointi vie levytilaa ja aikaa luotaessa ja muutoksissa
Ei kannata indeksoida:
harvoin haussa käytettäviä sarakkeita
sarakkeita, joiden selektiivisyys on huono

Peukalosääntö indeksin luomiselle (nk. 3 tähden indeksi)
Ota kaikki WHERE-kohdassa mainitut sarakkeet
Lisää ORDER BY –kohdassa mainitut sarakkeet
Laita loppuun SELECT-lauseessa olevat sarakenimet
Esim. sopiva indeksi ”SELECT a, b, c FROM t WHERE d = ’x’ ORDER BY b” –käskylle olisi
CREATE INDEX i_dbac ON t(d,b,a,c)
Jos kaikki SELECTissä mainitut sarakkeet on mukana indeksissä, kyse on paksusta indeksistä
Indeksi poistetaan DROP INDEX -käskyllä

Tietokannan ja tietokantakaavan (”skeeman”) perustaminen + systeemihakemisto
Tietokanta luodaan monissa tuotteissa  CREATE DATABASE -käskyllä, esim. CREATE DATABASE kirjat
Tietokantakaava (schema) on kokoelma tietokanta-objekteja (taulut, näkymät jne.), se vastaa siis käsitettä tietokanta; kaava luodaan käskyllä CREATE SCHEMA
Tieto eri tietokantaobjekteista on nk. tieto- eli systeemihakemistossa (catalog, data dictionary); se on standardin mukaan nimeltään INFORMATION_SCHEMA
Tietokantakaavan omistaa aina yksi henkilö (rooli)

Haut systeemihakemistosta
Käskyt vaihtelevat tuotteittain
Lista (käyttäjän) tauluista saadaan eri tuotteissa seuraavilla käskyillä:
SHOW TABLES (MySQL)
SELECT table_name from user_tables (Oracle)
SELECT tname FROM tab (Oracle)
SELECT table_name FROM information_schema.tables (SQL Server)
Lista tietohakemiston sisältämistä tietokannoista ja niiden omistajista (Ocelot): SELECT CATALOG_NAME, SCHEMA_NAME, SCHEMA_OWNER FROM INFORMATION_SCHEMA.SCHEMATA

Lisätietoa
Relaatiotietokantasanasto: http://www.cs.helsinki.fi/~laine/relaatiosanasto/
Historiaa ym.: http://en.wikipedia.org/wiki/SQL
Suomeksi: http://fi.wikipedia.org/wiki/SQL
Yhteenveto: http://www.ocelot.ca/glossary.htm
SQL-kurssi: http://sqlcourse.com ja http://sqlcourse2.com
SQL-standardeista: http://www.jcc.com/sql.htm
Tuotteiden erosta: http://troels.arvin.dk/db/rdbms/