ڊيٽابيس جي دنيا ڊگھي عرصي کان لاڳاپي واري ڊي بي ايم ايس جي تسلط ڪئي وئي آهي، جيڪي SQL ٻولي استعمال ڪندا آهن. ايتري قدر جو اڀرندڙ مختلف قسمن کي NoSQL سڏيو ويندو آهي. انهن هن مارڪيٽ ۾ پاڻ لاءِ هڪ خاص جڳهه ٺاهي ورتي، پر لاڳاپو DBMS مرڻ وارا نه آهن، ۽ انهن جي مقصدن لاءِ فعال طور تي استعمال ٿيڻ جاري آهن.
هن آرٽيڪل ۾ آئون هڪ فنڪشنل ڊيٽابيس جي تصور کي بيان ڪرڻ چاهيان ٿو. بهتر سمجھڻ لاءِ، مان ان کي ڪلاسيڪل رشتي واري ماڊل سان ڀيٽ ڪريان ٿو. انٽرنيٽ تي مليا مختلف SQL ٽيسٽن جا مسئلا مثال طور استعمال ڪيا ويندا.
تعارف
لاڳاپو ڊيٽابيس ٽيبل ۽ فيلڊ تي ڪم ڪن ٿا. هڪ فنڪشنل ڊيٽابيس ۾، ڪلاس ۽ افعال استعمال ڪيا ويندا، ترتيب سان. N keys سان ٽيبل ۾ هڪ فيلڊ کي N پيرا ميٽرز جي فنڪشن طور پيش ڪيو ويندو. جدولن جي وچ ۾ لاڳاپن جي بدران، فنڪشن استعمال ڪيا ويندا جيڪي ڪلاس جون شيون واپس ڪن ٿا جن سان ڪنيڪشن ٺاهيو ويو آهي. JOIN جي بدران فنڪشن جوڙ استعمال ڪيو ويندو.
ڪمن ڏانهن سڌو وڃڻ کان اڳ، مان ڊومين منطق جي ڪم کي بيان ڪندس. DDL لاءِ مان استعمال ڪندس PostgreSQL نحو. فنڪشنل لاءِ ان جو پنهنجو نحو آهي.
ٽيبل ۽ ميدان
نالي ۽ قيمت جي شعبن سان هڪ سادي اسڪو اعتراض:
تعلقي
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);
اسان ٻه اعلان ڪريون ٿا ڪم، جيڪو هڪ پيٽرولر اسڪو کي ان پٽ طور وٺي ٿو ۽ هڪ ابتدائي قسم واپس ڪري ٿو.
اهو فرض ڪيو ويو آهي ته هڪ فنڪشنل ڊي بي ايم ايس ۾ هر اعتراض کي ڪجهه اندروني ڪوڊ هوندو جيڪو خودڪار طور تي ٺاهيل آهي ۽ ضروري هجي ته رسائي ڪري سگهجي ٿو.
اچو ته پراڊڪٽ/ اسٽور/ سپلائر لاءِ قيمت مقرر ڪريون. اهو وقت سان تبديل ٿي سگهي ٿو، تنهنڪري اچو ته ٽيبل تي هڪ ٽائيم فيلڊ شامل ڪريو. مان ڪوڊ کي مختصر ڪرڻ لاءِ لاڳاپيل ڊيٽابيس ۾ ڊائريڪٽرن لاءِ جدولن جو اعلان ڪرڻ ڇڏي ڏيندس:
تعلقي
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();
اچو ته ٻئي کان وڌيڪ پيچيده ڪمن ڏانهن وڃو
ڪم 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: مسئلي جو حل پهرين ۽ سيڪنڊ اسٽرڪ سان
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++ ۽ پٿون هڪجهڙائي نحو.
بيان ڪيل ڊيٽابيس تصور، منهنجي خيال ۾، هيٺيان فائدا آهن:
- آسانيء. اهو هڪ نسبتا مضموني اشارو آهي جيڪو عام ڪيسن ۾ واضح ناهي. پر جيڪڏهن توهان وڌيڪ پيچيده ڪيسن تي نظر رکون ٿا (مثال طور، ستارن سان مسئلا)، پوء منهنجي خيال ۾، اهڙن سوالن کي لکڻ بلڪل آسان آهي.
- Инкапсуляция. ڪجھ مثالن ۾ مون وچولي افعال جو اعلان ڪيو (مثال طور، وڪرو ڪيو, خريد ڪيو وغيره)، جنهن مان ايندڙ فنڪشن ٺاهيا ويا. اهو توهان کي اجازت ڏئي ٿو ته ڪجهه ڪمن جي منطق کي تبديل ڪرڻ جي، جيڪڏهن ضروري هجي، انهن جي منطق کي تبديل ڪرڻ کان سواء جيڪي انهن تي منحصر آهن. مثال طور، توهان وڪرو ڪري سگهو ٿا وڪرو ڪيو مڪمل طور تي مختلف شين مان حساب ڪيو ويو، جڏهن ته باقي منطق تبديل نه ٿيندي. ها، اهو هڪ RDBMS ۾ لاڳو ڪري سگهجي ٿو CREATE VIEW استعمال ڪندي. پر جيڪڏهن سمورو منطق هن طرح لکيو وڃي ته اهو تمام گهڻو پڙهڻ لائق نظر نه ايندو.
- ڪوبه لفظي خال. اهڙو ڊيٽابيس ڪم ۽ طبقن تي هلندو آهي (جدول ۽ فيلڊ جي بدران). جيئن ته ڪلاسيڪل پروگرامنگ ۾ (جيڪڏهن اسان فرض ڪريون ته هڪ طريقو هڪ فنڪشن آهي جنهن ۾ پهرين پيراميٽر سان ڪلاس جي شڪل ۾ اهو تعلق رکي ٿو). ان جي مطابق، عالمي پروگرامنگ ٻولين سان ”دوست بڻائڻ“ تمام آسان ٿيڻ گھرجي. اضافي طور تي، هي تصور وڌيڪ پيچيده ڪارڪردگي کي لاڳو ڪرڻ جي اجازت ڏئي ٿو. مثال طور، توهان ايمبيڊ ڪري سگهو ٿا آپريٽرز جهڙوڪ:
CONSTRAINT sold(Employee e, 1, 2019) > 100 IF name(e) = 'Петя' MESSAGE 'Что-то Петя продает слишком много одного товара в 2019 году';
- وراثت ۽ پوليمورفيزم. هڪ فنڪشنل ڊيٽابيس ۾، توهان CLASS ClassP ذريعي ڪيترن ئي ورثي کي متعارف ڪرائي سگهو ٿا: ڪلاس 1، ڪلاس 2 ٺاهي ٿو ۽ ڪيترن ئي پوليمورفيزم کي لاڳو ڪري ٿو. مان شايد لکندس ته ڪيئن صحيح طور تي مستقبل جي مضمونن ۾.
جيتوڻيڪ اهو صرف هڪ تصور آهي، اسان وٽ اڳ ۾ ئي جاوا ۾ ڪجهه عمل درآمد آهي جيڪو سڀني فنڪشنل منطق کي لاڳاپي منطق ۾ ترجمو ڪري ٿو. ان سان گڏ، نمائندگي جي منطق ۽ ٻيون ڪيتريون ئي شيون خوبصورت طور تي ان سان ڳنڍيل آهن، جن جي مهرباني اسان کي مڪمل طور تي
جو ذريعو: www.habr.com