DBMS funcional

O mundo dos bancos de dados há muito tempo é capturado por DBMSs relacionais que usam a linguagem SQL. Tanto é assim que as espécies emergentes são chamadas NoSQL. Eles conseguiram ocupar um certo lugar nesse mercado, mas os DBMSs relacionais não vão morrer e continuam sendo usados ​​ativamente para seus propósitos.

Neste artigo, quero descrever o conceito de um banco de dados funcional. Para uma melhor compreensão, farei isso comparando com o modelo relacional clássico. Como exemplos, serão utilizadas tarefas de vários testes SQL encontrados na Internet.

1. Introdução


Bancos de dados relacionais operam em tabelas e campos. No banco de dados funcional, classes e funções serão usadas. Um campo em uma tabela com N teclas será apresentado em função de N parâmetros. Em vez de relacionamentos entre tabelas, serão utilizadas funções que retornam objetos da classe que está sendo vinculada. Em vez de JOIN, a composição da função será usada.

Antes de prosseguir diretamente para as tarefas, descreverei a tarefa da lógica do domínio. Para DDL, usarei a sintaxe do PostgreSQL. Para funcional, sua própria sintaxe.

Tabelas e campos


Objeto simples de Sku com nome e preço dos campos:

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/pt458774/


All Articles