فعال DBMS

د ډیټابیس نړۍ له اوږدې مودې راهیسې د اړونده DBMSs تسلط لري ، کوم چې د SQL ژبه کاروي. تر دې حده چې راپورته کیدونکي ډولونه د NoSQL په نوم یادیږي. دوی په دې بازار کې د ځان لپاره یو ټاکلی ځای رامینځته کړی، مګر اړونده DBMSs نه مري، او د خپلو موخو لپاره په فعاله توګه کارول کیږي.

پدې مقاله کې زه غواړم د فعال ډیټابیس مفهوم تشریح کړم. د ښه پوهیدو لپاره، زه به دا د کلاسیک اړونده ماډل سره پرتله کړم. په انټرنیټ کې موندل شوي د مختلف SQL ازموینو ستونزې به د مثال په توګه وکارول شي.

پېژندنه

اړونده ډیټابیسونه په میزونو او ساحو کې کار کوي. په فعال ډیټابیس کې، ټولګي او دندې به په ترتیب سره وکارول شي. د N کیلي سره په جدول کې یوه ساحه به د N پیرامیټرو د فعالیت په توګه ښودل کیږي. د جدولونو تر مینځ د اړیکو پرځای، افعال به وکارول شي چې د ټولګي توکي بیرته راولي چې اړیکه جوړه شوې. د فعالیت ترکیب به د JOIN پرځای وکارول شي.

مخکې له دې چې مستقیم دندو ته لاړ شم، زه به د ډومین منطق دنده تشریح کړم. د DDL لپاره زه به د PostgreSQL ترکیب وکاروم. د فعالیت لپاره دا خپل ترکیب لري.

میزونه او ساحې

د نوم او قیمت ساحو سره یو ساده Sku اعتراض:

اړونده

CREATE TABLE Sku
(
    id bigint NOT NULL,
    name character varying(100),
    price numeric(10,5),
    CONSTRAINT id_pkey PRIMARY KEY (id)
)

فعال

CLASS Sku;
name = DATA STRING[100] (Sku);
price = DATA NUMERIC[10,5] (Sku);

موږ دوه اعلان کوو دندې، کوم چې یو پیرامیټر Sku د ننوتلو په توګه اخلي او یو ابتدايي ډول بیرته راولي.

داسې انګیرل کیږي چې په فعال DBMS کې هر اعتراض به یو څه داخلي کوډ ولري چې په اوتومات ډول رامینځته کیږي او د اړتیا په صورت کې لاسرسی کیدی شي.

راځئ چې د محصول / پلورنځي / عرضه کونکي لپاره نرخ وټاکو. دا ممکن د وخت په تیریدو سره بدلون ومومي، نو راځئ چې میز ته د وخت ساحه اضافه کړو. زه به د کوډ لنډولو لپاره په اړوند ډیټابیس کې د لارښودونو لپاره د جدولونو اعلان کول پریږدم:

اړونده

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)
)

فعال

CLASS Sku;
CLASS Store;
CLASS Supplier;
dateTime = DATA DATETIME (Sku, Store, Supplier);
price = DATA NUMERIC[10,5] (Sku, Store, Supplier);

لیګونه

د وروستي مثال لپاره، موږ به په ټولو کلیدونو او نیټې کې یو شاخص جوړ کړو ترڅو موږ ژر تر ژره د یو ځانګړي وخت لپاره نرخ ومومئ.

اړونده

CREATE INDEX prices_date
    ON prices
    (skuId, storeId, supplierId, dateTime)

فعال

INDEX Sku sk, Store st, Supplier sp, dateTime(sk, st, sp);

دندې

راځئ چې د اړوند څخه اخیستل شوي نسبتا ساده ستونزو سره پیل وکړو مقالې په هابر کې

لومړی، راځئ چې د ډومین منطق اعلان کړو (د اړونده ډیټابیس لپاره دا په مستقیمه مقاله کې ترسره کیږي).

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);

دنده 1.1

د کارمندانو لیست ښکاره کړئ چې د خپل سمدستي څارونکي څخه ډیر معاش ترلاسه کوي.

اړونده

select a.*
from   employee a, employee b
where  b.id = a.chief_id
and    a.salary > b.salary

فعال

SELECT name(Employee a) WHERE salary(a) > salary(chief(a));

دنده 1.2

هغه کارمندان لیست کړئ چې په خپله څانګه کې اعظمي معاش ترلاسه کوي

اړونده

select a.*
from   employee a
where  a.salary = ( select max(salary) from employee b
                    where  b.department_id = a.department_id )

فعال

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));

دواړه تطبیقونه مساوي دي. د لومړۍ قضیې لپاره ، په اړوند ډیټابیس کې تاسو کولی شئ CREATE VIEW وکاروئ ، کوم چې په ورته ډول به لومړی په دې کې د یوې ځانګړې څانګې لپاره اعظمي معاش محاسبه کړي. په لاندې څه کې، د وضاحت لپاره، زه به لومړی قضیه وکاروم، ځکه چې دا د حل حل غوره کوي.

دنده 1.3

د ډیپارټمنټ IDs لیست ښکاره کړئ، د کارمندانو شمیر چې د 3 کسانو څخه ډیر نه وي.

اړونده

select department_id
from   employee
group  by department_id
having count(*) <= 3

فعال

countEmployees 'Количество сотрудников' (Department d) = 
    GROUP SUM 1 IF department(Employee e) = d;
SELECT Department d WHERE countEmployees(d) <= 3;

دنده 1.4

د هغو کارمندانو لیست ښکاره کړئ چې په ورته څانګه کې د کار لپاره ټاکل شوی مدیر نلري.

اړونده

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

فعال

SELECT name(Employee a) WHERE NOT (department(chief(a)) = department(a));

دنده 1.5

د ډیپارټمنټ IDs لیست ومومئ چې د کارمندانو اعظمي معاش سره.

اړونده

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 )

فعال

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();

راځئ چې له بل څخه ډیرو پیچلو کارونو ته لاړ شو مقالې. دا په MS SQL کې د دې دندې پلي کولو څرنګوالي تفصيلي تحلیل لري.

دنده 2.1

کوم پلورونکي په 1997 کې د محصول نمبر 30 له 1 واحدونو څخه ډیر پلورلي؟

د ډومین منطق (لکه څنګه چې مخکې په RDBMS کې موږ اعلامیه پریږدو):

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);

اړونده

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

فعال

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;

دنده 2.2

د هر پیرودونکي لپاره (نوم، تخلص)، هغه دوه توکي (نوم) ومومئ کوم چې پیرودونکي په 1997 کې ډیرې پیسې مصرف کړې.

موږ د پخوانی مثال څخه د ډومین منطق پراخوو:

CLASS Customer 'Клиент';
contactName 'ФИО' = DATA STRING[100] (Customer);

customer = DATA Customer (Order);

unitPrice = DATA NUMERIC[14,2] (Detail);
discount = DATA NUMERIC[6,2] (Detail);

اړونده

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

فعال

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;

د PARTITION آپریټر په لاندې اصولو کار کوي: دا د SUM (دلته 1) څخه وروسته مشخص شوي بیان راټولوي، په ټاکل شوي ګروپونو کې (دلته پیرودونکي او کال، مګر کیدای شي هر ډول بیان وي)، په ګروپونو کې د ORDER کې مشخص شوي بیانونو سره ترتیب کول ( دلته اخیستل شوي، او که مساوي وي، بیا د داخلي محصول کوډ سره سم).

دنده 2.3

د اوسني امرونو پوره کولو لپاره د عرضه کونکو څخه څومره توکو ته اړتیا ده.

راځئ چې د ډومین منطق بیا پراخ کړو:

CLASS Supplier 'Поставщик';
companyName = DATA STRING[100] (Supplier);

supplier = DATA Supplier (Product);

unitsInStock 'Остаток на складе' = DATA NUMERIC[10,3] (Product);
reorderLevel 'Норма продажи' = DATA NUMERIC[10,3] (Product);

اړونده

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

فعال

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;

د ستوري سره ستونزه

او وروستی مثال یې زما په شخصي توګه دی. د ټولنیز شبکې منطق شتون لري. خلک کولی شي د یو بل سره ملګري وي او یو بل خوښوي. د فعال ډیټابیس لید څخه دا به داسې ښکاري:

CLASS Person;
likes = DATA BOOLEAN (Person, Person);
friends = DATA BOOLEAN (Person, Person);

دا اړینه ده چې د ملګرتیا لپاره احتمالي نوماندان ومومئ. په رسمي توګه، تاسو اړتیا لرئ چې ټول خلک د A، B، C سره داسې ومومئ چې A د B سره ملګري وي، او B د C سره ملګري وي، A د C سره مینه لري، مګر A د C سره ملګري ندي.
د فعال ډیټابیس لید څخه، پوښتنه به داسې ښکاري:

SELECT Person a, Person b, Person c WHERE 
    likes(a, c) AND NOT friends(a, c) AND 
    friends(a, b) AND friends(b, c);

لوستونکی هڅول کیږي چې دا ستونزه پخپله په SQL کې حل کړي. داسې انګیرل کیږي چې ستاسو د خوښې خلکو په پرتله ډیر لږ ملګري شتون لري. له همدې امله دوی په جلا جدولونو کې دي. که بریالی وي، د دوو ستورو سره هم دنده لري. په دې کې، ملګرتیا همغږي نه ده. په فعال ډیټابیس کې دا به داسې ښکاري:

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: د لومړي او دوهم ستوري سره د ستونزې حل dss_کالیکا:

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 

پایلې

دا باید په یاد ولرئ چې د ورکړل شوي ژبې ترکیب یوازې د ورکړل شوي مفهوم پلي کولو لپاره یو له انتخابونو څخه دی. SQL د اساس په توګه اخیستل شوی و، او موخه یې دا وه چې د امکان تر حده ورته ورته وي. البته، ځینې ممکن د کلیمو نومونه، د کلمو راجستر، او نور نه خوښوي. دلته اصلي شی پخپله مفهوم دی. که وغواړئ، تاسو کولی شئ دواړه C++ او Python ورته ترکیب جوړ کړئ.

د تشریح شوي ډیټابیس مفهوم، زما په نظر، لاندې ګټې لري:

  • تسکين. دا یو نسبتا تابع شاخص دی چې په ساده قضیو کې څرګند ندی. مګر که تاسو ډیر پیچلي قضیې وګورئ (د بیلګې په توګه، د ستوري سره ستونزې)، نو زما په اند، د داسې پوښتنو لیکل خورا اسانه دي.
  • اندونېزیايي. په ځینو مثالونو کې ما منځمهاله افعال اعلان کړل (د مثال په توګه، پلورل شوی, اخیستل شوي وغيره)، له کوم څخه چې وروسته دندې جوړې شوې. دا تاسو ته اجازه درکوي د ځانګړو دندو منطق بدل کړئ، که اړتیا وي، پرته له دې چې د هغه منطق بدل کړي چې په دوی پورې اړه لري. د مثال په توګه، تاسو کولی شئ پلور جوړ کړئ پلورل شوی د بشپړ مختلف شیانو څخه محاسبه شوي، پداسې حال کې چې پاتې منطق به بدلون ونلري. هو، دا په RDBMS کې د CREATE VIEW په کارولو سره پلي کیدی شي. مګر که ټول منطق په دې ډول ولیکل شي، دا به د لوستلو وړ نه ښکاري.
  • هیڅ سیمانټیک تشه نشته. دا ډول ډیټابیس په دندو او ټولګیو کې کار کوي (د جدولونو او ساحو پرځای). لکه څنګه چې په کلاسیک پروګرام کولو کې (که موږ فرض کړو چې یو میتود د ټولګي په بڼه کې د لومړي پیرامیټر سره یو فنکشن دی چې دا تړاو لري). په دې اساس، دا باید د نړیوال پروګرام کولو ژبو سره "ملګري" کول خورا اسانه وي. سربیره پردې، دا مفهوم د پلي کولو لپاره خورا پیچلي فعالیت ته اجازه ورکوي. د مثال په توګه، تاسو کولی شئ چلونکي شامل کړئ لکه:

    CONSTRAINT sold(Employee e, 1, 2019) > 100 IF name(e) = 'Петя' MESSAGE  'Что-то Петя продает слишком много одного товара в 2019 году';

  • میراث او پولیمورفیزم. په فعال ډیټابیس کې، تاسو کولی شئ د CLASS ClassP له لارې ډیری میراث معرفي کړئ: کلاس 1، کلاس 2 ډیری پولیمورفیزم جوړوي او پلي کوي. زه به شاید په راتلونکو مقالو کې څنګه ولیکئ.

که څه هم دا یوازې یو مفهوم دی، موږ لا دمخه په جاوا کې یو څه تطبیق لرو چې ټول فعال منطق په اړونده منطق کې ژباړي. سربیره پردې ، د نمایشاتو منطق او ډیری نور شیان په ښکلي ډول دې سره وصل دي ، له دې امله موږ بشپړ ترلاسه کوو پلیټ فارم. په لازمي ډول ، موږ RDBMS (یوازې د اوس لپاره PostgreSQL) د "مجازی ماشین" په توګه کاروو. ځینې ​​وختونه ستونزې د دې ژباړې سره رامینځته کیږي ځکه چې د RDBMS پوښتنې اصلاح کونکی په ځانګړو احصایو نه پوهیږي چې FDBMS پوهیږي. په تیوري کې، دا ممکنه ده چې د ډیټابیس مدیریت سیسټم پلي کړي چې یو مشخص جوړښت به د ذخیره کولو په توګه وکاروي، په ځانګړې توګه د فعال منطق لپاره تطبیق شوی.

سرچینه: www.habr.com

Add a comment