Cîhana databasan demek dirêj ji hêla DBMS-yên têkildar ve, ku zimanê SQL bikar tînin, serdest e. Ji ber vê yekê ku guhertoyên derketine NoSQL têne gotin. Wan karî di vê sûkê de ji xwe re cîhek diyar bikin, lê DBMS-yên têkildar namirin, û berdewam dikin ku bi rengek çalak ji bo armancên xwe werin bikar anîn.
Di vê gotarê de ez dixwazim têgeha databasek fonksiyonel diyar bikim. Ji bo têgihiştinek çêtir, ez ê vê yekê bi berhevdana wê bi modela têkiliya klasîk re bikim. Pirsgirêkên ji ceribandinên SQL yên cihêreng ên li ser Înternetê têne dîtin dê wekî mînak werin bikar anîn.
Pîrozbahiyê
Databasên peywendîdar li ser tablo û zeviyan dixebitin. Di danegehek fonksiyonel de, dê li şûna wan ders û fonksiyon werin bikar anîn. Zeviyek di tabloyek bi N bişkokan de dê wekî fonksiyonek N parametreyan were destnîşan kirin. Li şûna têkiliyên di navbera tabloyan de, fonksiyonên ku tiştên çîna ku pêwendiya pê re tê çêkirin vedigerînin dê werin bikar anîn. Dê li şûna JOIN kompozîsyona fonksiyonê were bikar anîn.
Berî ku rasterast derbasî peywiran bibe, ez ê peywira mantiqa domainê diyar bikim. Ji bo DDL ez ê hevoksaziya PostgreSQL bikar bînim. Ji bo fonksiyonel, hevoksaziya wê heye.
Tablo û zeviyan
Tiştek Sku ya hêsan a bi nav û qadên bihayê:
Relational
CREATE TABLE Sku
(
id bigint NOT NULL,
name character varying(100),
price numeric(10,5),
CONSTRAINT id_pkey PRIMARY KEY (id)
)
Fonksiyonel
CLASS Sku;
name = DATA STRING[100] (Sku);
price = DATA NUMERIC[10,5] (Sku);
Em du diyar dikin fonksiyonên, ku yek parametreyek Sku wekî têketinê digire û celebek primitive vedigerîne.
Tê texmîn kirin ku di DBMSek fonksiyonel de her tişt dê kodek hundurîn hebe ku bixweber tête çêkirin û heke hewce be dikare were gihîştin.
Ka em bihayê hilber / firotgeh / dabînker destnîşan bikin. Dibe ku ew bi demê re biguhere, ji ber vê yekê em qada demê li tabloyê zêde bikin. Ez ê ji danûstendina tabloyên ji bo pelrêçan di databasek pêwendiyê de derbas bikim da ku kodê kurt bikim:
Relational
CREATE TABLE prices
(
skuId bigint NOT NULL,
storeId bigint NOT NULL,
supplierId bigint NOT NULL,
dateTime timestamp without time zone,
price numeric(10,5),
CONSTRAINT prices_pkey PRIMARY KEY (skuId, storeId, supplierId)
)
Fonksiyonel
CLASS Sku;
CLASS Store;
CLASS Supplier;
dateTime = DATA DATETIME (Sku, Store, Supplier);
price = DATA NUMERIC[10,5] (Sku, Store, Supplier);
Indexes
Ji bo nimûneya paşîn, em ê li ser hemî kilîtan û tarîxê pêdekek ava bikin da ku em zû zû bihayê ji bo demek taybetî bibînin.
Relational
CREATE INDEX prices_date
ON prices
(skuId, storeId, supplierId, dateTime)
Fonksiyonel
INDEX Sku sk, Store st, Supplier sp, dateTime(sk, st, sp);
erkên
Ka em bi pirsgirêkên nisbeten hêsan ên ku ji yên têkildar hatine girtin dest pê bikin
Pêşîn, bila em mantiqa domainê ragihînin (ji bo databasa têkildar ev rasterast di gotara jorîn de tête kirin).
CLASS Department;
name = DATA STRING[100] (Department);
CLASS Employee;
department = DATA Department (Employee);
chief = DATA Employee (Employee);
name = DATA STRING[100] (Employee);
salary = DATA NUMERIC[14,2] (Employee);
Kar 1.1
Navnîşek karmendên ku meaşek ji ya serpereştiya xwe ya tavilê mezintir distînin nîşan bidin.
Relational
select a.*
from employee a, employee b
where b.id = a.chief_id
and a.salary > b.salary
Fonksiyonel
SELECT name(Employee a) WHERE salary(a) > salary(chief(a));
Kar 1.2
Karmendên ku di beşa xwe de mûçeya herî zêde digirin navnîş bikin
Relational
select a.*
from employee a
where a.salary = ( select max(salary) from employee b
where b.department_id = a.department_id )
Fonksiyonel
maxSalary 'Максимальная зарплата' (Department s) =
GROUP MAX salary(Employee e) IF department(e) = s;
SELECT name(Employee a) WHERE salary(a) = maxSalary(department(a));
// или если "заинлайнить"
SELECT name(Employee a) WHERE
salary(a) = maxSalary(GROUP MAX salary(Employee e) IF department(e) = department(a));
Her du pêkanîn jî wekhev in. Ji bo doza yekem, di databasek pêwendiyê de hûn dikarin CREATE VIEW bikar bînin, ku bi heman rengî dê pêşî meaşê herî zêde ji bo dezgehek taybetî ya tê de hesab bike. Di tiştê jêrîn de, ji bo zelaliyê, ez ê doza yekem bikar bînim, ji ber ku ew çareseriyê çêtir nîşan dide.
Kar 1.3
Navnîşek nasnameyên beşê nîşan bidin, ku hejmara karmendan ji 3 kesan derbas nabe.
Relational
select department_id
from employee
group by department_id
having count(*) <= 3
Fonksiyonel
countEmployees 'Количество сотрудников' (Department d) =
GROUP SUM 1 IF department(Employee e) = d;
SELECT Department d WHERE countEmployees(d) <= 3;
Kar 1.4
Navnîşek karmendên ku ne xwediyê rêveberek destnîşankirî ne ku di heman beşê de dixebitin nîşan bidin.
Relational
select a.*
from employee a
left join employee b on (b.id = a.chief_id and b.department_id = a.department_id)
where b.id is null
Fonksiyonel
SELECT name(Employee a) WHERE NOT (department(chief(a)) = department(a));
Kar 1.5
Navnîşek nasnameyên beşê bi mûçeya karmendê ya herî zêde bibînin.
Relational
with sum_salary as
( select department_id, sum(salary) salary
from employee
group by department_id )
select department_id
from sum_salary a
where a.salary = ( select max(salary) from sum_salary )
Fonksiyonel
salarySum 'Максимальная зарплата' (Department d) =
GROUP SUM salary(Employee e) IF department(e) = d;
maxSalarySum 'Максимальная зарплата отделов' () =
GROUP MAX salarySum(Department d);
SELECT Department d WHERE salarySum(d) = maxSalarySum();
Werin em ji yekî din derbasî karên tevlihevtir bibin
Kar 2.1
Kîjan firoşkaran di sala 1997an de zêdetirî 30 yekîneyên berhema No.
Mantiqa domainê (wek berê li ser RDBMS em danezanê berdidin):
CLASS Employee 'Продавец';
lastName 'Фамилия' = DATA STRING[100] (Employee);
CLASS Product 'Продукт';
id = DATA INTEGER (Product);
name = DATA STRING[100] (Product);
CLASS Order 'Заказ';
date = DATA DATE (Order);
employee = DATA Employee (Order);
CLASS Detail 'Строка заказа';
order = DATA Order (Detail);
product = DATA Product (Detail);
quantity = DATA NUMERIC[10,5] (Detail);
Relational
select LastName
from Employees as e
where (
select sum(od.Quantity)
from [Order Details] as od
where od.ProductID = 1 and od.OrderID in (
select o.OrderID
from Orders as o
where year(o.OrderDate) = 1997 and e.EmployeeID = o.EmployeeID)
) > 30
Fonksiyonel
sold (Employee e, INTEGER productId, INTEGER year) =
GROUP SUM quantity(OrderDetail d) IF
employee(order(d)) = e AND
id(product(d)) = productId AND
extractYear(date(order(d))) = year;
SELECT lastName(Employee e) WHERE sold(e, 1, 1997) > 30;
Kar 2.2
Ji bo her kiriyarekî (nav, paşnav), du tiştên (nav) ku kiryar di sala 1997-an de herî zêde pere li ser xerc kiriye bibînin.
Em mantiqa domainê ji mînaka berê dirêj dikin:
CLASS Customer 'Клиент';
contactName 'ФИО' = DATA STRING[100] (Customer);
customer = DATA Customer (Order);
unitPrice = DATA NUMERIC[14,2] (Detail);
discount = DATA NUMERIC[6,2] (Detail);
Relational
SELECT ContactName, ProductName FROM (
SELECT c.ContactName, p.ProductName
, ROW_NUMBER() OVER (
PARTITION BY c.ContactName
ORDER BY SUM(od.Quantity * od.UnitPrice * (1 - od.Discount)) DESC
) AS RatingByAmt
FROM Customers c
JOIN Orders o ON o.CustomerID = c.CustomerID
JOIN [Order Details] od ON od.OrderID = o.OrderID
JOIN Products p ON p.ProductID = od.ProductID
WHERE YEAR(o.OrderDate) = 1997
GROUP BY c.ContactName, p.ProductName
) t
WHERE RatingByAmt < 3
Fonksiyonel
sum (Detail d) = quantity(d) * unitPrice(d) * (1 - discount(d));
bought 'Купил' (Customer c, Product p, INTEGER y) =
GROUP SUM sum(Detail d) IF
customer(order(d)) = c AND
product(d) = p AND
extractYear(date(order(d))) = y;
rating 'Рейтинг' (Customer c, Product p, INTEGER y) =
PARTITION SUM 1 ORDER DESC bought(c, p, y), p BY c, y;
SELECT contactName(Customer c), name(Product p) WHERE rating(c, p, 1997) < 3;
Operatorê PARTITION li ser prensîba jêrîn dixebite: ew îfadeya ku piştî SUM (li vir 1) hatî destnîşan kirin berhev dike, di nav komên diyarkirî de (li vir Xerîdar û Sal, lê dibe ku her bêjeyek be), di nav koman de li gorî bêjeyên ku di ORDER de hatine destnîşankirin ( li vir kirî, û heke wekhev be, wê hingê li gorî koda hilberê hundurîn).
Kar 2.3
Ji bo bicihanîna fermanên heyî çend tişt hewce ne ku ji dabînkeran werin ferman kirin.
Ka em dîsa mantiqa domainê berfireh bikin:
CLASS Supplier 'Поставщик';
companyName = DATA STRING[100] (Supplier);
supplier = DATA Supplier (Product);
unitsInStock 'Остаток на складе' = DATA NUMERIC[10,3] (Product);
reorderLevel 'Норма продажи' = DATA NUMERIC[10,3] (Product);
Relational
select s.CompanyName, p.ProductName, sum(od.Quantity) + p.ReorderLevel — p.UnitsInStock as ToOrder
from Orders o
join [Order Details] od on o.OrderID = od.OrderID
join Products p on od.ProductID = p.ProductID
join Suppliers s on p.SupplierID = s.SupplierID
where o.ShippedDate is null
group by s.CompanyName, p.ProductName, p.UnitsInStock, p.ReorderLevel
having p.UnitsInStock < sum(od.Quantity) + p.ReorderLevel
Fonksiyonel
orderedNotShipped 'Заказано, но не отгружено' (Product p) =
GROUP SUM quantity(OrderDetail d) IF product(d) = p;
toOrder 'К заказу' (Product p) = orderedNotShipped(p) + reorderLevel(p) - unitsInStock(p);
SELECT companyName(supplier(Product p)), name(p), toOrder(p) WHERE toOrder(p) > 0;
Pirsgirêka stêrkek
Û mînaka dawî ji min bi xwe ye. Mantiqa tora civakî heye. Mirov dikarin bi hev re bibin dost û ji hev hez bikin. Ji perspektîfa databasa fonksiyonel ew ê bi vî rengî xuya bike:
CLASS Person;
likes = DATA BOOLEAN (Person, Person);
friends = DATA BOOLEAN (Person, Person);
Pêdivî ye ku ji bo hevaltiyê namzetên mimkun bibînin. Bi awayekî fermî, hûn hewce ne ku hemî mirovên A, B, C bibînin ku A bi B re heval e, û B bi C re heval e, A ji C hez dike, lê A ne hevalê C ye.
Ji perspektîfek databasa fonksiyonel, pirs dê wiha xuya bike:
SELECT Person a, Person b, Person c WHERE
likes(a, c) AND NOT friends(a, c) AND
friends(a, b) AND friends(b, c);
Xwendevan tê teşwîq kirin ku bi serê xwe vê pirsgirêkê di SQL de çareser bike. Tê texmîn kirin ku hevalên ku hûn jê hez dikin pir hindiktir in. Ji ber vê yekê ew di tabloyên cuda de ne. Ger serketî be, peywirek bi du stêrkan jî heye. Di wê de, hevaltî ne simetrîk e. Li ser databasek fonksiyonel ew ê bi vî rengî xuya bike:
SELECT Person a, Person b, Person c WHERE
likes(a, c) AND NOT friends(a, c) AND
(friends(a, b) OR friends(b, a)) AND
(friends(b, c) OR friends(c, b));
UPD: çareseriya pirsgirêkê bi stêrka yekem û duyemîn ji
SELECT
pl.PersonAID
,pf.PersonAID
,pff.PersonAID
FROM Persons AS p
--Лайки
JOIN PersonRelationShip AS pl ON pl.PersonAID = p.PersonID
AND pl.Relation = 'Like'
--Друзья
JOIN PersonRelationShip AS pf ON pf.PersonAID = p.PersonID
AND pf.Relation = 'Friend'
--Друзья Друзей
JOIN PersonRelationShip AS pff ON pff.PersonAID = pf.PersonBID
AND pff.PersonBID = pl.PersonBID
AND pff.Relation = 'Friend'
--Ещё не дружат
LEFT JOIN PersonRelationShip AS pnf ON pnf.PersonAID = p.PersonID
AND pnf.PersonBID = pff.PersonBID
AND pnf.Relation = 'Friend'
WHERE pnf.PersonAID IS NULL
;WITH PersonRelationShipCollapsed AS (
SELECT pl.PersonAID
,pl.PersonBID
,pl.Relation
FROM #PersonRelationShip AS pl
UNION
SELECT pl.PersonBID AS PersonAID
,pl.PersonAID AS PersonBID
,pl.Relation
FROM #PersonRelationShip AS pl
)
SELECT
pl.PersonAID
,pf.PersonBID
,pff.PersonBID
FROM #Persons AS p
--Лайки
JOIN PersonRelationShipCollapsed AS pl ON pl.PersonAID = p.PersonID
AND pl.Relation = 'Like'
--Друзья
JOIN PersonRelationShipCollapsed AS pf ON pf.PersonAID = p.PersonID
AND pf.Relation = 'Friend'
--Друзья Друзей
JOIN PersonRelationShipCollapsed AS pff ON pff.PersonAID = pf.PersonBID
AND pff.PersonBID = pl.PersonBID
AND pff.Relation = 'Friend'
--Ещё не дружат
LEFT JOIN PersonRelationShipCollapsed AS pnf ON pnf.PersonAID = p.PersonID
AND pnf.PersonBID = pff.PersonBID
AND pnf.Relation = 'Friend'
WHERE pnf.[PersonAID] IS NULL
encamê
Divê were zanîn ku hevoksaziya zimanê hatî dayîn tenê yek ji vebijarkên pêkanîna têgîna hatî dayîn e. SQL wekî bingeh hate girtin, û armanc ew bû ku ew bi qasî ku pêkan dişibihe wê. Bê guman, dibe ku hin ji navên keywords, tomarên peyvan, hwd hez nekin. Ya sereke li vir têgîn bixwe ye. Ger bixwaze, hûn dikarin hem C++ û hem jî Python hevoksaziya wekhev bikin.
Têgeha databasa diyarkirî, li gorî min, avantajên jêrîn hene:
- sivikî. Ev nîşanek nisbeten subjektîf e ku di rewşên hêsan de ne diyar e. Lê heke hûn li dozên tevlihevtir binêrin (mînak, pirsgirêkên bi stêrkan), wê hingê, bi dîtina min, nivîsandina pirsên weha pir hêsantir e.
- Încîl. Di hin mînakan de min fonksiyonên navîn diyar kirin (mînak, firotin, kirrîn hwd.), ji kîjan fonksiyonên paşîn hatine çêkirin. Ev dihêle hûn mentiqê hin fonksiyonan biguhezînin, ger hewce be, bêyî guheztina mantiqa yên ku bi wan ve girêdayî ne. Mînakî, hûn dikarin firotanê bikin firotin ji tiştên bi tevahî cûda hatine hesibandin, dema ku mantiqê mayî nayê guhertin. Erê, ev dikare di RDBMS-ê de bi karanîna CREATE VIEW ve were bicîh kirin. Lê eger hemû mantiq bi vî awayî were nivîsandin, ew ê pir xweş neyê xwendin.
- Xala semantîk tune. Databasek wusa li ser fonksiyon û çînan (li şûna tablo û qadan) dixebite. Mîna di bernamesaziya klasîk de (heke em bihesibînin ku rêbazek fonksiyonek bi parametreya yekem e di forma çîna ku tê de ye). Li gorî vê yekê, divê bi zimanên bernamesaziya gerdûnî re "hevaltiya" pir hêsantir be. Wekî din, ev têgeh dihêle ku fonksiyonek pir tevlihevtir were bicîh kirin. Mînakî, hûn dikarin operatorên mîna:
CONSTRAINT sold(Employee e, 1, 2019) > 100 IF name(e) = 'Петя' MESSAGE 'Что-то Петя продает слишком много одного товара в 2019 году';
- Mîrasbûn û polymorphism. Di databasek fonksiyonel de, hûn dikarin bi navgîniya CLASS ClassP-ya mîrata pirjimar bidin nasîn: Class1, Class2 pirmorfîzma pirjimar ava dike û bicîh tîne. Ez ê belkî di gotarên pêşerojê de bi rastî çawa binivîsim.
Her çend ev tenê têgehek e, jixwe me di Java de hin pêkanînek heye ku hemî mantiqa fonksiyonel werdigerîne mantiqa pêwendiyê. Zêdeyî, mantiqa nûnertiyê û gelek tiştên din bi xweşikî pê ve girêdayî ne, bi saya wan em tevahiyek digirin
Source: www.habr.com