DBMS funcional

El mundo de las bases de datos ha sido capturado por DBMS relacionales que usan el lenguaje SQL. Tanto es así que las especies emergentes se llaman NoSQL. Se las arreglaron para ocupar cierto lugar en este mercado, pero los DBMS relacionales no van a morir, y continúan utilizándose activamente para sus fines.

En este artículo quiero describir el concepto de una base de datos funcional. Para una mejor comprensión, haré esto comparándolo con el modelo relacional clásico. Como ejemplos, se utilizarán tareas de varias pruebas SQL encontradas en Internet.

Introduccion


Las bases de datos relacionales operan en tablas y campos. En la base de datos funcional, se utilizarán clases y funciones en su lugar. Se presentará un campo en una tabla con N teclas en función de N parámetros. En lugar de relaciones entre tablas, se utilizarán funciones que devuelven objetos de la clase que se está vinculando. En lugar de la función JOIN se utilizará la composición.

Antes de continuar directamente con las tareas, describiré la tarea de la lógica de dominio. Para DDL, usaré la sintaxis de PostgreSQL. Para funcional, su propia sintaxis.

Tablas y Campos


Objeto Sku simple con nombre de campo y precio:

Relacional

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, .

, , , .

/ / . , . , :



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


ID , 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


ID .



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?

( ):
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, 11997) > 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), ( Customer Year, ), , ORDER ( bought, , ).

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_kalika:
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 .

, :

  • . , . (, ), , , .
  • . (, sold, bought ..), . . , , sold , . , CREATE VIEW. , .
  • . ( ). , ( , — , ). , «» . , . , :
    CONSTRAINT sold(Employee e, 12019) > 100 IF name(e) = '' MESSAGE  '-        2019 ';

  • . CLASS ClassP: Class1, Class2 . , .

, , Java, . , . , ( PostgreSQL) « ». , , . , , , .

Source: https://habr.com/ru/post/458774/


All Articles