SQL
SQL | |
![]() | |
Paradigma | deklaratív programozás |
Jellemző kiterjesztés | sql |
Megjelent | 1974 |
Tervező |
|
Fejlesztő |
|
Utolsó kiadás | SQL:2023 (2023. június 1.)[1] |
Hatással volt rá |
|
nélkül Weboldal |
Az SQL, azaz Structured Query Language (strukturált lekérdezőnyelv) relációsadatbázis-kezelők lekérdezési nyelve.
Angol nyelvterületen 'eszkjuel' a kiejtése. A hagyományokhoz való hűség jegyében sokan 'szíkvel'-nek ejtik, ugyanis korábban Structured English Query Language (SEQUEL) volt az elnevezés, és ezt rövidítették le.
A relációsadatbázis-kezelők általában az SQL nyelven programozhatók. Az SQL alapvető utasításait közel egyformán valósítják meg, de a később beépült nyelvi elemek körében nagyon nagy az eltérés, az inkompatibilitás, emiatt számos SQL nyelvjárásról beszélhetünk.
Jellegét tekintve ez a szakterület-specifikus nyelv részben procedurális, részben deklaratív.
Az SQL története
Az SQL alapjait az IBM-nél fektették le, még az 1970-es években. Elvi alapot a relációs adatmodell szolgáltatott, amit Edgar F. Codd híres 12 szabályával írt le először, 1970-ben.
Az IBM, az Oracle és más gyártók is érdekeltek voltak egy szabványos lekérdező nyelv kifejlesztésében, amivel a relációs adatbázisok programozhatók. Az iparági összefogással létrejött ANSI NCITS (National Committee on Information Technology Standards) H2 csoport lerakta az SQL alapjait.
A szabványt az ANSI (Amerikai Nemzeti Szabványügyi Intézet – American National Standards Institute) 1986-ban, az ISO (Nemzetközi Szabványügyi Szervezet – International Organization for Standardization) 1987-ben jegyezte be. Az SQL leírását az ISO 9075 szabvány rögzíti.[2] Az első változatot SQL86 néven is szokták emlegetni.
Az SQL-t folyamatosan továbbfejlesztették, és hét jelentős kiadást különböztetünk meg:
- SQL86
- SQL89
- SQL92
- SQL99 (v. más néven: SQL3)
- SQL:2006
- SQL:2008
- SQL:2011
Az első kivételével mindegyik szabvány többszintű megvalósítást tesz lehetővé a gyártóknak (belépő szintű, közepes vagy teljes). Általában a későbbi szabványok belépő szintjei az előző szabvány teljes szintjeinek felelnek meg.
Az SQL nyelv
Az SQL nyelvi elemeket 4 részre, adatdefiníciós (Data Definition Language, DDL), adatkezelési (Data Manipulation Language, DML), lekérdező (QUERY( Language - QL)) és adatvezérlő (Data Control Language, DCL) részekre lehet bontani.
A nyelvben az utasításokat a pontosvessző választja el egymástól.
Adatdefiníciós utasítások
Azt a nyelvet melynek segítségével az adatbázis adminisztrátorok az új adatbázisok sémáját definiálják adatdefiníciós nyelveknek (DDL = Data Definition Language) nevezzük.
CREATE
Adatbázis objektum létrehozása. Példa adatbázis tábla definíciójára:
CREATE TABLE Szamla (
Szamlaszam NUMERIC(24),
Tulajdonos VARCHAR(60),
Nyitas DATE,
Allapot VARCHAR(1),
PRIMARY KEY (Szamlaszam)
);
A fenti példa létrehoz egy adatbázis táblát, 4 oszloppal.
ALTER
Adatbázis-objektum módosítása. Példa:
ALTER TABLE Szamla
ALTER COLUMN Szamlaszam VARCHAR(26);
A fenti példa megváltoztatja egy adatbázis tábla egy oszlopának típusát.
DROP
Egy adatbázisbeli objektum megszüntetése. Példa:
DROP INDEX Szamla_1;
A fenti példa megszüntet egy indexet.
DROP TABLE egy_tabla;
Ez pedig egy adattáblát szüntet meg.
Adatlekérdező utasítások (QUERY)
A lekérdező nyelv egyetlen utasításból áll, mely számos alparancsot tartalmazhat, és a lekérdező utasítások többszörös mélységben egymásba ágyazhatók. Célja, hogy egy vagy több adathalmazból (reláció) egy adathalmazt állítson elő. A bemeneti adatokon, a relációs algebra műveletei hajthatóak végre, aminek következményeként egy eredmény táblát kap a felhasználó. Végrehajtási sorrendjük a következő: FROM, WHERE, GROUP BY, HAVING, SELECT, ORDER BY.[3]
SELECT
Az SQL talán leggyakrabban használt utasítása a lekérdezés. Ez a nyelvi elem inkább deklaratívnak[4] tekinthető, mint procedurálisnak, hiszen a felhasználó (programozó) csak az eredményhalmaz mezőit (oszlopait) és a halmaz felépítésének feltételeit határozza meg, a leválogatási algoritmus elkészítése az adatbázis-kezelő feladata.
A SELECT utasítás az adatok egy halmazát válogatja ki egy táblázatba a relációs adatbázisból, és teszi elérhetővé valamilyen technikával a felhasználó számára. Mivel elég nagy adatmennyiségekről lehet szó (szélsőséges esetben az egész adatbázisról), ezért a halmaz általában szekvenciálisan olvasható. Egy mutató (kurzor) mozgatható az eredmény halmazon előre vagy hátra, és kiolvasható, hogy milyen adatok vannak a mutató alatt. Ha a mutató az eredményhalmaz végére vagy elejére ért, azt különleges jelzéssel tudatja az adatbázis-kezelő (EOF – End of File – állomány vége, illetve BOF – Beginning of File, állomány eleje)
Példa:
SELECT COUNT(*), Tulajdonos
FROM Szamla
WHERE Allapot = 'N'
GROUP BY Tulajdonos
HAVING COUNT(*) > 1
ORDER BY Tulajdonos
A fenti példa kilistázza azokat a személyeket, akiknek egynél több aktív bankszámlája van. Az első oszlopban az aktív bankszámlák száma, a másodikban a tulajdonosok neve olvasható. A táblázat a tulajdonosok neve szerinti emelkedő sorrendben jelenik meg.
A SELECT utasítás több szakaszból állhat, amelyek közül majdnem mindegyik elhagyható, ha szükséges. Az egyes szakaszok magyarázata:
SELECT
Az eredményhalmaz oszlopait kell itt felsorolni. Nagyon hasznos, hogy további SELECT-ek is lehetnek benne!
Példa:
SELECT Vevo.Nev, (SELECT SUM(Osszeg) FROM Rendeles WHERE VevoID = Vevo.ID) RendelesOsszeg
A fenti példa a vevő neve mellett megjeleníti az eddigi rendeléseinek összegét is.
Összetettebb példa:
SELECT munka_szám FROM munka
WHERE óraszám*óradíj = (
SELECT max(óraszám*óradíj) FROM munka
);
A lekérdezés megkeresi a legnagyobb árbevételű munkáinkat – akkor használható jól, ha több is van belőle.
FROM
Meghatározza, hogy mely adatbázis-táblákból szeretnénk összegyűjteni az adatokat.
Példa a hagyományos (limitált képességű, néha problémás) szintaxissal:
SELECT *
FROM Beteg, Kezeles
WHERE Kezeles.Beteg_ID = Beteg.Beteg_ID
vagy az újabb módszer szerint:
SELECT *
FROM Beteg
INNER JOIN Kezeles ON Kezeles.Beteg_ID = Beteg.Beteg_ID
az összes beteg-kezelés párost adja. Amelyik betegnek nem volt kezelése, azt nem írja ki, amelyiknek több volt, azt annyiszor, ahány kezelésen átesett.
az INNER általában elhagyható, vagy írható helyette LEFT, RIGHT, FULL OUTER, CROSS is.
LEFT esetén: az első tábla adatai akkor is szerepelnek, ha nincs illeszkedő adat a másodikban (azaz a fenti példában megmutatja azokat a betegeket is, akinek soha nem volt kezelése)
RIGHT esetén: a második tábla adatai akkor is szerepelnek, ha nincs illeszkedő adat az elsőben (itt ugyanazt az eredményt adja, mint INNER esetén, ha minden kezeléshez tartozik beteg)
FULL OUTER: mindkét táblából megmutatja az összes sort (itt megegyezik a LEFT JOIN eredményével, ha minden kezeléshez tartozik beteg
CROSS: a táblák Descartes szorzatát képezi, azaz az összes lehetséges kombinációt megmutatja. Ekkor a modern szintaxis szerint az ON részre nincs szükség, a régi szerint pedig a WHERE rész nem kell. A gyakorlatban erre a változatra nagyon ritkán van szükség, itt sem adna értelmes adatokat.
A FROM részben a beágyazott lekérdezések (nested query) használatát nagy táblák esetében érdemes elkerülni, mert feleslegesen terhelheti a szervert, illetve megnyújthatja a lekérdezés futás idejét. Egyik lehetséges kerülő megoldás az ideiglenes táblák használata, melyet az eredeti lekérdezésünk elé írt WITH SubQueryTableName AS (SELECT ... FROM ... WHERE ...) szintaxissal valósítható meg.
WHERE
Szűrési feltételeket fogalmaz meg, amelyek szűkítik az eredményhalmazt (a Descartes-szorzathoz képest). Példa:
SELECT *
FROM Beteg, Kezeles
WHERE Beteg.ID = Kezeles.BetegID AND Kezeles.Datum = CURRENT DATE
A fenti lekérdezés visszaadja, milyen kezeléseket végeztek ma, és melyik betegeken. A WHERE szakaszban a Boole-algebra kifejezései használhatók, OR, AND és NOT operátorokkal.
GROUP BY
Egyes sorok összevonását, csoportosítását írja elő az eredménytáblában. Példa:
SELECT COUNT(*), Tulajdonos
FROM Szamla
WHERE Allapot = 'N'
GROUP BY Tulajdonos
A fenti példa a Tulajdonos oszlop alapján csoportosítja a sorokat. A SELECT részben lévő COUNT(*) egy-egy csoport sorainak számát adja vissza, az összevonás előtt.
HAVING
A WHERE-hez hasonlóan itt is szűrést fogalmazhatunk meg, azonban itt a csoportosítás utáni eredményhalmazra. Példa:
SELECT COUNT(*), Tulajdonos
FROM Szamla
WHERE Allapot = 'N'
GROUP BY Tulajdonos
HAVING COUNT(*) > 1
Az előző példához képest itt annyi a módosulás, hogy csak azok a csoportok jelennek meg, amelyek egynél több sorból lettek összevonva.
ORDER BY
Az eredményhalmaz rendezését adja meg. Példa:
SELECT *
FROM Beteg
ORDER BY Szuletes DESC
A fenti példa a betegek listáját adja vissza, születési dátum szerint sorba rendezve, elöl a legfiatalabb beteggel.
CASE
CASE WHEN logikai vizsgálat THEN kifejezés ha igaz .. ELSE kifejezés ha az előzőekre nem illeszkedik END
A logikai vizsgálat eredményétől függően vezérelhetjük, hogy mit szeretnénk az adott oszlopban látni. Példa:
select app_id,budget_info_type,amount
from acq_budget_info
A lekérdezés eredménye:
APP_ID BUDGET_INFO_TYPE AMOUNT ---------- ------------------------ ----------- 0001 net_income 110000 0001 bonus 7500 0001 gross_income 1000 0002 gross_income 2000 0002 net_income 120000 0002 bonus 8500 0003 gross_income 3000 0003 bonus 9500 0003 net_income 130000
Az előző lekérdezés transzponáltja:
select APP_ID, max(net_income), max(gross_income), max(bonus)
from (
select APP_ID,
case when BUDGET_INFO_TYPE='net_income' then amount else null end as net_income,
case when BUDGET_INFO_TYPE='gross_income' then amount else null end as gross_income,
case when BUDGET_INFO_TYPE='bonus' then amount else null end as bonus,
from acq_budget_info) xx
group by APP_ID
APP_ID NET_INCOME GROSS_INCOME BONUS ---------- ----------- ------------- ------------- 0001 110000 1000 7500 0002 120000 2000 8500 0003 130000 3000 9500
Adatmanipulációs nyelv (Data Manipulation Language, DML)
Angolul query plan.
A kurzor létrehozásának technikája adja az SQL kiszolgálók igazi erejét. Nem mindegy ugyanis, hogy sikerül-e a táblákat megfelelő oszlopok (és indexek!) segítségével összekapcsolni, és ezekből kurzort készíteni, vagy pedig átmeneti táblát kell létrehozni az eredményeknek.
Az egyes relációsadatbázis-kezelők egymástól igen eltérő algoritmusokat használnak a lekérdezési tervek megalkotásához. Gyakori a szabályalapú (rule-based), és a költségalapú (cost-based) lekérdezésiterv-készítés. A költségalapú lekérdezési tervhez ismerni kell az adatok statisztikai eloszlását: átlagát, szórását stb. A szabályalapú lekérdezéseknél elegendő csak a relációs adatbázis szerkezetének ismerete. A legtöbb relációsadatbázis-kezelő a kettő valamilyen kombinációjával dolgozik.
Sok gyártó SQL megvalósításában lehetséges a keresési stratégia befolyásolása, úgynevezett programozói lekérdezési tippek (query hints) segítségével. Azonban minél jobb egy adatbázis-kezelő, annál kevésbé szükséges ezek használata.
INSERT
Adatokat ad hozzá egy táblához. Példa:
INSERT INTO Szamla (Szamlaszam, Tulajdonos, Nyitas, Allapot)
VALUES (123456, 'H. Kovács Géza', '1996.05.14.', 'N');
UPDATE
Módosítást hajt végre az adatokon. Példa:
UPDATE Szamla SET Allapot = 'D' WHERE Szamlaszam = 123456;
A fenti utasítás megváltoztatja az egyik számla állapotát.
DELETE
Adatokat töröl egy táblából. Példa:
DELETE FROM Beteg WHERE TAJ = '123 456 789';
Ez az utasítás annak a betegnek, akinek a TAJ száma:123 456 789, törli az összes adatát a Beteg táblából.
Egyéb utasítások
Az SQL-t az idők során kiegészítették olyan tulajdonságokkal, hogy a programozók képesek legyenek benne bonyolult algoritmusokat is írni. Ez akkor válhat szükségessé, ha például komoly adatkezelési feladatokat szeretnénk az ügyféloldalról a kiszolgálóoldalra áthelyezni, az ott elérhető sokkal nagyobb teljesítmény miatt. De az is lehet, hogy csak egyszerűsíteni akarjuk a programozást felhasználói függvények létrehozásával (például szükségünk lenne egy olyan függvényre, ami a TAJ számból kiszedi a szóközöket).
Az SQL nyelv részei a változókezelés, elágazások, ciklusok kezelése, kivételkezelés stb.
A legnagyobb különbségek az SQL kiszolgálók között éppen ezeknél a nyelvi elemeknél adódik: ahány gyártó, annyiféle megvalósítás.
Az egyéb nyelvi elemek szemléltetésére álljon itt egy Sybase ASA SQL példa:
CREATE FUNCTION DigitsOnly(IN M_Nev VARCHAR(30))
RETURNS VARCHAR(30)
BEGIN
DECLARE M_Result VARCHAR(16);
DECLARE i INTEGER;
SET i = 1;
SET M_Result = '';
WHILE (i <= LENGTH(M_Nev)) LOOP
IF SUBSTR(M_Nev, i, 1) BETWEEN '0' AND '9' THEN
SET M_Result = M_Result + SUBSTR(M_Nev, i, 1)
END IF;
SET i = i + 1;
END LOOP;
IF m_Result = '' THEN
RETURN(Null)
ELSE
RETURN(M_Result)
END IF;
END;
A fenti függvény a bemenetére küldött szövegből csak a számjegyeket hagyja meg.
Jelentős különbségek az SQL megvalósítások között
Adattípusok
- Az Oracle rendszereiben nincs NUMERIC, helyette a NUMBER-t kell használni
- Az Oracle nem támogatja a VARCHAR-t, helyette a VARCHAR2-t javasolja
- Az Oracle nem támogatja a LONG VARCHAR-t, helyette a CLOB-ot javasolja
- Oracle-ben a DATE dátumot és időt is tartalmazhat, más rendszerekben ez csak dátum lehet
- Egyes megvalósításokban (pld. PostgreSQL) létezik általános típusú adat is (bytea), amelyben akármit és akármekkora terjedelemben tárolhatunk
- Némelyik rendszerben létezik a SMALLINT vagy az INTEGER típus is, mint szabványon kívüli elemek
- Van olyan rendszer, amiben a BOOL típust is megvalósították
Összekapcsolás
Az SQL kiszolgálók egy része támogatja a SELECT-FROM szakaszba írt összekapcsolási utasításokat, mások csak a SELECT-WHERE szakaszban fogadják el:
Összekapcsolás a SELECT-FROM-ban:
SELECT *
FROM Beteg KEY JOIN Lelet
Összekapcsolás a WHERE-ben:
SELECT *
FROM Beteg, Lelet
WHERE Beteg.ID = Lelet.BetegID
Keresés
Bizonyos SQL kiszolgálók gyors keresésnél csak a teljesen pontosan beírt keresőkérdésre találják meg a választ. Gondot kell fordítanunk a kis- és nagybetűkre, valamint az ékezetek helyes használatára (Oracle, Firebird, PostgreSQL).
Más SQL kiszolgálók képesek figyelmen kívül hagyni az ékezeteket és egyenrangúnak tekintik a kis- és nagybetűket a keresés során, ha ezt kérjük (Sybase ASE, Sybase ASA).
FROM nélküli SELECT
FROM nélküli SELECT utasításra példa:
SELECT SYSDATE
A fenti példa egyes SQL kiszolgálók esetében nem működik, mivel a FROM náluk kötelező nyelvi elem.
Ezért például az Oracle minden adatbázisában szerepelteti a DUAL táblát, amelynek egyetlen rekordja van. Így Oracle SQL-ben ezt kell írnunk:
SELECT SYSDATE FROM DUAL
Természetesen itt a DUAL tábla valódi tartalma lényegtelen.
Bármely adatbankban, ha számolási eredményekre kíváncsi a felhasználó, lehetséges egy dummy (vagy tetszőleges nevű) üres tábla létrehozása, majd ennek felhasználásaval aritmetikai műveletek végezhetők el. Példa:
create table dummy (teszt numeric)
insert into dummy values(0)
select (12+88)/3 from dummy
Jegyzetek
- ↑ SQL:2023 is out, 2023. június 1. (Hozzáférés: 2023. június 26.)
- ↑ ISO/IEC 9075-1:2011 - Information technology -- Database languages -- SQL -- Part 1: Framework (SQL/Framework). ISO. (Hozzáférés: 2017. január 17.)
- ↑ Az SQL nyelv alapjai, 2009. április 9. (Hozzáférés: 2012. június 14.)
- ↑ http://www.cs.bme.hu/dok/szeredi.html