Skip to content

Instantly share code, notes, and snippets.

@thinkphp
Last active May 26, 2025 18:34
Show Gist options
  • Save thinkphp/2ac3a85dafed1b67c55e190531f0df6f to your computer and use it in GitHub Desktop.
Save thinkphp/2ac3a85dafed1b67c55e190531f0df6f to your computer and use it in GitHub Desktop.
Magazin ONLINE

PROIECT BAZE DE DATE: MAGAZIN ONLINE

Student: Estera Anul universitar: 2024-2025
Facultatea de Științe Economice
Universitatea "Lucian Blaga" din Sibiu


CUPRINS

  1. Introducere și Tema Aleasă
  2. Crearea Bazei de Date și Tabelelor
  3. Crearea Relațiilor între Tabele
  4. Interogări SQL
  5. Vederi
  6. Структuri de Control
  7. Proceduri Stocate
  8. Cursoare SQL
  9. Triggere
  10. Testare și Validare
  11. Concluzii

1. INTRODUCERE ȘI TEMA ALEASĂ

1.1 Descrierea Temei

Tema aleasă pentru acest proiect este "Magazin Online" - un sistem de management pentru un magazin de comerț electronic.

1.2 Scopul Proiectului

Sistemul dezvoltat permite gestionarea:

  • Clienților și profilurilor lor
  • Produselor și categoriilor
  • Comenzilor și detaliilor acestora
  • Plăților și metodelor de plată
  • Furnizorilor și relațiilor cu aceștia
  • Rapoartelor și statisticilor de vânzări

1.3 Structura Bazei de Date

Baza de date conține 8 tabele principale și 2 tabele suplimentare pentru logging și raportare, respectând toate cerințele proiectului.


2. CREAREA BAZEI DE DATE ȘI TABELELOR

2.1 Crearea Bazei de Date

Prima etapă a constat în crearea bazei de date utilizând comanda DDL:

CREATE DATABASE MagazinOnline;
GO
USE MagazinOnline;
GO

Captură ecran: Se afișează Object Browser cu baza de date "MagazinOnline" creată

2.2 Tabelele Create

2.2.1 Tabelul "Clienti"

CREATE TABLE Clienti (
    ID_Client INT PRIMARY KEY IDENTITY(1,1),
    Nume NVARCHAR(100) NOT NULL,
    Email NVARCHAR(100) UNIQUE NOT NULL,
    Data_Inscriere DATE DEFAULT GETDATE(),
    Tip_Client NVARCHAR(50) DEFAULT 'Standard',
    Telefon VARCHAR(20),
    Data_Nasterii DATE,
    Activ BIT DEFAULT 1,
    Scor_Fidelitate FLOAT DEFAULT 0.0,
    Adresa NVARCHAR(255)
);

Tipuri de date utilizate în tabelul Clienti:

  • INT - pentru cheia primară
  • NVARCHAR - pentru textul Unicode
  • VARCHAR - pentru telefon
  • DATE - pentru date calendaristice
  • BIT - pentru valori boolean
  • FLOAT - pentru numere cu virgulă mobilă

Proprietăți utilizate:

  • PRIMARY KEY - definește cheia primară
  • IDENTITY(1,1) - numerotare automată
  • NOT NULL - câmp obligatoriu
  • UNIQUE - valoare unică în tabel
  • DEFAULT - valoare implicită

2.2.2 Tabelul "Produse"

CREATE TABLE Produse (
    ID_Produs INT PRIMARY KEY IDENTITY(1,1),
    Denumire NVARCHAR(100) NOT NULL,
    Descriere NTEXT,
    Pret DECIMAL(10,2) NOT NULL CHECK (Pret > 0),
    Stoc INT DEFAULT 0 CHECK (Stoc >= 0),
    Categorie NVARCHAR(50) NOT NULL,
    Data_Adaugare DATETIME DEFAULT GETDATE(),
    Greutate REAL,
    Imagine VARBINARY(MAX),
    Cod_Produs CHAR(10) UNIQUE
);

Tipuri de date suplimentare:

  • NTEXT - pentru text lung Unicode
  • DECIMAL(10,2) - pentru prețuri cu 2 zecimale
  • DATETIME - pentru data și ora
  • REAL - pentru numere cu precizie simplă
  • VARBINARY(MAX) - pentru date binare (imagini)
  • CHAR(10) - pentru șiruri de lungime fixă

Proprietăți suplimentare:

  • CHECK - constrângeri de validare

2.2.3 Restul Tabelelor

Tabelele Comenzi, Detalii_Comanda, Plati, Furnizori, Produse_Furnizori și Profile_Clienti au fost create urmând aceleași principii, utilizând diverse tipuri de date și proprietăți SQL Server.

Captură ecran: Object Browser arătând toate tabelele create în secțiunea Tables


3. CREAREA RELAȚIILOR ÎNTRE TABELE

3.1 Tipuri de Relații Implementate

3.1.1 Relații One-to-Many

Relația Clienti → Comenzi:

FOREIGN KEY (ID_Client) REFERENCES Clienti(ID_Client)

Relația Comenzi → Detalii_Comanda:

FOREIGN KEY (ID_Comanda) REFERENCES Comenzi(ID_Comanda)

Relația Produse → Detalii_Comanda:

FOREIGN KEY (ID_Produs) REFERENCES Produse(ID_Produs)

3.1.2 Relația One-to-One

Relația Clienti → Profile_Clienti:

CREATE TABLE Profile_Clienti (
    ID_Client INT PRIMARY KEY,
    FOREIGN KEY (ID_Client) REFERENCES Clienti(ID_Client)
);

3.1.3 Relația Many-to-Many

Tabelul de legătură Produse_Furnizori:

CREATE TABLE Produse_Furnizori (
    ID_Produs INT,
    ID_Furnizor INT,
    PRIMARY KEY (ID_Produs, ID_Furnizor),
    FOREIGN KEY (ID_Produs) REFERENCES Produse(ID_Produs),
    FOREIGN KEY (ID_Furnizor) REFERENCES Furnizori(ID_Furnizor)
);

Captură ecran: Database Design view arătând relațiile vizuale între tabele

3.2 Avantajele Implementării Relațiilor

  • Integritatea referențială - asigură consistența datelor
  • Normalizarea datelor - elimină redundanța
  • Eficiența interogărilor - permite JOIN-uri eficiente

4. INTEROGĂRI SQL

Au fost create 25 de interogări care respectă toate cerințele proiectului:

4.1 Interogări de Selecție

4.1.1 Selecție Simplă cu WHERE și ORDER BY

SELECT Nume, Email, Tip_Client, Scor_Fidelitate
FROM Clienti
WHERE Scor_Fidelitate > 100
ORDER BY Scor_Fidelitate DESC;

Captură ecran: Rezultatul interogării arătând clienții cu scor mare de fidelitate

4.1.2 Interogare cu JOIN și Funcții de Agregare

SELECT c.Nume, COUNT(co.ID_Comanda) as Numar_Comenzi, SUM(co.Total) as Total_Cumparaturi
FROM Clienti c
LEFT JOIN Comenzi co ON c.ID_Client = co.ID_Client
GROUP BY c.ID_Client, c.Nume
HAVING COUNT(co.ID_Comanda) > 0
ORDER BY Total_Cumparaturi DESC;

Elemente utilizate:

  • LEFT JOIN - pentru a include toți clienții
  • GROUP BY - pentru gruparea rezultatelor
  • HAVING - filtrarea după grupare
  • COUNT(), SUM() - funcții de agregare

4.2 Interogări cu Subinterogări

4.2.1 Subinterogare în WHERE

SELECT Nume, Email, Tip_Client
FROM Clienti
WHERE ID_Client IN (
    SELECT ID_Client
    FROM Comenzi
    WHERE Total > (SELECT AVG(Total) FROM Comenzi)
);

4.2.2 Subinterogare Corelată

SELECT c.Nume, c.Email,
    (SELECT COUNT(*) 
     FROM Comenzi co 
     WHERE co.ID_Client = c.ID_Client AND co.Status = 'Livrata') as Comenzi_Livrate
FROM Clienti c
WHERE EXISTS (
    SELECT 1 
    FROM Comenzi co2 
    WHERE co2.ID_Client = c.ID_Client
);

4.3 Interogări cu Câmpuri Calculate

SELECT 
    p.Denumire,
    p.Pret,
    p.Stoc,
    (p.Pret * p.Stoc) as Valoare_Stoc,
    CASE 
        WHEN p.Stoc < 10 THEN 'Stoc mic'
        WHEN p.Stoc BETWEEN 10 AND 25 THEN 'Stoc mediu'
        ELSE 'Stoc mare'
    END as Nivel_Stoc
FROM Produse p
WHERE p.Stoc > 0
ORDER BY Valoare_Stoc DESC;

4.4 Funcții Text și Dată

4.4.1 Funcții Text

SELECT 
    UPPER(c.Nume) as Nume_Client,
    LOWER(p.Denumire) as Produs,
    SUBSTRING(co.Status, 1, 3) as Status_Scurt,
    LEFT(c.Email, CHARINDEX('@', c.Email) - 1) as Username
FROM Clienti c
JOIN Comenzi co ON c.ID_Client = co.ID_Client
JOIN Detalii_Comanda dc ON co.ID_Comanda = dc.ID_Comanda
JOIN Produse p ON dc.ID_Produs = p.ID_Produs;

Funcții text utilizate:

  • UPPER(), LOWER() - conversie majuscule/minuscule
  • SUBSTRING() - extragere substring
  • LEFT() - primele caractere
  • CHARINDEX() - găsirea poziției unui caracter

4.4.2 Funcții Dată

SELECT 
    ID_Comanda,
    Data_Comanda,
    YEAR(Data_Comanda) as An_Comanda,
    MONTH(Data_Comanda) as Luna_Comanda,
    DATEDIFF(day, Data_Comanda, GETDATE()) as Zile_De_La_Comanda
FROM Comenzi
WHERE Data_Comanda BETWEEN '2024-05-01' AND '2024-05-31';

Funcții dată utilizate:

  • YEAR(), MONTH() - extragere componente dată
  • DATEDIFF() - calculul diferenței între date
  • GETDATE() - data curentă
  • BETWEEN - interval de date

4.5 Operatori Speciali

4.5.1 LIKE și Wildcards

SELECT Nume, Email, Telefon
FROM Clienti
WHERE (Nume LIKE '%escu%' OR Email LIKE '%gmail%')
AND Telefon LIKE '07_1%'
ORDER BY Nume;

4.5.2 IN și EXISTS

SELECT p.Denumire, p.Pret, p.Categorie
FROM Produse p
WHERE EXISTS (
    SELECT 1
    FROM Detalii_Comanda dc
    JOIN Comenzi c ON dc.ID_Comanda = c.ID_Comanda
    WHERE dc.ID_Produs = p.ID_Produs
    AND c.Status = 'Livrata'
);

4.6 Interogări de Modificare

4.6.1 UPDATE cu Subinterogare

UPDATE Clienti 
SET Scor_Fidelitate = Scor_Fidelitate + 10
WHERE ID_Client IN (
    SELECT DISTINCT c.ID_Client
    FROM Clienti c
    JOIN Comenzi co ON c.ID_Client = co.ID_Client
    WHERE co.Status = 'Livrata'
);

4.6.2 DELETE Condițional

DELETE FROM Produse
WHERE Stoc = 0 AND ID_Produs NOT IN (
    SELECT DISTINCT ID_Produs
    FROM Detalii_Comanda
);

4.6.3 INSERT cu SELECT

INSERT INTO Profile_Clienti (ID_Client, Preferinte, Newsletter_Subscription)
SELECT ID_Client, 'Preferinte generale', 1
FROM Clienti
WHERE ID_Client NOT IN (SELECT ID_Client FROM Profile_Clienti);

4.7 MAKE TABLE (SELECT INTO)

SELECT 
    p.Categorie,
    COUNT(*) as Numar_Produse,
    AVG(p.Pret) as Pret_Mediu,
    SUM(dc.Cantitate) as Cantitate_Vanduta
INTO Raport_Categorii
FROM Produse p
LEFT JOIN Detalii_Comanda dc ON p.ID_Produs = dc.ID_Produs
GROUP BY p.Categorie;

Captură ecran: Object Browser arătând tabelul "Raport_Categorii" creat automat


5. VEDERI

Au fost create 3 vederi pentru abstractizarea și simplificarea accesului la date:

5.1 View_Clienti_Activi

CREATE VIEW View_Clienti_Activi AS
SELECT 
    c.ID_Client,
    c.Nume,
    c.Email,
    c.Tip_Client,
    c.Scor_Fidelitate,
    COUNT(co.ID_Comanda) as Total_Comenzi,
    COALESCE(SUM(co.Total), 0) as Total_Cumparaturi,
    MAX(co.Data_Comanda) as Ultima_Comanda
FROM Clienti c
LEFT JOIN Comenzi co ON c.ID_Client = co.ID_Client
WHERE c.Activ = 1
GROUP BY c.ID_Client, c.Nume, c.Email, c.Tip_Client, c.Scor_Fidelitate;

Captură ecran: Rezultatul SELECT * FROM View_Clienti_Activi

5.2 View_Produse_Populare

CREATE VIEW View_Produse_Populare AS
SELECT 
    p.ID_Produs,
    p.Denumire,
    p.Categorie,
    p.Pret,
    p.Stoc,
    COUNT(dc.ID_Detaliu) as Numar_Vanzari,
    SUM(dc.Cantitate) as Cantitate_Totala_Vanduta,
    AVG(dc.Pret_Unitar) as Pret_Mediu_Vanzare
FROM Produse p
JOIN Detalii_Comanda dc ON p.ID_Produs = dc.ID_Produs
GROUP BY p.ID_Produs, p.Denumire, p.Categorie, p.Pret, p.Stoc
HAVING COUNT(dc.ID_Detaliu) > 0;

5.3 View_Comenzi_Complete

CREATE VIEW View_Comenzi_Complete AS
SELECT 
    co.ID_Comanda,
    c.Nume as Nume_Client,
    c.Email as Email_Client,
    co.Data_Comanda,
    co.Status,
    co.Total,
    COUNT(dc.ID_Detaliu) as Numar_Produse,
    pl.Metoda as Metoda_Plata,
    pl.Status_Plata
FROM Comenzi co
JOIN Clienti c ON co.ID_Client = c.ID_Client
LEFT JOIN Detalii_Comanda dc ON co.ID_Comanda = dc.ID_Comanda
LEFT JOIN Plati pl ON co.ID_Comanda = pl.ID_Comanda
GROUP BY co.ID_Comanda, c.Nume, c.Email, co.Data_Comanda, co.Status, co.Total, pl.Metoda, pl.Status_Plata;

Avantajele vederilor:

  • Simplificarea interogărilor complexe
  • Securitate prin restricționarea accesului
  • Abstractizarea structurii bazei de date

6. STRUCTURI DE CONTROL

Au fost implementate 2 structuri de control:

6.1 Structura IF-ELSE

DECLARE @ID_Produs INT = 1;
DECLARE @Cantitate_Vanduta INT = 5;
DECLARE @Stoc_Actual INT;

SELECT @Stoc_Actual = Stoc FROM Produse WHERE ID_Produs = @ID_Produs;

IF @Stoc_Actual >= @Cantitate_Vanduta
BEGIN
    UPDATE Produse 
    SET Stoc = Stoc - @Cantitate_Vanduta 
    WHERE ID_Produs = @ID_Produs;
    PRINT 'Stoc actualizat cu succes';
END
ELSE
BEGIN
    PRINT 'Stoc insuficient pentru această tranzacție';
END

Captură ecran: Messages tab arătând rezultatul execuției

6.2 Structura WHILE cu Cursor

DECLARE @ID_Comanda_Process INT;
DECLARE @Total_Comanda DECIMAL(12,2);
DECLARE @Status_Vechi NVARCHAR(50);

DECLARE comenzi_cursor CURSOR FOR
SELECT ID_Comanda, Total, Status 
FROM Comenzi 
WHERE Status = 'Pending';

OPEN comenzi_cursor;
FETCH NEXT FROM comenzi_cursor INTO @ID_Comanda_Process, @Total_Comanda, @Status_Vechi;

WHILE @@FETCH_STATUS = 0
BEGIN
    IF @Total_Comanda > 1000
    BEGIN
        UPDATE Comenzi 
        SET Status = 'Confirmata' 
        WHERE ID_Comanda = @ID_Comanda_Process;
        PRINT 'Comanda ' + CAST(@ID_Comanda_Process AS VARCHAR) + ' confirmată automat (valoare mare)';
    END
    ELSE
    BEGIN
        UPDATE Comenzi 
        SET Status = 'In procesare' 
        WHERE ID_Comanda = @ID_Comanda_Process;
        PRINT 'Comanda ' + CAST(@ID_Comanda_Process AS VARCHAR) + ' în procesare';
    END
    
    FETCH NEXT FROM comenzi_cursor INTO @ID_Comanda_Process, @Total_Comanda, @Status_Vechi;
END

CLOSE comenzi_cursor;
DEALLOCATE comenzi_cursor;

7. PROCEDURI STOCATE

Au fost create 3 proceduri stocate:

7.1 sp_AdaugaComanda

CREATE PROCEDURE sp_AdaugaComanda
    @ID_Client INT,
    @Produse NVARCHAR(MAX), -- Format: 'ID_Produs:Cantitate,ID_Produs:Cantitate'
    @Adresa_Livrare NVARCHAR(255) = NULL,
    @Observatii NTEXT = NULL
AS
BEGIN
    SET NOCOUNT ON;
    
    DECLARE @ID_Comanda INT;
    DECLARE @Total DECIMAL(12,2) = 0;
    -- [Restul codului procedurii]
END;

Funcționalitate:

  • Validarea existenței clientului
  • Procesarea listei de produse
  • Verificarea stocului disponibil
  • Crearea comenzii și detaliilor
  • Actualizarea automată a stocului

Captură ecran: Rezultatul execuției EXEC sp_AdaugaComanda

7.2 sp_RaportVanzari

CREATE PROCEDURE sp_RaportVanzari
    @Data_Inceput DATE,
    @Data_Sfarsit DATE,
    @Categorie NVARCHAR(50) = NULL
AS
BEGIN
    SET NOCOUNT ON;
    
    SELECT 
        p.Categorie,
        p.Denumire,
        SUM(dc.Cantitate) as Cantitate_Vanduta,
        SUM(dc.Cantitate * dc.Pret_Unitar) as Venituri_Totale,
        AVG(dc.Pret_Unitar) as Pret_Mediu,
        COUNT(DISTINCT co.ID_Client) as Clienti_Unici
    FROM Produse p
    JOIN Detalii_Comanda dc ON p.ID_Produs = dc.ID_Produs
    JOIN Comenzi co ON dc.ID_Comanda = co.ID_Comanda
    WHERE co.Data_Comanda BETWEEN @Data_Inceput AND @Data_Sfarsit
    AND (@Categorie IS NULL OR p.Categorie = @Categorie)
    AND co.Status IN ('Confirmata', 'Livrata')
    GROUP BY p.Categorie, p.Denumire
    ORDER BY Venituri_Totale DESC;
END;

7.3 sp_ActualizeazaPreturi

CREATE PROCEDURE sp_ActualizeazaPreturi
    @Categorie NVARCHAR(50),
    @Procent_Modificare DECIMAL(5,2),
    @Aplicare_Efective BIT = 0 -- 0 = preview, 1 = aplicare
AS
BEGIN
    SET NOCOUNT ON;
    
    IF @Aplicare_Efective = 0
    BEGIN
        -- Preview modificări
        SELECT 
            ID_Produs,
            Denumire,
            Pret as Pret_Vechi,
            ROUND(Pret * (1 + @Procent_Modificare / 100), 2) as Pret_Nou,
            ROUND(Pret * @Procent_Modificare / 100, 2) as Diferenta
        FROM Produse
        WHERE Categorie = @Categorie;
    END
    ELSE
    BEGIN
        -- Aplicare modificări
        UPDATE Produse
        SET Pret = ROUND(Pret * (1 + @Procent_Modificare / 100), 2)
        WHERE Categorie = @Categorie;
    END
END;

Captură ecran: Object Browser → Stored Procedures arătând cele 3 proceduri create


8. CURSOARE SQL

Au fost implementate 2 cursoare:

8.1 Cursor pentru Actualizarea Scorului de Fidelitate

DECLARE @ClientID INT, @TotalComanda DECIMAL(12,2), @StatusComanda NVARCHAR(50);
DECLARE @PuncteBonus DECIMAL(5,2);

DECLARE cursor_fidelitate CURSOR FOR
SELECT co.ID_Client, co.Total, co.Status
FROM Comenzi co
WHERE co.Status = 'Livrata' 
AND co.Data_Comanda >= DATEADD(month, -1, GETDATE());

OPEN cursor_fidelitate;
FETCH NEXT FROM cursor_fidelitate INTO @ClientID, @TotalComanda, @StatusComanda;

WHILE @@FETCH_STATUS = 0
BEGIN
    SET @PuncteBonus = @TotalComanda / 100;
    
    UPDATE Clienti
    SET Scor_Fidelitate = Scor_Fidelitate + @PuncteBonus
    WHERE ID_Client = @ClientID;
    
    PRINT CONCAT('Client ID: ', @ClientID, ' - Puncte adăugate: ', @PuncteBonus);
    
    FETCH NEXT FROM cursor_fidelitate INTO @ClientID, @TotalComanda, @StatusComanda;
END

CLOSE cursor_fidelitate;
DEALLOCATE cursor_fidelitate;

8.2 Cursor pentru Reaprovizionarea Stocului

DECLARE @ProdusID INT, @StocCurent INT, @DenumireProdus NVARCHAR(100);
DECLARE @CantitateVanduta INT, @PragCritic INT = 5;

DECLARE cursor_stoc CURSOR FOR
SELECT p.ID_Produs, p.Denumire, p.Stoc
FROM Produse p
WHERE p.Stoc <= @PragCritic;

OPEN cursor_stoc;
FETCH NEXT FROM cursor_stoc INTO @ProdusID, @DenumireProdus, @StocCurent;

WHILE @@FETCH_STATUS = 0
BEGIN
    SELECT @CantitateVanduta = COALESCE(SUM(dc.Cantitate), 0)
    FROM Detalii_Comanda dc
    JOIN Comenzi co ON dc.ID_Comanda = co.ID_Comanda
    WHERE dc.ID_Produs = @ProdusID
    AND co.Data_Comanda >= DATEADD(month, -1, GETDATE());
    
    IF @CantitateVanduta > 0
    BEGIN
        UPDATE Produse
        SET Stoc = Stoc + (@CantitateVanduta * 2)
        WHERE ID_Produs = @ProdusID;
        
        PRINT CONCAT('Produs: ', @DenumireProdus, ' - Stoc reaprovizionat cu: ', @CantitateVanduta * 2, ' unități');
    END
    
    FETCH NEXT FROM cursor_stoc INTO @ProdusID, @DenumireProdus, @StocCurent;
END

CLOSE cursor_stoc;
DEALLOCATE cursor_stoc;

Captură ecran: Messages tab cu rezultatele procesării cursor-ului


9. TRIGGERE

Au fost create 4 triggere:

9.1 tr_ActualizeazaTotalComanda

CREATE TRIGGER tr_ActualizeazaTotalComanda
ON Detalii_Comanda
AFTER INSERT, UPDATE, DELETE
AS
BEGIN
    SET NOCOUNT ON;
    
    -- Pentru INSERT și UPDATE
    IF EXISTS(SELECT * FROM inserted)
    BEGIN
        UPDATE Comenzi
        SET Total = (
            SELECT SUM(dc.Cantitate * dc.Pret_Unitar * (1 - dc.Discount/100))
            FROM Detalii_Comanda dc
            WHERE dc.ID_Comanda = Comenzi.ID_Comanda
        )
        WHERE ID_Comanda IN (SELECT DISTINCT ID_Comanda FROM inserted);
    END
    
    -- Pentru DELETE
    IF EXISTS(SELECT * FROM deleted) AND NOT EXISTS(SELECT * FROM inserted)
    BEGIN
        UPDATE Comenzi
        SET Total = COALESCE((
            SELECT SUM(dc.Cantitate * dc.Pret_Unitar * (1 - dc.Discount/100))
            FROM Detalii_Comanda dc
            WHERE dc.ID_Comanda = Comenzi.ID_Comanda
        ), 0)
        WHERE ID_Comanda IN (SELECT DISTINCT ID_Comanda FROM deleted);
    END
END;

9.2 tr_VerificaStoc (INSTEAD OF)

CREATE TRIGGER tr_VerificaStoc
ON Detalii_Comanda
INSTEAD OF INSERT
AS
BEGIN
    SET NOCOUNT ON;
    
    DECLARE @ID_Produs INT, @Cantitate INT, @StocDisponibil INT;
    DECLARE @DenumireProdus NVARCHAR(100);
    
    DECLARE stoc_cursor CURSOR FOR
    SELECT ID_Produs, Cantitate
    FROM inserted;
    
    OPEN stoc_cursor;
    FETCH NEXT FROM stoc_cursor INTO @ID_Produs, @Cantitate;
    
    WHILE @@FETCH_STATUS = 0
    BEGIN
        SELECT @StocDisponibil = Stoc, @DenumireProdus = Denumire
        FROM Produse
        WHERE ID_Produs = @ID_Produs;
        
        IF @StocDisponibil >= @Cantitate
        BEGIN
            INSERT INTO Detalii_Comanda (ID_Comanda, ID_Produs, Cantitate, Pret_Unitar, Discount)
            SELECT ID_Comanda, ID_Produs, Cantitate, Pret_Unitar, Discount
            FROM inserted
            WHERE ID_Produs = @ID_Produs;
            
            UPDATE Produse
            SET Stoc = Stoc - @Cantitate
            WHERE ID_Produs = @ID_Produs;
        END
        ELSE
        BEGIN
            RAISERROR('Stoc insuficient pentru produsul %s', 16, 1, @DenumireProdus);
        END
        
        FETCH NEXT FROM stoc_cursor INTO @ID_Produs, @Cantitate;
    END
    
    CLOSE stoc_cursor;
    DEALLOCATE stoc_cursor;
END;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment