Input: Quels sont les Top 10 produits vendus aujourd’hui ?

Output:
SELECT TOP (10)
    p.ProductKey,
    p.ProductName,
    SUM(o.AmountAfterDiscount) AS TotalSales
FROM FactOrders AS o
JOIN DimDate AS d ON o.OrderDateKey = d.date_key
JOIN DimProduct AS p ON o.ProductKey = p.ProductKey
WHERE d.full_date = CAST(GETDATE() AS date)
GROUP BY p.ProductKey, p.ProductName
ORDER BY TotalSales DESC;


Input: Quels sont les Flop 10 produits ?

Output:
SELECT TOP 10
    p.ProductName,
    SUM(o.AmountAfterDiscount) AS TotalSales
FROM FactOrders AS o
JOIN DimProduct AS p ON o.ProductKey = p.ProductKey
GROUP BY p.ProductName
ORDER BY TotalSales ASC;


Input: Quels sont les Top pré-vendeurs commerciaux en chiffre d’affaires ?

Output:
SELECT TOP 10
    e.EmployeeFullName AS EmployeeName,
    SUM(o.AmountAfterDiscount) AS ChiffreAffaires
FROM FactOrders AS o
JOIN DimEmployee AS e
    ON o.EmployeeKey = e.EmployeeKey
GROUP BY e.EmployeeFullName
ORDER BY ChiffreAffaires DESC;


Input: Quels sont les pré-vendeurs les moins performants ?

Output:
SELECT
    e.EmployeeID,
    e.EmployeeFullName,
    SUM(o.AmountAfterDiscount) AS TotalCA
FROM FactOrders AS o
JOIN DimEmployee AS e
    ON o.EmployeeKey = e.EmployeeKey
WHERE e.JobTitle LIKE '%Pré-vendeur%'
GROUP BY e.EmployeeID, e.EmployeeFullName
ORDER BY TotalCA ASC;


Input: Quelles sont les routes avec la meilleure performance ?

Output:
SELECT g.Route,
       SUM(o.AmountAfterDiscount) AS TotalRevenue
FROM FactOrders AS o
JOIN DimGeography AS g
  ON o.GeographyKey = g.GeographyID
GROUP BY g.Route
ORDER BY TotalRevenue DESC;


Input: Quelles sont les routes avec plus faibles ventes ?

Output:
SELECT g.Route,
       SUM(o.AmountAfterDiscount) AS TotalSales
FROM FactOrders o
JOIN DimGeography g ON o.GeographyKey = g.GeographyID
GROUP BY g.Route
ORDER BY TotalSales ASC;


Input: Quelles sont les régions avec la meilleure progression du chiffre d'affaire pendant le premier trimestre de cette année ?

Output:
WITH CurrentQ1 AS (
    SELECT g.Region,
           SUM(o.AmountAfterDiscount) AS CA_Current
    FROM FactOrders o
    JOIN DimGeography g ON o.GeographyKey = g.GeographyID
    JOIN DimDate d ON o.OrderDateKey = d.date_key
    WHERE d.year = YEAR(GETDATE())
      AND d.month_num_in_year IN (1, 2, 3)
    GROUP BY g.Region
),
PrevQ1 AS (
    SELECT g.Region,
           SUM(o.AmountAfterDiscount) AS CA_Prev
    FROM FactOrders o
    JOIN DimGeography g ON o.GeographyKey = g.GeographyID
    JOIN DimDate d ON o.OrderDateKey = d.date_key
    WHERE d.year = YEAR(GETDATE()) - 1
      AND d.month_num_in_year IN (1, 2, 3)
    GROUP BY g.Region
)
SELECT TOP 5
       COALESCE(c.Region, p.Region) AS Region,
       ISNULL(c.CA_Current, 0) AS CA_Current,
       ISNULL(p.CA_Prev, 0) AS CA_Prev,
       CASE WHEN ISNULL(p.CA_Prev, 0) = 0 THEN NULL
            ELSE (ISNULL(c.CA_Current, 0) - p.CA_Prev) * 100.0 / p.CA_Prev
       END AS GrowthPct
FROM CurrentQ1 c
FULL OUTER JOIN PrevQ1 p ON c.Region = p.Region
WHERE ISNULL(p.CA_Prev, 0) > 0
ORDER BY GrowthPct DESC;


Input: Quels produits génèrent 80% des ventes ?

Output:
WITH ProductSales AS (
    SELECT p.ProductKey,
           p.ProductName,
           SUM(o.AmountAfterDiscount) AS SalesAmount
    FROM FactOrders o
    JOIN DimProduct p ON o.ProductKey = p.ProductKey
    GROUP BY p.ProductKey, p.ProductName
),
TotalSales AS (
    SELECT SUM(SalesAmount) AS TotalAmount
    FROM ProductSales
),
Ranked AS (
    SELECT ps.ProductKey,
           ps.ProductName,
           ps.SalesAmount,
           SUM(ps.SalesAmount) OVER (ORDER BY ps.SalesAmount DESC ROWS UNBOUNDED PRECEDING) AS CumulativeSales,
           ts.TotalAmount,
           (SUM(ps.SalesAmount) OVER (ORDER BY ps.SalesAmount DESC ROWS UNBOUNDED PRECEDING) * 100.0) / ts.TotalAmount AS CumulativePct
    FROM ProductSales ps
    CROSS JOIN TotalSales ts
)
SELECT ProductKey,
       ProductName,
       SalesAmount,
       CumulativePct
FROM Ranked
WHERE CumulativePct <= 80
ORDER BY SalesAmount DESC;


Input: Quels clients génèrent 80% du chiffre d’affaires ?

Output:
WITH ClientRevenue AS (
    SELECT
        c.CustomerKey,
        c.CustomerFullName,
        SUM(o.AmountAfterDiscount) AS Revenue
    FROM FactOrders o
    INNER JOIN DimCustomer c ON o.CustomerKey = c.CustomerKey
    GROUP BY c.CustomerKey, c.CustomerFullName
),
TotalRevenue AS (
    SELECT SUM(Revenue) AS TotalRev FROM ClientRevenue
),
Ranked AS (
    SELECT
        cr.CustomerKey,
        cr.CustomerFullName,
        cr.Revenue,
        SUM(cr.Revenue) OVER (ORDER BY cr.Revenue DESC ROWS UNBOUNDED PRECEDING) AS CumulativeRevenue,
        tr.TotalRev
    FROM ClientRevenue cr
    CROSS JOIN TotalRevenue tr
)
SELECT
    CustomerKey,
    CustomerFullName,
    Revenue,
    CumulativeRevenue,
    TotalRev AS TotalRevenue,
    CAST(CumulativeRevenue AS decimal(18,4)) / CAST(TotalRev AS decimal(18,4)) AS CumulativePct
FROM Ranked
WHERE CumulativeRevenue <= 0.8 * TotalRev
ORDER BY Revenue DESC;


Input: Quelles routes génèrent 80% du volume ?

Output:
WITH RouteVolume AS (
    SELECT g.Route,
           SUM(o.OrderQty) AS TotalQty
    FROM FactOrders o
    JOIN DimGeography g ON o.GeographyKey = g.GeographyID
    GROUP BY g.Route
),
Total AS (
    SELECT SUM(TotalQty) AS GrandTotal
    FROM RouteVolume
),
Ranked AS (
    SELECT rv.Route,
           rv.TotalQty,
           SUM(rv.TotalQty) OVER (ORDER BY rv.TotalQty DESC ROWS UNBOUNDED PRECEDING) AS CumQty,
           t.GrandTotal,
           (SUM(rv.TotalQty) OVER (ORDER BY rv.TotalQty DESC ROWS UNBOUNDED PRECEDING) * 100.0) / t.GrandTotal AS CumPct
    FROM RouteVolume rv
    CROSS JOIN Total t
)
SELECT Route,
       TotalQty,
       CumPct
FROM Ranked
WHERE CumPct <= 80
ORDER BY CumPct ASC;


Input: Quels pré-vendeurs réalisent la majorité des ventes ?

Output:
WITH SalesByEmp AS (
    SELECT
        e.EmployeeKey,
        e.EmployeeID,
        e.EmployeeFullName,
        SUM(o.AmountAfterDiscount) AS TotalSales,
        100.0 * SUM(o.AmountAfterDiscount) / SUM(SUM(o.AmountAfterDiscount)) OVER () AS SalesPct
    FROM FactOrders o
    JOIN DimEmployee e ON o.EmployeeKey = e.EmployeeKey
    GROUP BY e.EmployeeKey, e.EmployeeID, e.EmployeeFullName
)
SELECT
    EmployeeID,
    EmployeeFullName,
    TotalSales,
    SalesPct
FROM SalesByEmp
WHERE SalesPct >= 50
ORDER BY TotalSales DESC;


Input: Comment évoluent les ventes cette journée ?

Output:
SELECT
    t.hour AS Heure,
    SUM(o.AmountAfterDiscount) AS ChiffreAffaires
FROM FactOrders AS o
JOIN DimDate AS d ON o.OrderDateKey = d.date_key
JOIN DimTime AS t ON o.TimeKey = t.time_key
WHERE d.full_date = CAST(GETDATE() AS date)
GROUP BY t.hour
ORDER BY t.hour;


Input: Quelle est l’évolution des ventes cette semaine ?

Output:
SELECT
    d.full_date AS SaleDate,
    SUM(o.AmountAfterDiscount) AS WeeklySales
FROM FactOrders AS o
JOIN DimDate AS d ON o.OrderDateKey = d.date_key
WHERE d.year = YEAR(GETDATE())
  AND d.week_num_in_year = DATEPART(ISO_WEEK, GETDATE())
GROUP BY d.full_date
ORDER BY d.full_date;


Input: Quelle est l’évolution des ventes ce mois ?

Output:
SELECT
    d.full_date AS VenteDate,
    SUM(o.AmountAfterDiscount) AS TotalVentesJour
FROM FactOrders o
JOIN DimDate d ON o.OrderDateKey = d.date_key
WHERE d.year = YEAR(GETDATE())
  AND d.month_num_in_year = MONTH(GETDATE())
GROUP BY d.full_date
ORDER BY d.full_date;


Input: Combien de commandes en moyenne par jour génére la région Est par jour?

Output:
SELECT AVG(CAST(DailyOrders AS float)) AS AvgOrdersPerDay
FROM (
    SELECT d.full_date,
           COUNT(DISTINCT o.SalesOrderNum) AS DailyOrders
    FROM FactOrders o
    JOIN DimGeography g ON o.GeographyKey = g.GeographyID
    JOIN DimDate d ON o.OrderDateKey = d.date_key
    WHERE g.Region = 'Est'
    GROUP BY d.full_date
) AS t;


Input: Quelle est la valeur moyenne des commandes ?

Output:
SELECT AVG(OrderTotal) AS AverageOrderValue
FROM (
    SELECT SalesOrderNum,
           SUM(AmountAfterDiscount) AS OrderTotal
    FROM FactOrders
    GROUP BY SalesOrderNum
) AS OrderSums;


Input: Quels pré-vendeurs font le plus de commandes ?

Output:
SELECT
    e.EmployeeID,
    e.EmployeeFullName,
    COUNT(DISTINCT o.SalesOrderNum) AS OrderCount
FROM FactOrders AS o
JOIN DimEmployee AS e
    ON o.EmployeeKey = e.EmployeeKey
GROUP BY e.EmployeeID, e.EmployeeFullName
ORDER BY OrderCount DESC;


Input: Quels pré-vendeurs font les plus grosses commandes ?

Output:
SELECT TOP 10
    e.EmployeeFullName,
    SUM(o.AmountAfterDiscount) AS TotalOrderAmount
FROM FactOrders AS o
JOIN DimEmployee AS e
    ON o.EmployeeKey = e.EmployeeKey
GROUP BY e.EmployeeFullName
ORDER BY TotalOrderAmount DESC;


Input: Quels clients commandent le plus souvent ?

Output:
SELECT
    c.CustomerKey,
    c.CustomerFullName,
    COUNT(DISTINCT o.SalesOrderNum) AS OrderCount
FROM FactOrders AS o
JOIN DimCustomer AS c ON o.CustomerKey = c.CustomerKey
GROUP BY c.CustomerKey, c.CustomerFullName
ORDER BY OrderCount DESC;


Input: Quel est le taux de réalisation des objectifs par route pendant le mois actuel?

Output:
SELECT
    g.Route,
    CASE WHEN SUM(obj.Montant) = 0 THEN NULL
         ELSE (SUM(o.AmountAfterDiscount) * 1.0 / SUM(obj.Montant)) * 100
    END AS ReachPct
FROM FactOrders AS o
JOIN DimDate AS d ON o.OrderDateKey = d.date_key
JOIN FactObjectifs AS obj
    ON o.GeographyKey = obj.GeographyKey
   AND YEAR(d.full_date) = TRY_CAST(obj.année AS int)
   AND FORMAT(d.full_date, 'MMMM') = obj.mois
JOIN DimGeography AS g ON o.GeographyKey = g.GeographyID
WHERE YEAR(d.full_date) = YEAR(GETDATE())
  AND MONTH(d.full_date) = MONTH(GETDATE())
GROUP BY g.Route;


Input: Quel est le classement des routes ?

Output:
WITH RouteCA AS (
    SELECT g.Route,
           SUM(o.AmountAfterDiscount) AS TotalCA
    FROM FactOrders o
    INNER JOIN DimGeography g
        ON o.GeographyKey = g.GeographyID
    GROUP BY g.Route
)
SELECT Route,
       TotalCA,
       ROW_NUMBER() OVER (ORDER BY TotalCA DESC) AS Rank
FROM RouteCA
ORDER BY Rank;


Input: Quel est le classement des régions ?

Output:
SELECT
    g.Region,
    SUM(o.AmountAfterDiscount) AS ChiffreAffaires,
    RANK() OVER (ORDER BY SUM(o.AmountAfterDiscount) DESC) AS Classement
FROM FactOrders AS o
JOIN DimGeography AS g
    ON o.GeographyKey = g.GeographyID
GROUP BY g.Region
ORDER BY ChiffreAffaires DESC;


Input: Quel est le classement des vendeurs ?

Output:
SELECT
    e.EmployeeID,
    e.EmployeeFullName,
    SUM(o.AmountAfterDiscount) AS TotalSales,
    RANK() OVER (ORDER BY SUM(o.AmountAfterDiscount) DESC) AS SalesRank
FROM FactOrders AS o
JOIN DimEmployee AS e ON o.EmployeeKey = e.EmployeeKey
GROUP BY e.EmployeeID, e.EmployeeFullName
ORDER BY TotalSales DESC;


Input: Quelle famille de produits vend le plus ce mois ci ?

Output:
SELECT TOP 1 f.FamilleName AS FamilleProduit,
       SUM(o.AmountAfterDiscount) AS ChiffreAffaires
FROM FactOrders o
JOIN DimProduct p ON o.ProductKey = p.ProductKey
JOIN DimFamille f ON p.FamilleKey = f.FamilleKey
JOIN DimDate d ON o.OrderDateKey = d.date_key
WHERE d.year = YEAR(GETDATE())
  AND d.month_num_in_year = MONTH(GETDATE())
GROUP BY f.FamilleName
ORDER BY SUM(o.AmountAfterDiscount) DESC;


Input: Quelle famille vend le moins ?

Output:
SELECT TOP 1
    f.FamilleName AS Famille,
    SUM(o.AmountAfterDiscount) AS TotalVentes
FROM FactOrders AS o
JOIN DimProduct AS p ON o.ProductKey = p.ProductKey
JOIN DimFamille AS f ON p.FamilleKey = f.FamilleKey
GROUP BY f.FamilleName
ORDER BY TotalVentes ASC;


Input: Quel SKU progresse le plus cette année ?

Output:
WITH YearlySales AS (
    SELECT
        p.ProductKey,
        p.ProductID,
        p.ProductReference,
        p.ProductName,
        SUM(CASE WHEN d.year = YEAR(GETDATE()) THEN fo.AmountAfterDiscount ELSE 0 END) AS SalesCurrentYear,
        SUM(CASE WHEN d.year = YEAR(GETDATE()) - 1 THEN fo.AmountAfterDiscount ELSE 0 END) AS SalesPrevYear
    FROM FactOrders fo
    INNER JOIN DimDate d ON fo.OrderDateKey = d.date_key
    INNER JOIN DimProduct p ON fo.ProductKey = p.ProductKey
    GROUP BY p.ProductKey, p.ProductID, p.ProductReference, p.ProductName
)
SELECT TOP (1)
    ProductKey,
    ProductID,
    ProductReference,
    ProductName,
    SalesCurrentYear,
    SalesPrevYear,
    CASE WHEN SalesPrevYear = 0 THEN NULL ELSE (SalesCurrentYear - SalesPrevYear) * 100.0 / SalesPrevYear END AS GrowthPercent
FROM YearlySales
ORDER BY GrowthPercent DESC;


Input: Quel SKU recule le plus cette année ?

Output:
SELECT TOP 1
    p.ProductID AS SKU,
    p.ProductReference,
    p.ProductName,
    SUM(CASE WHEN d.year = YEAR(GETDATE()) THEN fo.AmountAfterDiscount ELSE 0 END) -
    SUM(CASE WHEN d.year = YEAR(GETDATE()) - 1 THEN fo.AmountAfterDiscount ELSE 0 END) AS AmountDiff
FROM FactOrders fo
JOIN DimDate d ON fo.OrderDateKey = d.date_key
JOIN DimProduct p ON fo.ProductKey = p.ProductKey
GROUP BY p.ProductID, p.ProductReference, p.ProductName
ORDER BY AmountDiff ASC;


Input: À quelle heure vend-on le plus ?

Output:
SELECT TOP 1 WITH TIES
    dt.hour AS Heure,
    SUM(o.AmountAfterDiscount) AS TotalVentes
FROM FactOrders AS o
JOIN DimTime AS dt ON o.TimeKey = dt.time_key
GROUP BY dt.hour
ORDER BY TotalVentes DESC;


Input: Quel jour de la semaine vend le plus ?

Output:
SELECT TOP 1
    d.day_name AS DayOfWeek,
    SUM(o.AmountAfterDiscount) AS TotalSales
FROM FactOrders AS o
JOIN DimDate AS d ON o.OrderDateKey = d.date_key
GROUP BY d.day_name
ORDER BY TotalSales DESC;


Input: Quel jour de la semaine vend le moins ?

Output:
SELECT TOP 1
    d.day_name AS DayOfWeek,
    SUM(o.AmountAfterDiscount) AS TotalSales
FROM FactOrders AS o
JOIN DimDate AS d ON o.OrderDateKey = d.date_key
GROUP BY d.day_name
ORDER BY TotalSales ASC;


Input: Quelle semaine du mois est la plus performante ?

Output:
SELECT TOP 1
    ((d.day_num_in_month - 1) / 7) + 1 AS WeekOfMonth,
    SUM(o.AmountAfterDiscount) AS TotalRevenue
FROM FactOrders o
JOIN DimDate d ON o.OrderDateKey = d.date_key
GROUP BY ((d.day_num_in_month - 1) / 7) + 1
ORDER BY TotalRevenue DESC;


Input: Quelle semaine de l'année actuelle est la plus performante ?

Output:
SELECT TOP 1
    d.week_num_in_year AS WeekNumber,
    SUM(o.AmountAfterDiscount) AS TotalRevenue
FROM FactOrders AS o
JOIN DimDate AS d ON o.OrderDateKey = d.date_key
WHERE d.year = YEAR(GETDATE())
GROUP BY d.week_num_in_year
ORDER BY TotalRevenue DESC;


Input: Quelles routes sont en dessous de 50% de l’objectif ?

Output:
SELECT
    g.Route,
    SUM(o.AmountAfterDiscount) AS RealizedAmount,
    SUM(obj.Montant) AS ObjectiveAmount,
    CASE WHEN SUM(obj.Montant) = 0 THEN 0 ELSE (SUM(o.AmountAfterDiscount) / SUM(obj.Montant)) * 100 END AS ReachPct
FROM FactOrders AS o
JOIN DimDate AS d ON o.OrderDateKey = d.date_key
JOIN FactObjectifs AS obj
    ON o.GeographyKey = obj.GeographyKey
    AND YEAR(d.full_date) = TRY_CAST(obj.année AS int)
    AND DATENAME(month, d.full_date) = obj.mois
JOIN DimGeography AS g ON o.GeographyKey = g.GeographyID
GROUP BY g.Route
HAVING CASE WHEN SUM(obj.Montant) = 0 THEN 0 ELSE (SUM(o.AmountAfterDiscount) / SUM(obj.Montant)) * 100 END < 50;


Input: Quels vendeurs sont en retard sur l’objectif ?

Output:
WITH OrderAgg AS (
    SELECT
        fo.EmployeeKey,
        YEAR(d.full_date) AS YearNum,
        DATENAME(month, d.full_date) AS MonthName,
        SUM(fo.AmountAfterDiscount) AS RealizedAmount
    FROM FactOrders fo
    JOIN DimDate d ON fo.OrderDateKey = d.date_key
    GROUP BY fo.EmployeeKey, YEAR(d.full_date), DATENAME(month, d.full_date)
),
ObjAgg AS (
    SELECT
        EmployeeKey,
        CAST(année AS int) AS YearNum,
        mois AS MonthName,
        SUM(Montant) AS ObjectiveAmount
    FROM FactObjectifs
    GROUP BY EmployeeKey, CAST(année AS int), mois
)
SELECT
    de.EmployeeID,
    de.EmployeeFullName,
    oa.YearNum,
    oa.MonthName,
    ob.ObjectiveAmount,
    oa.RealizedAmount,
    (oa.RealizedAmount / NULLIF(ob.ObjectiveAmount, 0)) * 100 AS ReachPct
FROM OrderAgg oa
JOIN ObjAgg ob
    ON oa.EmployeeKey = ob.EmployeeKey
   AND oa.YearNum = ob.YearNum
   AND oa.MonthName = ob.MonthName
JOIN DimEmployee de ON oa.EmployeeKey = de.EmployeeKey
WHERE oa.RealizedAmount < ob.ObjectiveAmount
ORDER BY ReachPct ASC;


Input: Quels produits n’ont pas été vendus aujourd’hui ?

Output:
SELECT p.ProductKey,
       p.ProductID,
       p.ProductName
FROM   DimProduct AS p
WHERE  NOT EXISTS (SELECT 1
                   FROM   FactOrders AS o
                          INNER JOIN DimDate AS d ON o.OrderDateKey = d.date_key
                   WHERE  d.full_date = CAST(GETDATE() AS date)
                          AND o.ProductKey = p.ProductKey);


Input: Quels clients n’ont pas commandé depuis 30 jours ?

Output:
WITH LastOrder AS (
    SELECT fo.CustomerKey,
           MAX(dd.full_date) AS LastOrderDate
    FROM FactOrders fo
    JOIN DimDate dd ON fo.OrderDateKey = dd.date_key
    GROUP BY fo.CustomerKey
)
SELECT c.CustomerKey,
       c.CustomerFullName,
       c.CustomerCode,
       lo.LastOrderDate
FROM DimCustomer c
LEFT JOIN LastOrder lo ON c.CustomerKey = lo.CustomerKey
WHERE lo.LastOrderDate IS NULL
   OR DATEDIFF(day, lo.LastOrderDate, GETDATE()) > 30;


Input: Quelle combinaison produit + région fonctionne le mieux ?

Output:
SELECT TOP 1
    p.ProductName,
    g.Region,
    SUM(o.AmountAfterDiscount) AS TotalRevenue
FROM FactOrders AS o
JOIN DimProduct AS p ON o.ProductKey = p.ProductKey
JOIN DimGeography AS g ON o.GeographyKey = g.GeographyID
GROUP BY p.ProductName, g.Region
ORDER BY TotalRevenue DESC;


Input: Quel vendeur performe mieux avec quel produit ?

Output:
WITH SalesAgg AS (
    SELECT
        o.EmployeeKey,
        o.ProductKey,
        SUM(o.AmountAfterDiscount) AS TotalRevenue
    FROM FactOrders o
    GROUP BY o.EmployeeKey, o.ProductKey
),
Ranked AS (
    SELECT
        sa.EmployeeKey,
        sa.ProductKey,
        sa.TotalRevenue,
        ROW_NUMBER() OVER (PARTITION BY sa.EmployeeKey ORDER BY sa.TotalRevenue DESC) AS rn
    FROM SalesAgg sa
)
SELECT
    e.EmployeeID,
    e.EmployeeFullName,
    p.ProductID,
    p.ProductName,
    r.TotalRevenue
FROM Ranked r
JOIN DimEmployee e ON r.EmployeeKey = e.EmployeeKey
JOIN DimProduct p ON r.ProductKey = p.ProductKey
WHERE r.rn = 1
ORDER BY r.TotalRevenue DESC;


Input: Quel client achète plusieurs familles ?

Output:
SELECT c.CustomerKey,
       c.CustomerFullName,
       COUNT(DISTINCT p.FamilleKey) AS FamilyCount
FROM FactOrders fo
JOIN DimProduct p ON fo.ProductKey = p.ProductKey
JOIN DimCustomer c ON fo.CustomerKey = c.CustomerKey
GROUP BY c.CustomerKey, c.CustomerFullName
HAVING COUNT(DISTINCT p.FamilleKey) > 1
ORDER BY FamilyCount DESC;


Input: Montre-moi le Top 10 des produits par chiffre d’affaires cette semaine avec l’évolution par rapport à la semaine dernière

Output:
WITH SalesByWeek AS (
    SELECT
        p.ProductKey,
        p.ProductName,
        SUM(CASE
                WHEN d.year = YEAR(GETDATE())
                     AND d.week_num_in_year = DATEPART(week, GETDATE())
                THEN f.AmountAfterDiscount
                ELSE 0
            END) AS ThisWeekSales,
        SUM(CASE
                WHEN d.year = YEAR(DATEADD(week, -1, GETDATE()))
                     AND d.week_num_in_year = DATEPART(week, DATEADD(week, -1, GETDATE()))
                THEN f.AmountAfterDiscount
                ELSE 0
            END) AS LastWeekSales
    FROM FactOrders f
    JOIN DimProduct p ON f.ProductKey = p.ProductKey
    JOIN DimDate d ON f.OrderDateKey = d.date_key
    GROUP BY p.ProductKey, p.ProductName
)
SELECT TOP 10
    ProductName,
    ThisWeekSales,
    LastWeekSales,
    CASE WHEN LastWeekSales = 0 THEN NULL
         ELSE (ThisWeekSales - LastWeekSales) * 100.0 / LastWeekSales
    END AS PctChange
FROM SalesByWeek
ORDER BY ThisWeekSales DESC;


Input: Quels produits ont enregistré une baisse de volume de vente de plus de 30% par rapport à la semaine dernière

Output:
WITH WeeklyQty AS (
    SELECT
        p.ProductKey,
        p.ProductName,
        d.[year]               AS OrderYear,
        d.week_num_in_year    AS OrderWeek,
        SUM(o.OrderQty)       AS TotalQty
    FROM FactOrders AS o
    INNER JOIN DimDate AS d   ON o.OrderDateKey = d.date_key
    INNER JOIN DimProduct AS p ON o.ProductKey   = p.ProductKey
    GROUP BY
        p.ProductKey,
        p.ProductName,
        d.[year],
        d.week_num_in_year
),
RankedQty AS (
    SELECT
        *,
        ROW_NUMBER() OVER (PARTITION BY ProductKey ORDER BY OrderYear, OrderWeek) AS rn
    FROM WeeklyQty
)
SELECT
    cur.ProductName,
    cur.OrderYear   AS CurrentYear,
    cur.OrderWeek   AS CurrentWeek,
    cur.TotalQty    AS CurrentQty,
    prev.OrderYear  AS PreviousYear,
    prev.OrderWeek  AS PreviousWeek,
    prev.TotalQty   AS PreviousQty,
    CAST(100.0 * (prev.TotalQty - cur.TotalQty) / NULLIF(prev.TotalQty,0) AS decimal(5,2)) AS DecreasePct
FROM RankedQty AS cur
INNER JOIN RankedQty AS prev
    ON cur.ProductKey = prev.ProductKey
   AND cur.rn = prev.rn + 1
WHERE cur.TotalQty < 0.7 * prev.TotalQty
  AND prev.TotalQty > 0 -- éviter division par zéro
ORDER BY DecreasePct DESC;


Input: Quels sont les produits dont le chiffre d'affaires a chuté de manière significative entre hier et aujourd'hui

Output:
WITH DailyRevenue AS (
    SELECT p.ProductKey,
           p.ProductName,
           d.full_date,
           SUM(o.AmountAfterDiscount) AS Revenue
    FROM FactOrders o
    JOIN DimProduct p ON o.ProductKey = p.ProductKey
    JOIN DimDate d ON o.OrderDateKey = d.date_key
    WHERE d.full_date IN (CAST(GETDATE() AS date), DATEADD(day, -1, CAST(GETDATE() AS date)))
    GROUP BY p.ProductKey, p.ProductName, d.full_date
),
Pivoted AS (
    SELECT ProductKey,
           ProductName,
           MAX(CASE WHEN full_date = DATEADD(day, -1, CAST(GETDATE() AS date)) THEN Revenue END) AS RevenueYesterday,
           MAX(CASE WHEN full_date = CAST(GETDATE() AS date) THEN Revenue END) AS RevenueToday
    FROM DailyRevenue
    GROUP BY ProductKey, ProductName
)
SELECT ProductKey,
       ProductName,
       RevenueYesterday,
       RevenueToday,
       RevenueToday - RevenueYesterday AS RevenueChange,
       CASE WHEN RevenueYesterday = 0 THEN NULL
            ELSE (RevenueToday - RevenueYesterday) * 100.0 / RevenueYesterday
       END AS ChangePct
FROM Pivoted
WHERE RevenueToday < RevenueYesterday
ORDER BY RevenueChange ASC;


Input: Liste les produits qui étaient dans le Top 10 le mois dernier mais qui ne sont plus dans le Top 10 aujourd'hui

Output:
WITH DateInfo AS (
    SELECT date_key,
           full_date,
           YEAR(full_date) AS yr,
           MONTH(full_date) AS mo
    FROM DimDate
),
LastMonth AS (
    SELECT fo.ProductKey,
           SUM(fo.AmountAfterDiscount) AS revenue
    FROM FactOrders fo
    JOIN DateInfo di ON fo.OrderDateKey = di.date_key
    WHERE di.full_date >= DATEFROMPARTS(YEAR(DATEADD(month, -1, GETDATE())), MONTH(DATEADD(month, -1, GETDATE())), 1)
      AND di.full_date < DATEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), 1)
    GROUP BY fo.ProductKey
),
LastMonthTop AS (
    SELECT ProductKey
    FROM (
        SELECT ProductKey,
               revenue,
               ROW_NUMBER() OVER (ORDER BY revenue DESC) AS rn
        FROM LastMonth
    ) t
    WHERE rn <= 10
),
CurrentMonth AS (
    SELECT fo.ProductKey,
           SUM(fo.AmountAfterDiscount) AS revenue
    FROM FactOrders fo
    JOIN DateInfo di ON fo.OrderDateKey = di.date_key
    WHERE di.full_date >= DATEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), 1)
      AND di.full_date <= GETDATE()
    GROUP BY fo.ProductKey
),
CurrentMonthTop AS (
    SELECT ProductKey
    FROM (
        SELECT ProductKey,
               revenue,
               ROW_NUMBER() OVER (ORDER BY revenue DESC) AS rn
        FROM CurrentMonth
    ) t
    WHERE rn <= 10
)
SELECT dp.ProductID,
       dp.ProductName,
       dp.ProductReference
FROM DimProduct dp
WHERE dp.ProductKey IN (
    SELECT ProductKey FROM LastMonthTop
    EXCEPT
    SELECT ProductKey FROM CurrentMonthTop
)
ORDER BY dp.ProductName;


Input: Quel commercial affiche la meilleure progression de Chiffre d'affaire sur les 7 derniers jours

Output:
WITH RecentPeriod AS (
    SELECT fo.EmployeeKey,
           SUM(fo.AmountAfterDiscount) AS RecentAmount
    FROM FactOrders fo
    JOIN DimDate d ON fo.OrderDateKey = d.date_key
    WHERE d.full_date >= DATEADD(day, -6, CAST(GETDATE() AS date))
      AND d.full_date <= CAST(GETDATE() AS date)
    GROUP BY fo.EmployeeKey
),
PreviousPeriod AS (
    SELECT fo.EmployeeKey,
           SUM(fo.AmountAfterDiscount) AS PrevAmount
    FROM FactOrders fo
    JOIN DimDate d ON fo.OrderDateKey = d.date_key
    WHERE d.full_date >= DATEADD(day, -13, CAST(GETDATE() AS date))
      AND d.full_date < DATEADD(day, -6, CAST(GETDATE() AS date))
    GROUP BY fo.EmployeeKey
)
SELECT TOP 1
    e.EmployeeID,
    e.EmployeeFullName,
    ISNULL(r.RecentAmount, 0) AS RecentAmount,
    ISNULL(p.PrevAmount, 0) AS PreviousAmount,
    CASE WHEN ISNULL(p.PrevAmount, 0) = 0 THEN NULL
         ELSE (ISNULL(r.RecentAmount, 0) - p.PrevAmount) / p.PrevAmount * 100 END AS GrowthPct
FROM RecentPeriod r
FULL OUTER JOIN PreviousPeriod p ON r.EmployeeKey = p.EmployeeKey
JOIN DimEmployee e ON e.EmployeeKey = COALESCE(r.EmployeeKey, p.EmployeeKey)
ORDER BY GrowthPct DESC;


Input: Quel vendeur a enregistré la plus forte progression dans l'atteinte de ses volumes de vente par rapport au trimestre dernier

Output:
WITH OrdersByQuarter AS (
    SELECT o.EmployeeKey,
           o.OrderQty,
           d.[year],
           d.quarter,
           CASE
               WHEN d.[year] = YEAR(GETDATE()) AND d.quarter = DATEPART(quarter, GETDATE()) THEN 'Current'
               WHEN d.[year] = CASE WHEN DATEPART(quarter, GETDATE()) = 1 THEN YEAR(GETDATE()) - 1 ELSE YEAR(GETDATE()) END
                    AND d.quarter = CASE WHEN DATEPART(quarter, GETDATE()) = 1 THEN 4 ELSE DATEPART(quarter, GETDATE()) - 1 END THEN 'Previous'
           END AS PeriodFlag
    FROM FactOrders o
    JOIN DimDate d ON o.OrderDateKey = d.date_key
    WHERE (d.[year] = YEAR(GETDATE()) AND d.quarter = DATEPART(quarter, GETDATE()))
       OR (d.[year] = CASE WHEN DATEPART(quarter, GETDATE()) = 1 THEN YEAR(GETDATE()) - 1 ELSE YEAR(GETDATE()) END
           AND d.quarter = CASE WHEN DATEPART(quarter, GETDATE()) = 1 THEN 4 ELSE DATEPART(quarter, GETDATE()) - 1 END)
),
Agg AS (
    SELECT EmployeeKey,
           SUM(CASE WHEN PeriodFlag = 'Current' THEN OrderQty END) AS QtyCurrent,
           SUM(CASE WHEN PeriodFlag = 'Previous' THEN OrderQty END) AS QtyPrevious
    FROM OrdersByQuarter
    GROUP BY EmployeeKey
    HAVING SUM(CASE WHEN PeriodFlag = 'Previous' THEN OrderQty END) > 0
)
SELECT TOP 1
       e.EmployeeID,
       e.EmployeeFullName,
       a.QtyCurrent,
       a.QtyPrevious,
       (a.QtyCurrent - a.QtyPrevious) AS QtyIncrease,
       CASE WHEN a.QtyPrevious = 0 THEN NULL
            ELSE CAST((a.QtyCurrent - a.QtyPrevious) * 100.0 / a.QtyPrevious AS decimal(10,2))
       END AS PercentIncrease
FROM Agg a
JOIN DimEmployee e ON a.EmployeeKey = e.EmployeeKey
ORDER BY QtyIncrease DESC;


Input: Quelle zone vend moins bien que le mois passé ?

Output:
WITH SalesByZone AS (
    SELECT g.Zone,
           YEAR(d.full_date) AS yr,
           MONTH(d.full_date) AS mn,
           (YEAR(d.full_date) * 100 + MONTH(d.full_date)) AS MonthID,
           SUM(o.AmountAfterDiscount) AS total_sales
    FROM FactOrders o
    JOIN DimDate d ON o.OrderDateKey = d.date_key
    JOIN DimGeography g ON o.GeographyKey = g.GeographyID
    WHERE d.full_date >= DATEADD(month, DATEDIFF(month, 0, GETDATE()) - 1, 0) -- début du mois précédent
      AND d.full_date <  DATEADD(month, DATEDIFF(month, 0, GETDATE()) + 1, 0) -- fin du mois en cours
    GROUP BY g.Zone, YEAR(d.full_date), MONTH(d.full_date), (YEAR(d.full_date) * 100 + MONTH(d.full_date))
)
SELECT cur.Zone,
       cur.total_sales AS CurrentMonthSales,
       prev.total_sales AS PreviousMonthSales
FROM SalesByZone cur
JOIN SalesByZone prev
  ON cur.Zone = prev.Zone
 AND cur.MonthID = prev.MonthID + 1
WHERE cur.total_sales < prev.total_sales;


Input: Quelle zone vend moins bien que l'année passé ?

Output:
WITH SalesByZoneYear AS (
    SELECT g.Zone,
           d.[year] AS Year,
           SUM(o.AmountAfterDiscount) AS TotalSales
    FROM FactOrders o
    JOIN DimDate d ON o.OrderDateKey = d.date_key
    JOIN DimGeography g ON o.GeographyKey = g.GeographyID
    GROUP BY g.Zone, d.[year]
)
SELECT cur.Zone,
       cur.TotalSales AS SalesCurrentYear,
       prev.TotalSales AS SalesPreviousYear,
       (cur.TotalSales - prev.TotalSales) AS Difference
FROM SalesByZoneYear cur
JOIN SalesByZoneYear prev
  ON cur.Zone = prev.Zone
 AND cur.Year = YEAR(GETDATE())
 AND prev.Year = YEAR(GETDATE()) - 1
WHERE cur.TotalSales < prev.TotalSales
ORDER BY cur.Zone;


Input: Quel produit est vendu chez le plus petit nombre de clients

Output:
WITH ProductCustomerCounts AS (
    SELECT fo.ProductKey,
           COUNT(DISTINCT fo.CustomerKey) AS CustomerCount
    FROM FactOrders fo
    GROUP BY fo.ProductKey
)
SELECT TOP 1 dp.ProductKey,
       dp.ProductName,
       pcc.CustomerCount
FROM ProductCustomerCounts pcc
JOIN DimProduct dp ON dp.ProductKey = pcc.ProductKey
ORDER BY pcc.CustomerCount ASC, dp.ProductName;


Input: Quel vendeur a le meilleur panier moyen ?

Output:
WITH OrderTotals AS (
    SELECT
        SalesOrderNum,
        EmployeeKey,
        SUM(AmountAfterDiscount) AS OrderTotal
    FROM FactOrders
    GROUP BY SalesOrderNum, EmployeeKey
)
SELECT TOP 1
    e.EmployeeID,
    e.EmployeeFullName,
    AVG(ot.OrderTotal) AS AvgBasketSize
FROM OrderTotals ot
JOIN DimEmployee e ON ot.EmployeeKey = e.EmployeeKey
GROUP BY e.EmployeeID, e.EmployeeFullName
ORDER BY AvgBasketSize DESC;


Input: Quel est le montant total des ventes par Wilaya ?

Output:
SELECT dc.Wilaya,
       SUM(fo.AmountAfterDiscount) AS TotalSales
FROM FactOrders AS fo
JOIN DimCustomer AS dc
  ON fo.CustomerKey = dc.CustomerKey
GROUP BY dc.Wilaya
ORDER BY TotalSales DESC;


Input: Combien de clients actifs avons-nous par secteur ?

Output:
WITH CustomerFlags AS (
    SELECT
        fo.CustomerKey,
        dg.Secteur,
        MAX(CASE WHEN DATEDIFF(day, dd.full_date, GETDATE()) <= 30 THEN 1 ELSE 0 END) AS RecentOrderFlag,
        MAX(CASE WHEN dc.IsActive = 'True' THEN 1 ELSE 0 END) AS IsActiveFlag
    FROM FactOrders fo
    JOIN DimDate dd ON fo.OrderDateKey = dd.date_key
    JOIN DimGeography dg ON fo.GeographyKey = dg.GeographyID
    JOIN DimCustomer dc ON fo.CustomerKey = dc.CustomerKey
    GROUP BY fo.CustomerKey, dg.Secteur
)
SELECT
    Secteur,
    COUNT(*) AS ActiveClients
FROM CustomerFlags
WHERE RecentOrderFlag = 1 OR IsActiveFlag = 1
GROUP BY Secteur
ORDER BY ActiveClients DESC;


Input: Quelle est la quantité totale de produits retournés ce mois-ci ?

Output:
SELECT SUM(fd.QuantiteDelivered) AS TotalQuantityReturned
FROM FactDelivery fd
JOIN DimDate dd ON fd.DeliveredDateKey = dd.date_key
WHERE dd.[year] = YEAR(GETDATE())
  AND dd.month_num_in_year = MONTH(GETDATE());


Input: Quel est le taux de retour par famille de produits ?

Output:
WITH Orders AS (
    SELECT f.FamilleKey, SUM(o.OrderQty) AS TotalOrdered
    FROM FactOrders o
    JOIN DimProduct p ON o.ProductKey = p.ProductKey
    JOIN DimFamille f ON p.FamilleKey = f.FamilleKey
    GROUP BY f.FamilleKey
),
Returns AS (
    SELECT f.FamilleKey, SUM(d.QuantiteDelivered) AS TotalReturned
    FROM FactDelivery d
    JOIN DimProduct p ON d.ProductKey = p.ProductKey
    JOIN DimFamille f ON p.FamilleKey = f.FamilleKey
    WHERE d.IsDelivered = 0
    GROUP BY f.FamilleKey
)
SELECT f.FamilleName,
       CASE WHEN o.TotalOrdered = 0 THEN 0
            ELSE 100.0 * r.TotalReturned / o.TotalOrdered
       END AS ReturnRatePercent
FROM DimFamille f
LEFT JOIN Orders o ON f.FamilleKey = o.FamilleKey
LEFT JOIN Returns r ON f.FamilleKey = r.FamilleKey
ORDER BY ReturnRatePercent DESC;


Input: Liste les clients qui n'ont jamais passé de commande.

Output:
SELECT
    dc.CustomerKey,
    dc.CustomerFullName,
    dc.CustomerCode,
    dc.CustomerReference,
    dc.IsActive
FROM DimCustomer AS dc
WHERE NOT EXISTS (
    SELECT 1
    FROM FactOrders AS fo
    WHERE fo.CustomerKey = dc.CustomerKey
);


Input: Quelles sont les 5 communes avec le plus gros volume de ventes ?

Output:
SELECT TOP 5
    c.Commune,
    SUM(o.OrderQty) AS TotalVolume
FROM FactOrders AS o
JOIN DimCustomer AS c ON o.CustomerKey = c.CustomerKey
WHERE c.Commune IS NOT NULL
GROUP BY c.Commune
ORDER BY TotalVolume DESC;


Input: Combien de visites ont été effectuées sans commande hier ?

Output:
WITH Yesterday AS (
    SELECT date_key
    FROM DimDate
    WHERE full_date = CAST(DATEADD(day, -1, GETDATE()) AS date)
)
SELECT COUNT(*) AS VisitsWithoutOrder
FROM FactClientVisits v
JOIN Yesterday y ON v.DateKey = y.date_key
WHERE NOT EXISTS (
    SELECT 1
    FROM FactOrders o
    WHERE o.CustomerKey = v.CustomerKey
      AND o.OrderDateKey = v.DateKey
);


Input: Quel est le motif de non-vente le plus fréquent ?

Output:
SELECT TOP 1
    Raison AS MotifNonVente,
    COUNT(*) AS NbOccurrences
FROM FactClientVisits
WHERE Raison IS NOT NULL AND Raison <> ''
GROUP BY Raison
ORDER BY COUNT(*) DESC;


Input: Quelle est la distance moyenne parcourue par les vendeurs pour leurs visites ?

Output:
SELECT AVG(CAST(Distance AS float)) AS AvgDistance
FROM FactClientVisits;


Input: Compare des ventes entre le matin et le soir pendant la semaine actuelle

Output:
SELECT dt.day_part AS DayPart,
       SUM(fo.AmountAfterDiscount) AS TotalSales
FROM FactOrders fo
JOIN DimDate dd ON fo.OrderDateKey = dd.date_key
JOIN DimTime dt ON fo.TimeKey = dt.time_key
WHERE dd.year = YEAR(GETDATE())
  AND dd.week_num_in_year = DATEPART(week, GETDATE())
  AND dt.day_part IN ('Matin', 'Soir')
GROUP BY dt.day_part
ORDER BY CASE WHEN dt.day_part = 'Matin' THEN 1 ELSE 2 END;


Input: Compare des ventes entre le matin et le soir pendant le mois d'octobre 2025

Output:
SELECT dt.day_part AS DayPart,
       SUM(fo.AmountAfterDiscount) AS TotalSales
FROM FactOrders AS fo
JOIN DimTime   AS dt ON fo.TimeKey = dt.time_key
JOIN DimDate   AS dd ON fo.OrderDateKey = dd.date_key
WHERE dd.year = 2025
  AND dd.month_name = N'October'
  AND dt.day_part IN (N'Matin', N'Soir')
GROUP BY dt.day_part
ORDER BY TotalSales DESC;


Input: Quelle est l'évolution des quantités livrés par semaine cette année ?

Output:
SELECT
    d.week_num_in_year AS WeekNumber,
    MIN(d.week_begin_date) AS WeekStartDate,
    SUM(fd.QuantiteDelivered) AS TotalDeliveredQuantity
FROM FactDelivery fd
JOIN DimDate d ON fd.DeliveredDateKey = d.date_key
WHERE d.year = YEAR(GETDATE())
GROUP BY d.week_num_in_year
ORDER BY d.week_num_in_year;


Input: Quelle est l'évolution des quantités livrés par semaine et par région ?

Output:
SELECT
    dg.Region,
    dd.[year] AS Year,
    dd.week_num_in_year AS WeekNumber,
    SUM(fd.QuantiteDelivered) AS TotalDeliveredQuantity
FROM FactDelivery fd
JOIN DimGeography dg ON fd.GeographyKey = dg.GeographyID
JOIN DimDate dd ON fd.DeliveredDateKey = dd.date_key
GROUP BY
    dg.Region,
    dd.[year],
    dd.week_num_in_year
ORDER BY
    dg.Region,
    dd.[year],
    dd.week_num_in_year;


Input: Quels vendeurs ont dépassé leur objectif en volume de 20% ?

Output:
WITH OrderAgg AS (
    SELECT
        fo.EmployeeKey,
        YEAR(dd.full_date) AS YearNum,
        FORMAT(dd.full_date, 'MMMM') AS MonthName,
        SUM(fo.OrderQty) AS RealizedQty
    FROM FactOrders fo
    INNER JOIN DimDate dd ON fo.OrderDateKey = dd.date_key
    GROUP BY
        fo.EmployeeKey,
        YEAR(dd.full_date),
        FORMAT(dd.full_date, 'MMMM')
),
TargetAgg AS (
    SELECT
        fobj.EmployeeKey,
        TRY_CAST(fobj.année AS int) AS YearNum,
        fobj.mois AS MonthName,
        SUM(fobj.QuantiteObjectifs) AS TargetQty
    FROM FactObjectifs fobj
    GROUP BY
        fobj.EmployeeKey,
        fobj.année,
        fobj.mois
)
SELECT
    e.EmployeeID,
    e.EmployeeFullName,
    oa.RealizedQty,
    ta.TargetQty,
    (oa.RealizedQty * 1.0 / NULLIF(ta.TargetQty,0)) - 1 AS OverAchievementPct
FROM OrderAgg oa
INNER JOIN TargetAgg ta
    ON oa.EmployeeKey = ta.EmployeeKey
    AND oa.YearNum = ta.YearNum
    AND oa.MonthName = ta.MonthName
INNER JOIN DimEmployee e ON e.EmployeeKey = oa.EmployeeKey
WHERE oa.RealizedQty > 1.2 * ta.TargetQty
ORDER BY oa.RealizedQty DESC;


Input: Quels vendeurs ont dépassé leur objectif en quantité de 30% ?

Output:
WITH OrderAgg AS (
    SELECT
        o.EmployeeKey,
        YEAR(d.full_date) AS yr,
        DATENAME(month, d.full_date) AS mn,
        SUM(o.OrderQty) AS RealizedQty
    FROM FactOrders o
    JOIN DimDate d ON o.OrderDateKey = d.date_key
    GROUP BY o.EmployeeKey, YEAR(d.full_date), DATENAME(month, d.full_date)
),
TargetAgg AS (
    SELECT
        fo.EmployeeKey,
        fo.année AS yr,
        fo.mois AS mn,
        SUM(fo.QuantiteObjectifs) AS TargetQty
    FROM FactObjectifs fo
    GROUP BY fo.EmployeeKey, fo.année, fo.mois
)
SELECT
    e.EmployeeID,
    e.EmployeeFullName,
    oa.yr,
    oa.mn,
    oa.RealizedQty,
    ta.TargetQty,
    CAST(oa.RealizedQty * 100.0 / NULLIF(ta.TargetQty, 0) AS decimal(5,2)) AS RealizedPct
FROM OrderAgg oa
JOIN TargetAgg ta
    ON oa.EmployeeKey = ta.EmployeeKey
   AND oa.yr = TRY_CAST(ta.yr AS int)
   AND oa.mn = ta.mn
JOIN DimEmployee e ON e.EmployeeKey = oa.EmployeeKey
WHERE oa.RealizedQty >= 1.3 * ta.TargetQty
ORDER BY RealizedPct DESC;


Input: Quels employées ont dépassé leur objectif en volume de 20% ?

Output:
WITH Realised AS (
    SELECT
        fo.EmployeeKey,
        d.year AS OrderYear,
        d.month_name AS OrderMonth,
        SUM(fo.OrderQty) AS RealisedQty
    FROM FactOrders fo
    INNER JOIN DimDate d ON fo.OrderDateKey = d.date_key
    GROUP BY fo.EmployeeKey, d.year, d.month_name
),
Objectif AS (
    SELECT
        obj.EmployeeKey,
        CAST(obj.année AS int) AS ObjYear,
        obj.mois AS ObjMonth,
        SUM(obj.QuantiteObjectifs) AS ObjectifQty
    FROM FactObjectifs obj
    GROUP BY obj.EmployeeKey, CAST(obj.année AS int), obj.mois
)
SELECT
    e.EmployeeID,
    e.EmployeeFullName,
    r.OrderYear,
    r.OrderMonth,
    r.RealisedQty,
    o.ObjectifQty,
    (r.RealisedQty * 100.0 / NULLIF(o.ObjectifQty,0)) AS RealisationPct
FROM Realised r
INNER JOIN Objectif o
    ON r.EmployeeKey = o.EmployeeKey
    AND r.OrderYear = o.ObjYear
    AND r.OrderMonth = o.ObjMonth
INNER JOIN DimEmployee e ON r.EmployeeKey = e.EmployeeKey
WHERE r.RealisedQty >= 1.2 * o.ObjectifQty;


Input: Quels employées ont dépassé leur objectif en quantité de 30% ?

Output:
WITH OrdersAgg AS (
    SELECT
        o.EmployeeKey,
        YEAR(d.full_date) AS YearNum,
        FORMAT(d.full_date, 'MMMM') AS MonthName,
        SUM(o.OrderQty) AS RealizedQty
    FROM FactOrders o
    JOIN DimDate d ON o.OrderDateKey = d.date_key
    GROUP BY o.EmployeeKey, YEAR(d.full_date), FORMAT(d.full_date, 'MMMM')
),
ObjAgg AS (
    SELECT
        EmployeeKey,
        TRY_CAST(année AS int) AS YearNum,
        mois AS MonthName,
        SUM(QuantiteObjectifs) AS TargetQty
    FROM FactObjectifs
    GROUP BY EmployeeKey, TRY_CAST(année AS int), mois
)
SELECT
    e.EmployeeID,
    e.EmployeeFullName,
    oa.YearNum,
    oa.MonthName,
    oa.RealizedQty,
    ob.TargetQty,
    (oa.RealizedQty * 1.0 / NULLIF(ob.TargetQty, 0)) - 1 AS OverPct
FROM OrdersAgg oa
JOIN ObjAgg ob ON oa.EmployeeKey = ob.EmployeeKey
               AND oa.YearNum = ob.YearNum
               AND oa.MonthName = ob.MonthName
JOIN DimEmployee e ON oa.EmployeeKey = e.EmployeeKey
WHERE oa.RealizedQty >= 1.3 * ob.TargetQty
ORDER BY oa.RealizedQty DESC;


Input: Liste des clients créés au cours des 30 derniers jours.

Output:
SELECT
    CustomerKey,
    CustomerID,
    CustomerCode,
    CustomerFullName,
    FirstOrderDate
FROM DimCustomer
WHERE DATEDIFF(day, FirstOrderDate, GETDATE()) <= 30
ORDER BY FirstOrderDate DESC;


Input: Combien de commandes n'ont pas été livrées ce trimestre ?

Output:
SELECT COUNT(DISTINCT o.SalesOrderNum) AS NonDeliveredOrders
FROM FactOrders AS o
JOIN DimDate AS d ON o.OrderDateKey = d.date_key
WHERE d.year = YEAR(GETDATE())
  AND d.quarter = DATEPART(QUARTER, GETDATE())
  AND (o.IsDelivered = 0 OR o.IsDelivered IS NULL);


Input: Quelle est la répartition des ventes par type de commerce (BusinessType) ?

Output:
WITH TotalSales AS (
    SELECT SUM(AmountAfterDiscount) AS TotalAmount
    FROM FactOrders
)
SELECT
    dc.BusinessType,
    SUM(fo.AmountAfterDiscount) AS SalesAmount,
    CAST(100.0 * SUM(fo.AmountAfterDiscount) / ts.TotalAmount AS decimal(10,2)) AS PercentageOfTotal
FROM FactOrders fo
JOIN DimCustomer dc ON fo.CustomerKey = dc.CustomerKey
CROSS JOIN TotalSales ts
GROUP BY dc.BusinessType, ts.TotalAmount
ORDER BY SalesAmount DESC;


Input: Quel est le produit le plus vendu dans la région Ouest ?

Output:
SELECT TOP 1
    p.ProductName,
    SUM(o.OrderQty) AS TotalQty
FROM FactOrders AS o
JOIN DimGeography AS g ON o.GeographyKey = g.GeographyID
JOIN DimProduct AS p ON o.ProductKey = p.ProductKey
WHERE g.Region = N'Ouest'
GROUP BY p.ProductName
ORDER BY TotalQty DESC;


Input: Combien a-t-on vendu durant les jours fériés cette année ?

Output:
SELECT SUM(o.AmountAfterDiscount) AS TotalSalesHoliday
FROM FactOrders AS o
JOIN DimDate AS d ON o.OrderDateKey = d.date_key
WHERE d.holiday IS NOT NULL
  AND YEAR(d.full_date) = YEAR(GETDATE());


Input: Quel est le délai moyen entre la commande et la livraison ?

Output:
SELECT AVG(CAST(DATEDIFF(day, od.full_date, dd.full_date) AS float)) AS AverageDelayDays
FROM FactOrders fo
JOIN DimDate od ON fo.OrderDateKey = od.date_key
JOIN DimDate dd ON fo.DeliveredDateKey = dd.date_key
WHERE fo.DeliveredDateKey IS NOT NULL;


Input: Quel fournisseur a le plus gros volume de ventes ?

Output:
SELECT TOP 1
    dp.ProductSupplier,
    SUM(fo.OrderQty) AS TotalVolume
FROM FactOrders AS fo
JOIN DimProduct AS dp ON fo.ProductKey = dp.ProductKey
GROUP BY dp.ProductSupplier
ORDER BY TotalVolume DESC;


Input: Quel vendeur a le plus grand nombre de clients inactifs ?

Output:
SELECT TOP 1
    e.EmployeeID,
    e.EmployeeFullName,
    COUNT(DISTINCT c.CustomerKey) AS InactiveCustomerCount
FROM FactOrders fo
JOIN DimCustomer c ON fo.CustomerKey = c.CustomerKey
JOIN DimEmployee e ON fo.EmployeeKey = e.EmployeeKey
WHERE c.IsActive <> 'True' OR c.IsActive IS NULL
GROUP BY e.EmployeeID, e.EmployeeFullName
ORDER BY InactiveCustomerCount DESC;


Input: Quels clients ont commandé plus de 5 familles différentes ce mois ci ?

Output:
SELECT
    C.CustomerKey,
    C.CustomerFullName,
    C.CustomerCode,
    COUNT(DISTINCT P.FamilleKey) AS DistinctFamilles
FROM FactOrders FO
JOIN DimDate D ON FO.OrderDateKey = D.date_key
JOIN DimProduct P ON FO.ProductKey = P.ProductKey
JOIN DimCustomer C ON FO.CustomerKey = C.CustomerKey
WHERE D.year = YEAR(GETDATE())
  AND D.month_num_in_year = MONTH(GETDATE())
GROUP BY C.CustomerKey, C.CustomerFullName, C.CustomerCode
HAVING COUNT(DISTINCT P.FamilleKey) > 5;


Input: Quels clients ont commandé plus de 5 familles différentes cette semaines ?

Output:
SELECT
    dc.CustomerKey,
    dc.CustomerFullName,
    dc.CustomerCode,
    COUNT(DISTINCT dp.FamilleKey) AS DistinctFamilyCount
FROM FactOrders fo
JOIN DimDate dd ON fo.OrderDateKey = dd.date_key
JOIN DimProduct dp ON fo.ProductKey = dp.ProductKey
JOIN DimCustomer dc ON fo.CustomerKey = dc.CustomerKey
WHERE dd.year = YEAR(GETDATE())
  AND dd.week_num_in_year = DATEPART(week, GETDATE())
GROUP BY dc.CustomerKey, dc.CustomerFullName, dc.CustomerCode
HAVING COUNT(DISTINCT dp.FamilleKey) > 5
ORDER BY DistinctFamilyCount DESC;


Input: Quel est le montant total des objectifs pour le mois prochain ?

Output:
SELECT SUM(Montant) AS TotalMontantObjectifs
FROM FactObjectifs
WHERE année = CAST(YEAR(DATEADD(month, 1, GETDATE())) AS nvarchar(15))
  AND mois = FORMAT(DATEADD(month, 1, GETDATE()), 'MMMM');


Input: Quelles sont les ventes par mois pendant cette année ?

Output:
SELECT
    d.month_name AS Mois,
    SUM(o.AmountAfterDiscount) AS TotalVentes
FROM FactOrders o
JOIN DimDate d ON o.OrderDateKey = d.date_key
WHERE d.year = YEAR(GETDATE())
GROUP BY d.month_name, d.month_num_in_year
ORDER BY d.month_num_in_year;


Input: Quelles zones géographiques ont doublé leurs ventes en un par rapport à l'année précédente ?

Output:
WITH ZoneYearSales AS (
    SELECT g.Zone,
           d.year,
           SUM(o.AmountAfterDiscount) AS total_sales
    FROM FactOrders o
    JOIN DimGeography g ON o.GeographyKey = g.GeographyID
    JOIN DimDate d ON o.OrderDateKey = d.date_key
    GROUP BY g.Zone, d.year
)
SELECT cur.Zone,
       cur.year AS CurrentYear,
       cur.total_sales AS CurrentYearSales,
       prev.year AS PreviousYear,
       prev.total_sales AS PreviousYearSales
FROM ZoneYearSales cur
JOIN ZoneYearSales prev
  ON cur.Zone = prev.Zone
 AND cur.year = prev.year + 1
WHERE cur.total_sales >= 2 * prev.total_sales
ORDER BY cur.Zone;


Input: Combien de prospects ont été visités cette semaine ?

Output:
SELECT COUNT(DISTINCT fc.CustomerKey) AS ProspectsVisitedThisWeek
FROM FactClientVisits fc
JOIN DimDate d ON fc.DateKey = d.date_key
WHERE d.year = YEAR(GETDATE())
  AND d.week_num_in_year = DATEPART(week, GETDATE());


Input: Quelle est la contribution de chaque distributeur au CA total pendant cette année?

Output:
WITH CA_Year AS (
    SELECT
        fo.DistributeurKey,
        SUM(fo.AmountAfterDiscount) AS CA_Distributeur
    FROM FactOrders fo
    JOIN DimDate dd ON fo.OrderDateKey = dd.date_key
    WHERE dd.year = YEAR(GETDATE())
    GROUP BY fo.DistributeurKey
),
TotalCA AS (
    SELECT SUM(AmountAfterDiscount) AS TotalCA
    FROM FactOrders fo
    JOIN DimDate dd ON fo.OrderDateKey = dd.date_key
    WHERE dd.year = YEAR(GETDATE())
)
SELECT
    ca.DistributeurKey AS DistributeurID,
    ca.CA_Distributeur,
    ca.CA_Distributeur * 100.0 / t.TotalCA AS ContributionPct
FROM CA_Year ca
CROSS JOIN TotalCA t
ORDER BY ca.CA_Distributeur DESC;


Input: Quelle est la contribution de chaque distributeur au CA total pendant le mois de janvier 2026?

Output:
WITH CA_Total AS (
    SELECT SUM(o.AmountAfterDiscount) AS TotalCA
    FROM FactOrders AS o
    INNER JOIN DimDate d ON o.OrderDateKey = d.date_key
    WHERE d.year = 2026 AND d.month_num_in_year = 1
)
SELECT
    g.Distributeur AS Distributeur,
    SUM(o.AmountAfterDiscount) AS CA_Distributeur,
    CAST(100.0 * SUM(o.AmountAfterDiscount) / ct.TotalCA AS DECIMAL(5,2)) AS Pourcentage_CA
FROM FactOrders o
INNER JOIN DimDate d ON o.OrderDateKey = d.date_key
INNER JOIN DimGeography g ON o.GeographyKey = g.GeographyID
CROSS JOIN CA_Total ct
WHERE d.year = 2026 AND d.month_num_in_year = 1
GROUP BY g.Distributeur, ct.TotalCA
ORDER BY CA_Distributeur DESC;


Input: Quel est le panier moyen par BusinessType ?

Output:
WITH OrderTotals AS (
    SELECT fo.SalesOrderNum,
           dc.BusinessType,
           SUM(fo.AmountAfterDiscount) AS OrderTotal
    FROM FactOrders fo
    INNER JOIN DimCustomer dc ON fo.CustomerKey = dc.CustomerKey
    GROUP BY fo.SalesOrderNum, dc.BusinessType
)
SELECT BusinessType,
       AVG(OrderTotal) AS PanierMoyen
FROM OrderTotals
GROUP BY BusinessType
ORDER BY BusinessType;


Input: Quels produits sont vendus exclusivement dans une seule zone ?

Output:
SELECT
    p.ProductID,
    p.ProductName,
    MIN(g.Zone) AS Zone
FROM FactOrders fo
JOIN DimProduct p ON fo.ProductKey = p.ProductKey
JOIN DimGeography g ON fo.GeographyKey = g.GeographyID
GROUP BY p.ProductID, p.ProductName
HAVING COUNT(DISTINCT g.Zone) = 1;


Input: Quel vendeur a le meilleur taux de transformation visite/commande ce mois ci ?

Output:
WITH Visits AS (
    SELECT fc.EmployeeKey,
           COUNT(*) AS VisitCount
    FROM FactClientVisits fc
    JOIN DimDate dv ON fc.DateKey = dv.date_key
    WHERE dv.year = YEAR(GETDATE())
      AND dv.month_num_in_year = MONTH(GETDATE())
    GROUP BY fc.EmployeeKey
),
Orders AS (
    SELECT fo.EmployeeKey,
           COUNT(DISTINCT fo.SalesOrderNum) AS OrderCount
    FROM FactOrders fo
    JOIN DimDate do ON fo.OrderDateKey = do.date_key
    WHERE do.year = YEAR(GETDATE())
      AND do.month_num_in_year = MONTH(GETDATE())
    GROUP BY fo.EmployeeKey
)
SELECT TOP 1
    de.EmployeeFullName AS Vendeur,
    ISNULL(o.OrderCount, 0) AS NombreCommandes,
    ISNULL(v.VisitCount, 0) AS NombreVisites,
    CASE WHEN ISNULL(v.VisitCount, 0) = 0 THEN 0
         ELSE CAST(ISNULL(o.OrderCount, 0) AS float) / v.VisitCount
    END AS TauxTransformation
FROM Visits v
FULL OUTER JOIN Orders o ON v.EmployeeKey = o.EmployeeKey
JOIN DimEmployee de ON COALESCE(v.EmployeeKey, o.EmployeeKey) = de.EmployeeKey
ORDER BY TauxTransformation DESC;


Input: Quelles sont les 10 routes les plus rentables ?

Output:
SELECT TOP 10
    dg.[Route] AS Route,
    SUM(fo.[AmountAfterDiscount]) AS ChiffreAffaires
FROM [FactOrders] fo
INNER JOIN [DimGeography] dg
    ON fo.[GeographyKey] = dg.[GeographyID]
GROUP BY dg.[Route]
ORDER BY ChiffreAffaires DESC;


Input: Combien de commandes contiennent plus de 10 articles différents pendant le mois de novembre?

Output:
SELECT COUNT(*) AS NombreCommandesPlusDe10Articles
FROM (
    SELECT fo.SalesOrderNum
    FROM FactOrders fo
    INNER JOIN DimDate dd ON fo.OrderDateKey = dd.date_key
    WHERE dd.month_name = N'November'
    GROUP BY fo.SalesOrderNum
    HAVING COUNT(DISTINCT fo.ProductKey) > 10
) AS cmd;


Input: Quel est le chiffre d'affaires généré par client et par famille de produit?

Output:
SELECT
    c.CustomerFullName AS Client,
    f.FamilleName   AS FamilleProduit,
    SUM(o.AmountAfterDiscount) AS ChiffreAffaires
FROM FactOrders o
INNER JOIN DimCustomer c ON o.CustomerKey = c.CustomerKey
INNER JOIN DimProduct p ON o.ProductKey = p.ProductKey
INNER JOIN DimFamille f ON p.FamilleKey = f.FamilleKey
GROUP BY
    c.CustomerFullName,
    f.FamilleName
ORDER BY
    ChiffreAffaires DESC;


Input: Quels clients ont augmenté leur volume d'achat de 50%  pendant les six mois précédent?

Output:
WITH RecentPeriod AS (
    SELECT
        fo.CustomerKey,
        SUM(fo.OrderQty) AS RecentQty
    FROM FactOrders fo
    JOIN DimDate dd ON fo.OrderDateKey = dd.date_key
    WHERE dd.full_date >= DATEADD(month, -6, CAST(GETDATE() AS date))
      AND dd.full_date <= CAST(GETDATE() AS date)
    GROUP BY fo.CustomerKey
),
PreviousPeriod AS (
    SELECT
        fo.CustomerKey,
        SUM(fo.OrderQty) AS PrevQty
    FROM FactOrders fo
    JOIN DimDate dd ON fo.OrderDateKey = dd.date_key
    WHERE dd.full_date >= DATEADD(month, -12, CAST(GETDATE() AS date))
      AND dd.full_date < DATEADD(month, -6, CAST(GETDATE() AS date))
    GROUP BY fo.CustomerKey
)
SELECT
    dc.CustomerKey,
    dc.CustomerFullName,
    rp.RecentQty,
    pp.PrevQty,
    CAST( (rp.RecentQty * 1.0) / pp.PrevQty AS decimal(5,2)) AS IncreaseFactor
FROM RecentPeriod rp
JOIN PreviousPeriod pp ON rp.CustomerKey = pp.CustomerKey
JOIN DimCustomer dc ON rp.CustomerKey = dc.CustomerKey
WHERE pp.PrevQty > 0
  AND rp.RecentQty >= 1.5 * pp.PrevQty
ORDER BY IncreaseFactor DESC;


Input: Quel est le top 3 des marques les plus vendues ?

Output:
SELECT TOP 3
    dp.ProductMarque,
    SUM(fo.AmountAfterDiscount) AS TotalSales
FROM FactOrders AS fo
JOIN DimProduct AS dp ON fo.ProductKey = dp.ProductKey
GROUP BY dp.ProductMarque
ORDER BY TotalSales DESC;


Input: Quelle est la fréquence moyenne de visite par client et par mois ?

Output:
WITH VisitsPerClientMonth AS (
    SELECT
        fv.CustomerKey,
        d.year,
        d.month_num_in_year AS month,
        COUNT(*) AS VisitCount
    FROM FactClientVisits fv
    JOIN DimDate d ON fv.DateKey = d.date_key
    GROUP BY fv.CustomerKey, d.year, d.month_num_in_year
)
SELECT AVG(CAST(VisitCount AS float)) AS AvgVisitsPerClientPerMonth
FROM VisitsPerClientMonth;


Input: Quelle est la part de marché de notre top produit dans sa famille ?

Output:
WITH ProductSales AS (
    SELECT o.ProductKey,
           p.ProductName,
           p.FamilleKey,
           SUM(o.AmountAfterDiscount) AS SalesAmt
    FROM FactOrders o
    JOIN DimProduct p ON o.ProductKey = p.ProductKey
    GROUP BY o.ProductKey, p.ProductName, p.FamilleKey
),
TopProduct AS (
    SELECT TOP 1 ProductKey,
           ProductName,
           FamilleKey,
           SalesAmt
    FROM ProductSales
    ORDER BY SalesAmt DESC
),
FamilySales AS (
    SELECT ps.FamilleKey,
           SUM(ps.SalesAmt) AS FamilySalesAmt
    FROM ProductSales ps
    JOIN TopProduct tp ON ps.FamilleKey = tp.FamilleKey
    GROUP BY ps.FamilleKey
)
SELECT tp.ProductName AS TopProduct,
       f.FamilleName AS Family,
       tp.SalesAmt AS ProductSales,
       fs.FamilySalesAmt AS FamilySales,
       CAST(100.0 * tp.SalesAmt / NULLIF(fs.FamilySalesAmt, 0) AS decimal(10,2)) AS MarketSharePct
FROM TopProduct tp
JOIN DimFamille f ON tp.FamilleKey = f.FamilleKey
JOIN FamilySales fs ON tp.FamilleKey = fs.FamilleKey;


Input: Quelle est l'évolution du nombre de clients actifs par trimestre pendant l'année actuelle ?

Output:
WITH OrdersWithQuarter AS (
    SELECT fo.CustomerKey,
           dd.quarter,
           dd.year
    FROM FactOrders fo
    JOIN DimDate dd ON fo.OrderDateKey = dd.date_key
    WHERE dd.year = YEAR(GETDATE())
),
ActiveCustomers AS (
    -- Clients ayant passé au moins une commande dans le trimestre
    SELECT DISTINCT CustomerKey, quarter
    FROM OrdersWithQuarter
    UNION ALL
    -- Clients marqués comme actifs dans DimCustomer (comptés pour chaque trimestre de l'année en cours)
    SELECT DISTINCT dc.CustomerKey, q.quarter
    FROM DimCustomer dc
    CROSS JOIN (
        SELECT DISTINCT quarter
        FROM DimDate
        WHERE year = YEAR(GETDATE())
    ) q
    WHERE dc.IsActive = 'True'
)
SELECT quarter,
       COUNT(DISTINCT CustomerKey) AS ActiveCustomerCount
FROM ActiveCustomers
GROUP BY quarter
ORDER BY quarter;


Input: Quelles routes ont le plus de clients de class Silver

Output:
SELECT TOP 10
    g.Route,
    COUNT(*) AS SilverCustomerCount
FROM DimCustomer AS c
JOIN DimGeography AS g
    ON c.Route = g.Route
WHERE c.BusinessClass = 'Silver'
GROUP BY g.Route
ORDER BY SilverCustomerCount DESC;


Input: Quel est le montant moyen des commandes par jour ouvré ?

Output:
WITH DailyTotals AS (
    SELECT
        d.full_date,
        SUM(o.AmountAfterDiscount) AS DailyTotal
    FROM FactOrders o
    INNER JOIN DimDate d ON o.OrderDateKey = d.date_key
    WHERE d.day_of_week BETWEEN 1 AND 5  -- jours ouvrés (lundi à vendredi)
    GROUP BY d.full_date
)
SELECT
    AVG(DailyTotal) AS AvgAmountPerWorkingDay
FROM DailyTotals;


Input: Combien de livraisons ont été effectuées par camion hier ?

Output:
SELECT
    dc.CamionID,
    dc.CamionDesignation,
    COUNT(*) AS DeliveriesYesterday
FROM FactDelivery fd
INNER JOIN DimCamion dc ON fd.CamionKey = dc.CamionKey
INNER JOIN DimDate dd ON fd.DeliveredDateKey = dd.date_key
WHERE dd.full_date = CAST(DATEADD(day, -1, GETDATE()) AS date)
GROUP BY dc.CamionID, dc.CamionDesignation
ORDER BY DeliveriesYesterday DESC;


Input: Quels clients n'ont pas été visités ce mois-ci ?

Output:
SELECT c.CustomerKey,
       c.CustomerFullName
FROM   DimCustomer AS c
WHERE  NOT EXISTS ( SELECT 1
                    FROM   FactClientVisits v
                           INNER JOIN DimDate d ON v.DateKey = d.date_key
                    WHERE  v.CustomerKey = c.CustomerKey
                           AND d.year = YEAR(GETDATE())
                           AND d.month_num_in_year = MONTH(GETDATE()) );


Input: Quels produits sont souvent achetés ensemble ?

Output:
WITH OrderProducts AS (
    SELECT SalesOrderNum, ProductKey
    FROM FactOrders
)
SELECT
    p1.ProductName AS Product1,
    p2.ProductName AS Product2,
    COUNT(DISTINCT op1.SalesOrderNum) AS OrderCount
FROM OrderProducts op1
JOIN OrderProducts op2
    ON op1.SalesOrderNum = op2.SalesOrderNum
   AND op1.ProductKey < op2.ProductKey
JOIN DimProduct p1 ON p1.ProductKey = op1.ProductKey
JOIN DimProduct p2 ON p2.ProductKey = op2.ProductKey
GROUP BY p1.ProductName, p2.ProductName
HAVING COUNT(DISTINCT op1.SalesOrderNum) >= 2 -- seuil minimal pour considérer "souvent"
ORDER BY OrderCount DESC;


Input: Quel est le montant total des ventes pour les produits en promotion ?

Output:
SELECT SUM(o.AmountAfterDiscount) AS TotalPromotionSales
FROM FactOrders AS o
JOIN DimPromotion AS p ON o.PromotionKey = p.PromotionKey
WHERE o.IsPromo = 1;


Input: Quelle zone a le plus faible taux de couverture clients ?

Output:
WITH TotalCustomers AS (
    SELECT
        dc.Zone,
        COUNT(DISTINCT dc.CustomerKey) AS TotalCustomers
    FROM DimCustomer dc
    WHERE dc.IsActive = 'True'
    GROUP BY dc.Zone
),
CoveredCustomers AS (
    SELECT
        dc.Zone,
        COUNT(DISTINCT fo.CustomerKey) AS CoveredCustomers
    FROM DimCustomer dc
    JOIN FactOrders fo ON dc.CustomerKey = fo.CustomerKey
    WHERE dc.IsActive = 'True'
    GROUP BY dc.Zone
)
SELECT TOP 1
    t.Zone,
    CAST(COALESCE(c.CoveredCustomers, 0) AS float) / NULLIF(t.TotalCustomers, 0) AS CoverageRate
FROM TotalCustomers t
LEFT JOIN CoveredCustomers c ON t.Zone = c.Zone
ORDER BY CoverageRate ASC;


Input: Quel est le montant moyen d'achat des clients de type 'Superette' ?

Output:
SELECT AVG(fo.AmountAfterDiscount) AS AvgPurchaseAmount
FROM FactOrders AS fo
JOIN DimCustomer AS dc ON fo.CustomerKey = dc.CustomerKey
WHERE dc.BusinessType = 'Superette';


Input: Quelles sont les ventes réalisées le week-end par rapport à la semaine pendant le moi d'octobre 2025 ?

Output:
SELECT
    SUM(CASE WHEN d.day_of_week IN (6,7) THEN o.AmountAfterDiscount ELSE 0 END) AS WeekendSales,
    SUM(CASE WHEN d.day_of_week NOT IN (6,7) THEN o.AmountAfterDiscount ELSE 0 END) AS WeekdaySales
FROM FactOrders o
JOIN DimDate d ON o.OrderDateKey = d.date_key
WHERE d.year = 2025
  AND d.month_num_in_year = 10;


Input: Quels produits se vendent de moins en moins depuis ces derniers 6 mois ?

Output:
WITH SalesByMonth AS (
    SELECT
        p.ProductKey,
        p.ProductName,
        (d.[year] * 100 + d.month_num_in_year) AS YearMonth,
        SUM(o.AmountAfterDiscount) AS MonthlySales,
        LAG(SUM(o.AmountAfterDiscount)) OVER (PARTITION BY p.ProductKey ORDER BY d.[year], d.month_num_in_year) AS PrevSales
    FROM FactOrders o
    JOIN DimDate d ON o.OrderDateKey = d.date_key
    JOIN DimProduct p ON o.ProductKey = p.ProductKey
    WHERE d.full_date >= DATEADD(month, -6, CAST(GETDATE() AS date))
    GROUP BY p.ProductKey, p.ProductName, d.[year], d.month_num_in_year
)
SELECT
    ProductKey,
    ProductName
FROM (
    SELECT
        ProductKey,
        ProductName,
        SUM(CASE WHEN PrevSales IS NOT NULL AND MonthlySales < PrevSales THEN 1 ELSE 0 END) AS DecreaseCount,
        COUNT(*) - 1 AS ExpectedDecreases
    FROM SalesByMonth
    GROUP BY ProductKey, ProductName
) t
WHERE DecreaseCount = ExpectedDecreases
ORDER BY ProductName;


Input: Quels clients commandent uniquement de promotion ?

Output:
SELECT
    c.CustomerKey,
    c.CustomerFullName,
    c.CustomerCode
FROM DimCustomer AS c
JOIN FactOrders AS o ON o.CustomerKey = c.CustomerKey
GROUP BY
    c.CustomerKey,
    c.CustomerFullName,
    c.CustomerCode
HAVING
    MIN(o.IsPromo) = 1 AND MAX(o.IsPromo) = 1;


Input: Quel chiffre d'affaires génèrent nos Top 10 clients ?

Output:
SELECT TOP (10)
    c.CustomerKey,
    c.CustomerFullName,
    SUM(o.AmountAfterDiscount) AS Revenue
FROM FactOrders AS o
JOIN DimCustomer AS c ON o.CustomerKey = c.CustomerKey
GROUP BY c.CustomerKey, c.CustomerFullName
ORDER BY Revenue DESC;


Input: Quelle famille de produits a le plus augmenté ses revenus par rapport au mois passé

Output:
WITH RevenueByFamily AS (
    SELECT
        p.FamilleKey,
        f.FamilleName,
        SUM(CASE
                WHEN d.year = YEAR(GETDATE()) AND d.month_num_in_year = MONTH(GETDATE())
                THEN o.AmountAfterDiscount
                ELSE 0
            END) AS RevCurrentMonth,
        SUM(CASE
                WHEN d.year = YEAR(DATEADD(month, -1, GETDATE())) AND d.month_num_in_year = MONTH(DATEADD(month, -1, GETDATE()))
                THEN o.AmountAfterDiscount
                ELSE 0
            END) AS RevPrevMonth
    FROM FactOrders o
    INNER JOIN DimDate d ON o.OrderDateKey = d.date_key
    INNER JOIN DimProduct p ON o.ProductKey = p.ProductKey
    INNER JOIN DimFamille f ON p.FamilleKey = f.FamilleKey
    GROUP BY p.FamilleKey, f.FamilleName
)
SELECT TOP 1
    FamilleName,
    RevCurrentMonth,
    RevPrevMonth,
    (RevCurrentMonth - RevPrevMonth) AS IncreaseAmount
FROM RevenueByFamily
ORDER BY IncreaseAmount DESC;


Input: En moyenne, combien d'articles différents y a-t-il dans une commande

Output:
SELECT AVG(CAST(ItemCount AS float)) AS AvgDistinctItemsPerOrder
FROM (
    SELECT SalesOrderNum,
           COUNT(DISTINCT ProductKey) AS ItemCount
    FROM FactOrders
    GROUP BY SalesOrderNum
) AS t;


Input: Quels sont les produits que les clients rachètent le plus souvent ?

Output:
WITH RepeatPurchases AS (
    SELECT
        fo.CustomerKey,
        fo.ProductKey,
        COUNT(DISTINCT fo.SalesOrderNum) AS OrderCount
    FROM FactOrders fo
    GROUP BY fo.CustomerKey, fo.ProductKey
    HAVING COUNT(DISTINCT fo.SalesOrderNum) > 1
)
SELECT
    dp.ProductName,
    COUNT(*) AS NumberOfCustomersRepeatingPurchase
FROM RepeatPurchases rp
JOIN DimProduct dp ON rp.ProductKey = dp.ProductKey
GROUP BY dp.ProductName
ORDER BY NumberOfCustomersRepeatingPurchase DESC;


Input: Quelle est l'évolution de la valeur moyenne du panier par mois de l'année actuelle ?

Output:
WITH OrderTotals AS (
    SELECT
        fo.SalesOrderNum,
        dd.month_num_in_year AS MonthNum,
        dd.month_name AS MonthName,
        SUM(fo.AmountAfterDiscount) AS OrderTotal
    FROM FactOrders fo
    JOIN DimDate dd ON fo.OrderDateKey = dd.date_key
    WHERE dd.year = YEAR(GETDATE())
    GROUP BY fo.SalesOrderNum, dd.month_num_in_year, dd.month_name
)
SELECT
    MonthNum,
    MonthName,
    AVG(OrderTotal) AS AvgBasketValue
FROM OrderTotals
GROUP BY MonthNum, MonthName
ORDER BY MonthNum;


Input: En moyenne, combien les clients dépensent-ils par commande chaque année ?

Output:
WITH OrderTotals AS (
    SELECT
        D.[year] AS OrderYear,
        FO.SalesOrderNum,
        SUM(FO.AmountAfterDiscount) AS OrderTotal
    FROM FactOrders FO
    INNER JOIN DimDate D ON FO.OrderDateKey = D.date_key
    GROUP BY D.[year], FO.SalesOrderNum
)
SELECT
    OrderYear,
    AVG(OrderTotal) AS AvgSpendPerOrder
FROM OrderTotals
GROUP BY OrderYear
ORDER BY OrderYear;


Input: Combien de clients ont été perdus ce semestre ?

Output:
DECLARE @CurrentYear int = YEAR(GETDATE());
DECLARE @CurrentSemester tinyint = CASE WHEN MONTH(GETDATE()) <= 6 THEN 1 ELSE 2 END;

SELECT COUNT(*) AS LostCustomers
FROM DimCustomer dc
JOIN DimDate dd ON dd.full_date = CAST(dc.InactiveDate AS date)
WHERE dc.IsActive = 'False'
  AND dd.[year] = @CurrentYear
  AND dd.semester = @CurrentSemester;


Input: Quel est le volume total des marchandises livrées aujourd'hui ?

Output:
SELECT SUM(ISNULL(fd.QuantiteDelivered, 0) * ISNULL(dp.volume, 0)) AS TotalVolume
FROM FactDelivery fd
JOIN DimDate dd ON fd.DeliveredDateKey = dd.date_key
JOIN DimProduct dp ON fd.ProductKey = dp.ProductKey
WHERE dd.full_date = CAST(GETDATE() AS date);


Input: Quels commerciaux vendent le plus dès la première semaine du mois

Output:
SELECT
    e.EmployeeID,
    e.EmployeeFullName,
    SUM(o.AmountAfterDiscount) AS TotalSalesFirstWeek
FROM FactOrders AS o
JOIN DimDate AS d ON o.OrderDateKey = d.date_key
JOIN DimEmployee AS e ON o.EmployeeKey = e.EmployeeKey
WHERE d.day_num_in_month BETWEEN 1 AND 7
GROUP BY e.EmployeeID, e.EmployeeFullName
ORDER BY TotalSalesFirstWeek DESC;


Input: Est-ce que les vendeurs qui visitent le plus de clients sont ceux qui vendent le plus ?

Output:
WITH Visits AS (
    SELECT fc.EmployeeKey,
           COUNT(DISTINCT fc.CustomerKey) AS VisitsCount
    FROM FactClientVisits fc
    GROUP BY fc.EmployeeKey
),
Sales AS (
    SELECT fo.EmployeeKey,
           SUM(fo.AmountAfterDiscount) AS SalesAmount
    FROM FactOrders fo
    GROUP BY fo.EmployeeKey
)
SELECT e.EmployeeKey,
       e.EmployeeFullName,
       ISNULL(v.VisitsCount, 0) AS VisitsCount,
       ISNULL(s.SalesAmount, 0) AS SalesAmount
FROM DimEmployee e
LEFT JOIN Visits v ON e.EmployeeKey = v.EmployeeKey
LEFT JOIN Sales s ON e.EmployeeKey = s.EmployeeKey
ORDER BY v.VisitsCount DESC,
         s.SalesAmount DESC;


Input: Quel est l'heure la plus chargée pour les commandes entre le matin et le soir

Output:
SELECT TOP 1
    t.hour AS Heure,
    COUNT(*) AS NombreCommandes
FROM FactOrders fo
JOIN DimTime t ON fo.TimeKey = t.time_key
WHERE t.day_part IN ('Matin', 'Soir')
GROUP BY t.hour
ORDER BY NombreCommandes DESC;


Input: Combien de clients n'ont pas commandé depuis plus de 90 jours ?

Output:
SELECT COUNT(*) AS ClientsSansCommandeDepuis90Jours
FROM DimCustomer
WHERE LastOrderDate IS NULL
   OR DATEDIFF(day, LastOrderDate, GETDATE()) > 90;


Input: Qui sont les 10 clients qui commandent le plus souvent

Output:
SELECT TOP (10)
    dc.CustomerKey,
    dc.CustomerFullName,
    COUNT(DISTINCT fo.SalesOrderNum) AS OrderCount
FROM FactOrders AS fo
JOIN DimCustomer AS dc ON fo.CustomerKey = dc.CustomerKey
GROUP BY dc.CustomerKey, dc.CustomerFullName
ORDER BY OrderCount DESC;


Input: Quelle est la répartition géographique des clients par classe de business ?

Output:
SELECT
    g.Region,
    g.Zone,
    g.Secteur,
    g.Route,
    c.BusinessType,
    COUNT(DISTINCT c.CustomerKey) AS CustomerCount
FROM FactClientVisits fcv
JOIN DimCustomer c ON fcv.CustomerKey = c.CustomerKey
JOIN DimGeography g ON fcv.GeographyID = g.GeographyID
GROUP BY
    g.Region,
    g.Zone,
    g.Secteur,
    g.Route,
    c.BusinessType
ORDER BY
    g.Region,
    g.Zone,
    g.Secteur,
    g.Route,
    c.BusinessType;


Input: Quel est le montant des ventes par type d'emballage ?

Output:
SELECT dp.Emballege AS Emballage,
       SUM(fo.AmountAfterDiscount) AS MontantVentes
FROM FactOrders fo
JOIN DimProduct dp ON fo.ProductKey = dp.ProductKey
GROUP BY dp.Emballege
ORDER BY MontantVentes DESC;


Input: Quelle est l'évolution des ventes par jour du mois actuel du 1er au 31 ?

Output:
SELECT
    d.full_date AS [Date],
    d.day_num_in_month AS [Day],
    SUM(o.AmountAfterDiscount) AS [TotalSales]
FROM FactOrders o
JOIN DimDate d ON o.OrderDateKey = d.date_key
WHERE YEAR(d.full_date) = YEAR(GETDATE())
  AND MONTH(d.full_date) = MONTH(GETDATE())
GROUP BY d.full_date, d.day_num_in_month
ORDER BY d.day_num_in_month;


Input: Quel est le taux de succès des objectifs par famille de produits pendant le mois actuel ?

Output:
WITH RealizedAgg AS (
    SELECT dp.FamilleKey,
           SUM(fo.AmountAfterDiscount) AS RealizedAmt
    FROM FactOrders fo
    INNER JOIN DimDate dd ON fo.OrderDateKey = dd.date_key
    INNER JOIN DimProduct dp ON fo.ProductKey = dp.ProductKey
    WHERE dd.year = YEAR(GETDATE())
      AND dd.month_num_in_year = MONTH(GETDATE())
    GROUP BY dp.FamilleKey
),
ObjectiveAgg AS (
    SELECT fo.FamilleKey,
           SUM(fo.Montant) AS ObjectiveAmt
    FROM FactObjectifs fo
    WHERE fo.année = CAST(YEAR(GETDATE()) AS nvarchar(15))
      AND fo.mois = FORMAT(GETDATE(),'MMMM')
    GROUP BY fo.FamilleKey
)
SELECT df.FamilleName,
       COALESCE(o.ObjectiveAmt, 0) AS ObjectiveAmount,
       COALESCE(r.RealizedAmt, 0) AS RealizedAmount,
       CASE WHEN COALESCE(o.ObjectiveAmt, 0) = 0 THEN NULL
            ELSE (COALESCE(r.RealizedAmt, 0) / NULLIF(o.ObjectiveAmt, 0)) * 100
       END AS SuccessRatePercent
FROM RealizedAgg r
FULL OUTER JOIN ObjectiveAgg o ON r.FamilleKey = o.FamilleKey
INNER JOIN DimFamille df ON df.FamilleKey = COALESCE(r.FamilleKey, o.FamilleKey)
ORDER BY SuccessRatePercent DESC;


Input: Quels clients achètent toujours pour un montant très proche de leur panier moyen  ?

Output:
WITH OrderTotals AS (
    SELECT fo.CustomerKey,
           fo.SalesOrderNum,
           SUM(fo.AmountAfterDiscount) AS OrderTotal
    FROM FactOrders fo
    GROUP BY fo.CustomerKey, fo.SalesOrderNum
),
AvgBasket AS (
    SELECT ot.CustomerKey,
           AVG(ot.OrderTotal) AS AvgBasket
    FROM OrderTotals ot
    GROUP BY ot.CustomerKey
)
SELECT dc.CustomerKey,
       dc.CustomerFullName,
       ab.AvgBasket
FROM AvgBasket ab
JOIN OrderTotals ot ON ot.CustomerKey = ab.CustomerKey
JOIN DimCustomer dc ON dc.CustomerKey = ab.CustomerKey
GROUP BY dc.CustomerKey, dc.CustomerFullName, ab.AvgBasket
HAVING MAX(ABS(ot.OrderTotal - ab.AvgBasket)) / ab.AvgBasket <= 0.05
ORDER BY dc.CustomerFullName;


Input: Quelles marques progressent le plus en zone Est ?

Output:
SELECT
    p.ProductMarque AS Brand,
    SUM(o.AmountAfterDiscount) AS TotalSales
FROM FactOrders AS o
JOIN DimProduct AS p ON o.ProductKey = p.ProductKey
JOIN DimGeography AS g ON o.GeographyKey = g.GeographyID
WHERE g.Zone = N'Est'
GROUP BY p.ProductMarque
ORDER BY TotalSales DESC;


Input: Quels vendeurs ont le plus gros écart entre commandes et livraisons ?

Output:
WITH OrderAgg AS (
    SELECT EmployeeKey,
           SUM(AmountAfterDiscount) AS TotalOrderAmount
    FROM FactOrders
    GROUP BY EmployeeKey
),
DeliveryAgg AS (
    SELECT EmplyeeKey AS EmployeeKey,
           SUM(AmountAfterDiscount) AS TotalDeliveryAmount
    FROM FactDelivery
    GROUP BY EmplyeeKey
)
SELECT e.EmployeeID,
       e.EmployeeFullName,
       COALESCE(o.TotalOrderAmount, 0) - COALESCE(d.TotalDeliveryAmount, 0) AS AmountGap
FROM DimEmployee AS e
LEFT JOIN OrderAgg AS o ON e.EmployeeKey = o.EmployeeKey
LEFT JOIN DeliveryAgg AS d ON e.EmployeeKey = d.EmployeeKey
ORDER BY AmountGap DESC;


Input: Quel est le ratio de clients visités par rapport au total pendant le mois d'octobre 2025?

Output:
WITH Visited AS (
    SELECT COUNT(DISTINCT fc.CustomerKey) AS VisitedCount
    FROM FactClientVisits fc
    JOIN DimDate d ON fc.DateKey = d.date_key
    WHERE d.year = 2025
      AND d.month_name = 'October'
),
Total AS (
    SELECT COUNT(DISTINCT CustomerKey) AS TotalCount
    FROM DimCustomer
)
SELECT
    CAST(v.VisitedCount AS decimal(10,2)) / NULLIF(t.TotalCount, 0) AS VisitRatio
FROM Visited v
CROSS JOIN Total t;


Input: Quels produits sont les plus vendus le lundi ?

Output:
SELECT
    p.ProductID,
    p.ProductName,
    SUM(o.OrderQty) AS TotalQty
FROM FactOrders AS o
JOIN DimDate AS d ON o.OrderDateKey = d.date_key
JOIN DimProduct AS p ON o.ProductKey = p.ProductKey
WHERE d.day_name = 'Monday'
GROUP BY p.ProductID, p.ProductName
ORDER BY TotalQty DESC;


Input: Quels sont les produits qui font le plus grimper le chiffre d'affaires de leur catégorie?

Output:
WITH CategoryRevenue AS (
    SELECT p.FamilleKey,
           SUM(o.AmountAfterDiscount) AS CategoryRevenue
    FROM FactOrders o
    INNER JOIN DimProduct p ON o.ProductKey = p.ProductKey
    GROUP BY p.FamilleKey
),
ProductRevenue AS (
    SELECT o.ProductKey,
           p.ProductName,
           p.FamilleKey,
           SUM(o.AmountAfterDiscount) AS ProductRevenue
    FROM FactOrders o
    INNER JOIN DimProduct p ON o.ProductKey = p.ProductKey
    GROUP BY o.ProductKey, p.ProductName, p.FamilleKey
)
SELECT pr.ProductName,
       f.FamilleName AS CategoryName,
       pr.ProductRevenue,
       cr.CategoryRevenue,
       CAST(100.0 * pr.ProductRevenue / NULLIF(cr.CategoryRevenue, 0) AS decimal(5,2)) AS ContributionPct
FROM ProductRevenue pr
INNER JOIN CategoryRevenue cr ON pr.FamilleKey = cr.FamilleKey
INNER JOIN DimFamille f ON pr.FamilleKey = f.FamilleKey
ORDER BY pr.ProductRevenue DESC;


Input: Quelle est la performance comparée des différents distributeurs ?

Output:
SELECT
    fo.DistributeurKey AS DistributeurID,
    SUM(fo.AmountAfterDiscount) AS TotalRevenue
FROM FactOrders AS fo
GROUP BY fo.DistributeurKey
ORDER BY TotalRevenue DESC;


Input: Quel jour de l'année a le plus bas volume de ventes ?

Output:
SELECT TOP 1
    d.full_date,
    d.day_num_in_year,
    SUM(o.OrderQty) AS total_quantity
FROM FactOrders o
JOIN DimDate d ON o.OrderDateKey = d.date_key
GROUP BY d.full_date, d.day_num_in_year
ORDER BY total_quantity ASC;


Input: Quels sont les clients qui n'achètent qu'un seul et même produit à chaque fois ?

Output:
WITH SingleProductCustomers AS (
    SELECT
        fo.CustomerKey,
        MIN(fo.ProductKey) AS ProductKey -- le seul produit acheté
    FROM FactOrders AS fo
    GROUP BY fo.CustomerKey
    HAVING COUNT(DISTINCT fo.ProductKey) = 1
)
SELECT
    dc.CustomerKey,
    dc.CustomerFullName,
    dc.CustomerIDName,
    dc.CustomerCode,
    spc.ProductKey
FROM SingleProductCustomers AS spc
JOIN DimCustomer AS dc
    ON dc.CustomerKey = spc.CustomerKey
ORDER BY dc.CustomerFullName;


Input: Quel est le nombre de visites par vendeur pour une route spécifique ?

Output:
DECLARE @RouteName NVARCHAR(100) = N'NomDeLaRoute';

SELECT
    e.EmployeeID,
    e.EmployeeFullName,
    COUNT(*) AS VisitCount
FROM FactClientVisits AS fcv
INNER JOIN DimGeography AS dg
    ON fcv.GeographyID = dg.GeographyID
INNER JOIN DimEmployee AS e
    ON fcv.EmployeeKey = e.EmployeeKey
WHERE dg.Route = @RouteName
GROUP BY e.EmployeeID, e.EmployeeFullName
ORDER BY VisitCount DESC;


Input: Quel est le panier moyen le plus élevé enregistré cette année ?

Output:
WITH OrderTotals AS (
    SELECT fo.SalesOrderNum,
           SUM(fo.AmountAfterDiscount) AS OrderTotal
    FROM FactOrders fo
    JOIN DimDate d ON fo.OrderDateKey = d.date_key
    WHERE d.year = YEAR(GETDATE())
    GROUP BY fo.SalesOrderNum
)
SELECT AVG(OrderTotal) AS PanierMoyen
FROM OrderTotals;


Input: Combien de vendeurs ont atteint moins de 30% de l'objectif pendant le mois de novembre 2025?

Output:
WITH Realized AS (
    SELECT fo.EmployeeKey,
           SUM(fo.AmountAfterDiscount) AS RealizedAmt
    FROM FactOrders fo
    JOIN DimDate dd ON fo.OrderDateKey = dd.date_key
    WHERE dd.[year] = 2025
      AND FORMAT(dd.full_date, 'MMMM') = N'Novembre'
    GROUP BY fo.EmployeeKey
),
Objective AS (
    SELECT fo.EmployeeKey,
           SUM(fo.Montant) AS ObjectiveAmt
    FROM FactObjectifs fo
    WHERE fo.année = N'2025'
      AND fo.mois = N'Novembre'
    GROUP BY fo.EmployeeKey
)
SELECT COUNT(*) AS VendeursMoins30Pct
FROM (
    SELECT COALESCE(r.EmployeeKey, o.EmployeeKey) AS EmployeeKey,
           ISNULL(r.RealizedAmt, 0) AS RealizedAmt,
           ISNULL(o.ObjectiveAmt, 0) AS ObjectiveAmt,
           CASE WHEN ISNULL(o.ObjectiveAmt, 0) = 0 THEN 0
                ELSE (ISNULL(r.RealizedAmt, 0) * 100.0 / o.ObjectiveAmt)
           END AS ReachPct
    FROM Realized r
    FULL OUTER JOIN Objective o ON r.EmployeeKey = o.EmployeeKey
) AS t
WHERE t.ObjectiveAmt > 0
  AND t.ReachPct < 30;


Input: Quel est le CA moyen par visite réussie ce trimestre ?

Output:
WITH SuccessfulVisits AS (
    SELECT fv.CustomerKey,
           fv.EmployeeKey,
           fv.DateKey
    FROM FactClientVisits fv
    JOIN DimDate d ON fv.DateKey = d.date_key
    WHERE fv.Status = 'Réussie'
      AND d.year = YEAR(GETDATE())
      AND d.quarter = DATEPART(QUARTER, GETDATE())
)
SELECT CASE WHEN COUNT(*) = 0 THEN 0
            ELSE SUM(o.AmountAfterDiscount) * 1.0 / COUNT(*)
       END AS AvgRevenuePerSuccessfulVisit
FROM SuccessfulVisits sv
LEFT JOIN FactOrders o
       ON sv.CustomerKey = o.CustomerKey
      AND sv.EmployeeKey = o.EmployeeKey
      AND sv.DateKey = o.OrderDateKey;


Input: Quelles sont les 5 Wilayas les plus dynamiques cette semaine ?

Output:
WITH WeekBounds AS (
    SELECT
        CAST(DATEADD(day, -(DATEPART(weekday, GETDATE()) - 1), CAST(GETDATE() AS date)) AS date) AS WeekStart,
        CAST(DATEADD(day, 6 - (DATEPART(weekday, GETDATE()) - 1), CAST(GETDATE() AS date)) AS date) AS WeekEnd
)
SELECT TOP 5
    g.Wilaya,
    SUM(o.AmountAfterDiscount) AS CA
FROM FactOrders o
JOIN DimGeography g ON o.GeographyKey = g.GeographyID
JOIN DimDate d ON o.OrderDateKey = d.date_key
CROSS JOIN WeekBounds wb
WHERE d.full_date BETWEEN wb.WeekStart AND wb.WeekEnd
GROUP BY g.Wilaya
ORDER BY CA DESC;


Input: Quels sont les Top 10 produits livré aujourd’hui ?

Output:
SELECT TOP (10)
    p.ProductKey,
    p.ProductName,
    SUM(d.AmountAfterDiscount) AS TotalAmount
FROM FactDelivery AS d
JOIN DimDate AS dd ON d.DeliveredDateKey = dd.date_key
JOIN DimProduct AS p ON d.ProductKey = p.ProductKey
WHERE dd.full_date = CAST(GETDATE() AS date)
GROUP BY p.ProductKey, p.ProductName
ORDER BY TotalAmount DESC;


Input: Quels sont les 10 produits vendus le moins aujourd’hui ?

Output:
SELECT TOP (10)
    p.ProductID,
    p.ProductName,
    SUM(o.OrderQty) AS TotalQty
FROM FactOrders AS o
JOIN DimDate AS d ON o.OrderDateKey = d.date_key
JOIN DimProduct AS p ON o.ProductKey = p.ProductKey
WHERE d.full_date = CAST(GETDATE() AS DATE)
GROUP BY p.ProductID, p.ProductName
ORDER BY TotalQty ASC;


Input: Quels sont les 10 produits livrés le moins aujourd’hui ?

Output:
SELECT TOP (10)
    p.ProductID,
    p.ProductName,
    SUM(fd.QuantiteDelivered) AS TotalDeliveredQty
FROM FactDelivery fd
JOIN DimDate d ON fd.DeliveredDateKey = d.date_key
JOIN DimProduct p ON fd.ProductKey = p.ProductKey
WHERE d.full_date = CAST(GETDATE() AS date)
GROUP BY p.ProductID, p.ProductName
ORDER BY TotalDeliveredQty ASC;


Input: Quels sont les Top employées en chiffre d’affaires livré ?

Output:
SELECT TOP (10)
    e.EmployeeFullName AS EmployeeName,
    SUM(fd.AmountAfterDiscount) AS DeliveredRevenue
FROM FactDelivery fd
JOIN DimEmployee e ON fd.EmplyeeKey = e.EmployeeKey
GROUP BY e.EmployeeFullName
ORDER BY DeliveredRevenue DESC;


Input: Quels sont les Top employées en chiffre d’affaires commandé ?

Output:
SELECT TOP 10
    e.EmployeeFullName AS EmployeeName,
    SUM(o.AmountAfterDiscount) AS ChiffreAffaires
FROM FactOrders o
JOIN DimEmployee e ON o.EmployeeKey = e.EmployeeKey
GROUP BY e.EmployeeFullName
ORDER BY ChiffreAffaires DESC;


Input: Quelles sont les routes avec plus faibles quantité livrés ?

Output:
SELECT
    dg.Route,
    SUM(fd.QuantiteDelivered) AS TotalQuantiteDelivered
FROM FactDelivery fd
JOIN DimGeography dg ON fd.GeographyKey = dg.GeographyID
GROUP BY dg.Route
ORDER BY TotalQuantiteDelivered ASC;


Input: Quelles sont les routes avec plus faibles quantité vendues ?

Output:
SELECT
    dg.Route,
    SUM(fo.OrderQty) AS TotalQuantity
FROM FactOrders AS fo
JOIN DimGeography AS dg
    ON fo.GeographyKey = dg.GeographyID
GROUP BY dg.Route
ORDER BY TotalQuantity ASC;


Input: Quelles sont les routes avec plus faibles montant vendues ?

Output:
SELECT g.Route,
       SUM(o.AmountAfterDiscount) AS TotalSales
FROM FactOrders AS o
JOIN DimGeography AS g
  ON o.GeographyKey = g.GeographyID
GROUP BY g.Route
ORDER BY TotalSales ASC;


Input: Quelles sont les routes avec plus faibles montant livrés ?

Output:
WITH RouteDelivery AS (
    SELECT g.Route,
           SUM(fd.AmountAfterDiscount) AS TotalDeliveredAmount
    FROM FactDelivery fd
    JOIN DimGeography g
      ON fd.GeographyKey = g.GeographyID
    WHERE fd.IsDelivered = 1
    GROUP BY g.Route
)
SELECT Route,
       TotalDeliveredAmount
FROM RouteDelivery
ORDER BY TotalDeliveredAmount ASC;


Input: Quelles sont les régions avec la meilleure progression du chiffre d'affaire pendant les trois premiers mois de l'année 2025

Output:
WITH MonthlyCA AS (
    SELECT g.Region,
           d.month_num_in_year AS MonthNum,
           SUM(o.AmountAfterDiscount) AS CA
    FROM FactOrders o
    JOIN DimDate d ON o.OrderDateKey = d.date_key
    JOIN DimGeography g ON o.GeographyKey = g.GeographyID
    WHERE d.year = 2025
      AND d.month_num_in_year IN (1, 2, 3)
    GROUP BY g.Region, d.month_num_in_year
),
RegionProgress AS (
    SELECT
        Region,
        SUM(CASE WHEN MonthNum = 1 THEN CA ELSE 0 END) AS CA_Jan,
        SUM(CASE WHEN MonthNum = 2 THEN CA ELSE 0 END) AS CA_Feb,
        SUM(CASE WHEN MonthNum = 3 THEN CA ELSE 0 END) AS CA_Mar,
        CASE
            WHEN SUM(CASE WHEN MonthNum = 1 THEN CA ELSE 0 END) = 0 THEN NULL
            ELSE (SUM(CASE WHEN MonthNum = 3 THEN CA ELSE 0 END) - SUM(CASE WHEN MonthNum = 1 THEN CA ELSE 0 END))
                 / NULLIF(SUM(CASE WHEN MonthNum = 1 THEN CA ELSE 0 END), 0)
        END AS ProgressionPct
    FROM MonthlyCA
    GROUP BY Region
)
SELECT Region,
       CA_Jan,
       CA_Feb,
       CA_Mar,
       ProgressionPct
FROM RegionProgress
WHERE ProgressionPct IS NOT NULL
ORDER BY ProgressionPct DESC;


Input: Quels produits génèrent 80% des livraison ?

Output:
WITH ProductDelivery AS (
    SELECT d.ProductKey,
           p.ProductName,
           SUM(d.AmountAfterDiscount) AS TotalAmount
    FROM FactDelivery d
    JOIN DimProduct p ON d.ProductKey = p.ProductKey
    GROUP BY d.ProductKey, p.ProductName
),
Total AS (
    SELECT SUM(TotalAmount) AS GrandTotal
    FROM ProductDelivery
),
Ranked AS (
    SELECT pd.ProductKey,
           pd.ProductName,
           pd.TotalAmount,
           SUM(pd.TotalAmount) OVER (ORDER BY pd.TotalAmount DESC ROWS UNBOUNDED PRECEDING) AS CumulativeAmount,
           t.GrandTotal,
           (SUM(pd.TotalAmount) OVER (ORDER BY pd.TotalAmount DESC ROWS UNBOUNDED PRECEDING) * 100.0) / t.GrandTotal AS CumulativePct
    FROM ProductDelivery pd
    CROSS JOIN Total t
)
SELECT ProductKey,
       ProductName,
       TotalAmount,
       CumulativePct
FROM Ranked
WHERE CumulativePct <= 80
ORDER BY CumulativePct ASC;


Input: Quels produits génèrent 50% des ventes ?

Output:
WITH ProductSales AS (
    SELECT p.ProductKey,
           p.ProductName,
           SUM(o.AmountAfterDiscount) AS SalesAmount
    FROM FactOrders AS o
    INNER JOIN DimProduct AS p ON o.ProductKey = p.ProductKey
    GROUP BY p.ProductKey, p.ProductName
),
TotalSales AS (
    SELECT SUM(SalesAmount) AS TotalAmount
    FROM ProductSales
),
RankedSales AS (
    SELECT ps.ProductKey,
           ps.ProductName,
           ps.SalesAmount,
           SUM(ps.SalesAmount) OVER (ORDER BY ps.SalesAmount DESC ROWS UNBOUNDED PRECEDING) AS CumulativeSales,
           ts.TotalAmount
    FROM ProductSales AS ps
    CROSS JOIN TotalSales AS ts
)
SELECT ProductKey,
       ProductName,
       SalesAmount
FROM RankedSales
WHERE CumulativeSales <= 0.5 * TotalAmount
ORDER BY SalesAmount DESC;


Input: Quels famille de produit génèrent 50% des livraison ?

Output:
WITH FamilleQty AS (
    SELECT f.FamilleKey,
           fam.FamilleName,
           SUM(d.QuantiteDelivered) AS TotalQty
    FROM FactDelivery d
    INNER JOIN DimProduct p ON d.ProductKey = p.ProductKey
    INNER JOIN DimFamille fam ON p.FamilleKey = fam.FamilleKey
    GROUP BY f.FamilleKey, fam.FamilleName
),
TotalQty AS (
    SELECT SUM(TotalQty) AS GrandTotal
    FROM FamilleQty
),
Cumulative AS (
    SELECT fq.FamilleKey,
           fq.FamilleName,
           fq.TotalQty,
           SUM(fq.TotalQty) OVER (ORDER BY fq.TotalQty DESC) AS CumQty,
           tq.GrandTotal,
           (SUM(fq.TotalQty) OVER (ORDER BY fq.TotalQty DESC) * 100.0) / tq.GrandTotal AS CumPct
    FROM FamilleQty fq
    CROSS JOIN TotalQty tq
)
SELECT FamilleName,
       TotalQty,
       CumPct
FROM Cumulative
WHERE CumPct <= 50.0
ORDER BY CumPct ASC;


Input: Quels produits génèrent 80% des retour?

Output:
WITH ProductReturns AS (
    SELECT d.ProductKey,
           p.ProductName,
           SUM(d.AmountAfterDiscount) AS ReturnAmount
    FROM FactDelivery d
    INNER JOIN DimProduct p ON d.ProductKey = p.ProductKey
    GROUP BY d.ProductKey, p.ProductName
),
TotalReturn AS (
    SELECT SUM(ReturnAmount) AS TotalAmount
    FROM ProductReturns
),
Ranked AS (
    SELECT pr.ProductKey,
           pr.ProductName,
           pr.ReturnAmount,
           SUM(pr.ReturnAmount) OVER (ORDER BY pr.ReturnAmount DESC) AS CumSum,
           CAST(SUM(pr.ReturnAmount) OVER (ORDER BY pr.ReturnAmount DESC) AS float) / NULLIF(t.TotalAmount, 0) AS CumPct
    FROM ProductReturns pr
    CROSS JOIN TotalReturn t
)
SELECT ProductKey,
       ProductName,
       ReturnAmount,
       CumPct
FROM Ranked
WHERE CumPct <= 0.8
ORDER BY ReturnAmount DESC;


Input: Quels famille de produit génèrent 50% des retour ?

Output:
WITH FamilyRevenue AS (
    SELECT
        f.FamilleName,
        SUM(o.AmountAfterDiscount) AS FamilyAmount
    FROM FactOrders o
    INNER JOIN DimProduct p ON o.ProductKey = p.ProductKey
    INNER JOIN DimFamille f ON p.FamilleKey = f.FamilleKey
    GROUP BY f.FamilleName
), Totals AS (
    SELECT
        *,
        SUM(FamilyAmount) OVER () AS TotalAmount
    FROM FamilyRevenue
), Cumulative AS (
    SELECT
        FamilleName,
        FamilyAmount,
        TotalAmount,
        SUM(FamilyAmount) OVER (ORDER BY FamilyAmount DESC ROWS UNBOUNDED PRECEDING) AS CumAmount,
        100.0 * SUM(FamilyAmount) OVER (ORDER BY FamilyAmount DESC ROWS UNBOUNDED PRECEDING) / TotalAmount AS CumPct
    FROM Totals
)
SELECT
    FamilleName,
    FamilyAmount,
    CumPct
FROM Cumulative
WHERE CumPct <= 50
ORDER BY CumPct ASC;


Input: Comment évoluent les ventes pendant le mois de septembre ?

Output:
SELECT
    d.day_num_in_month AS DayOfMonth,
    SUM(o.AmountAfterDiscount) AS TotalSales
FROM FactOrders AS o
JOIN DimDate AS d ON o.OrderDateKey = d.date_key
WHERE d.month_name = N'September'
  AND d.year = YEAR(GETDATE())
GROUP BY d.day_num_in_month
ORDER BY d.day_num_in_month;


Input: Comment évoluent les ventes par mois ?

Output:
SELECT
    d.[year]      AS Annee,
    d.[month_name] AS Mois,
    SUM(o.[AmountAfterDiscount]) AS ChiffreAffaires
FROM dbo.FactOrders AS o
JOIN dbo.DimDate AS d
    ON o.[OrderDateKey] = d.[date_key]
GROUP BY
    d.[year],
    d.[month_num_in_year],
    d.[month_name]
ORDER BY
    d.[year],
    d.[month_num_in_year];


Input: Quelle région progresse le plus par rapport aux livraisons ?

Output:
WITH MaxPeriod AS (
    SELECT MAX(d.year) AS MaxYear,
           MAX(d.month_num_in_year) AS MaxMonth
    FROM DimDate d
    JOIN FactDelivery fd ON fd.DeliveredDateKey = d.date_key
),
CurrentPeriod AS (
    SELECT g.Region,
           SUM(fd.AmountAfterDiscount) AS CurrentAmt
    FROM FactDelivery fd
    JOIN DimDate d ON fd.DeliveredDateKey = d.date_key
    JOIN DimGeography g ON fd.GeographyKey = g.GeographyID
    CROSS JOIN MaxPeriod mp
    WHERE d.year = mp.MaxYear
      AND d.month_num_in_year = mp.MaxMonth
    GROUP BY g.Region
),
PrevPeriod AS (
    SELECT g.Region,
           SUM(fd.AmountAfterDiscount) AS PrevAmt
    FROM FactDelivery fd
    JOIN DimDate d ON fd.DeliveredDateKey = d.date_key
    JOIN DimGeography g ON fd.GeographyKey = g.GeographyID
    CROSS JOIN MaxPeriod mp
    WHERE (
            d.year = mp.MaxYear AND d.month_num_in_year = mp.MaxMonth - 1
          ) OR (
            mp.MaxMonth = 1 AND d.year = mp.MaxYear - 1 AND d.month_num_in_year = 12
          )
    GROUP BY g.Region
)
SELECT TOP 1
    c.Region,
    ISNULL(c.CurrentAmt, 0) AS CurrentAmount,
    ISNULL(p.PrevAmt, 0) AS PreviousAmount,
    CASE WHEN ISNULL(p.PrevAmt, 0) = 0 THEN NULL
         ELSE (ISNULL(c.CurrentAmt, 0) - p.PrevAmt) / NULLIF(p.PrevAmt, 0) * 100
    END AS GrowthPct
FROM CurrentPeriod c
LEFT JOIN PrevPeriod p ON c.Region = p.Region
ORDER BY GrowthPct DESC;


Input: Quelle région regresse le plus par rapport aux livraisons ?

Output:
WITH MaxDateCTE AS (
    SELECT MAX(d.full_date) AS MaxDate
    FROM FactDelivery fd
    JOIN DimDate d ON fd.DeliveredDateKey = d.date_key
),
Aggregated AS (
    SELECT
        g.Region,
        CASE
            WHEN d.full_date >= DATEFROMPARTS(YEAR(m.MaxDate), MONTH(m.MaxDate), 1)
                 AND d.full_date < DATEADD(month, 1, DATEFROMPARTS(YEAR(m.MaxDate), MONTH(m.MaxDate), 1))
            THEN 'Current'
            WHEN d.full_date >= DATEADD(month, -1, DATEFROMPARTS(YEAR(m.MaxDate), MONTH(m.MaxDate), 1))
                 AND d.full_date < DATEFROMPARTS(YEAR(m.MaxDate), MONTH(m.MaxDate), 1)
            THEN 'Previous'
        END AS Period,
        SUM(fd.AmountAfterDiscount) AS TotalAmount
    FROM FactDelivery fd
    JOIN DimDate d ON fd.DeliveredDateKey = d.date_key
    JOIN DimGeography g ON fd.GeographyKey = g.GeographyID
    CROSS JOIN MaxDateCTE m
    GROUP BY g.Region,
        CASE
            WHEN d.full_date >= DATEFROMP ARTS(YEAR(m.MaxDate), MONTH(m.MaxDate), 1)
                 AND d.full_date < DATEADD(month, 1, DATEFROMPARTS(YEAR(m.MaxDate), MONTH(m.MaxDate), 1))
            THEN 'Current'
            WHEN d.full_date >= DATEADD(month, -1, DATEFROMPARTS(YEAR(m.MaxDate), MONTH(m.MaxDate), 1))
                 AND d.full_date < DATEFROMPARTS(YEAR(m.MaxDate), MONTH(m.MaxDate), 1)
            THEN 'Previous'
        END
),
Pivoted AS (
    SELECT
        Region,
        SUM(CASE WHEN Period = 'Current' THEN TotalAmount ELSE 0 END) AS CurrentAmt,
        SUM(CASE WHEN Period = 'Previous' THEN TotalAmount ELSE 0 END) AS PreviousAmt
    FROM Aggregated
    GROUP BY Region
)
SELECT TOP 1
    Region,
    (CurrentAmt - PreviousAmt) AS AmountChange
FROM Pivoted
ORDER BY AmountChange ASC; -- la variation la plus négative correspond à la plus forte régression


Input: Quel est le taux de livraison global (quantité livrée / quantité commandée) aujourd'hui ?

Output:
DECLARE @todayKey int = (SELECT date_key FROM DimDate WHERE full_date = CAST(GETDATE() AS date));

SELECT
    CASE WHEN o.TotalOrdered = 0 THEN NULL
         ELSE CAST(d.TotalDelivered AS float) / o.TotalOrdered
    END AS DeliveryRate
FROM
    (SELECT SUM(QuantiteDelivered) AS TotalDelivered
     FROM FactDelivery
     WHERE DeliveredDateKey = @todayKey) d
CROSS JOIN
    (SELECT SUM(OrderQty) AS TotalOrdered
     FROM FactOrders
     WHERE OrderDateKey = @todayKey) o;


Input: Quels clients reçoivent leurs commandes en moins de 24 heures en moyenne ?

Output:
SELECT
    c.CustomerKey,
    c.CustomerFullName,
    AVG(DATEDIFF(hour, od.full_date, dd.full_date)) AS AvgDeliveryHours
FROM FactOrders fo
JOIN DimDate od ON fo.OrderDateKey = od.date_key
JOIN DimDate dd ON fo.DeliveredDateKey = dd.date_key
JOIN DimCustomer c ON fo.CustomerKey = c.CustomerKey
GROUP BY c.CustomerKey, c.CustomerFullName
HAVING AVG(DATEDIFF(hour, od.full_date, dd.full_date)) <= 24;


Input: Combien de commandes ont été livrées avec un retard de plus de 48h cette semaine ?

Output:
SELECT COUNT(DISTINCT fd.MouvementNumber) AS CommandesRetardées
FROM FactDelivery fd
JOIN DimDate od ON fd.OrderDateKey = od.date_key
JOIN DimDate dd ON fd.DeliveredDateKey = dd.date_key
WHERE fd.IsDelivered = 1
  AND DATEDIFF(hour, od.full_date, dd.full_date) > 48
  AND dd.week_num_in_year = DATEPART(week, GETDATE())
  AND dd.year = YEAR(GETDATE());


Input: Quels produits sont actuellement en rupture de stock suite aux commandes du matin ?

Output:
SELECT DISTINCT
    p.ProductKey,
    p.ProductID,
    p.ProductName,
    p.ProductReference
FROM FactOrders fo
JOIN DimTime dt ON fo.TimeKey = dt.time_key
JOIN DimProduct p ON fo.ProductKey = p.ProductKey
WHERE dt.day_part = 'Matin'
  AND fo.IsStocked = 0;


Input: Combien de livraisons ont été effectuées aujourd'hui ?

Output:
SELECT COUNT(*) AS LivraisonCount
FROM FactDelivery fd
JOIN DimDate d ON fd.DeliveredDateKey = d.date_key
WHERE d.full_date = CAST(GETDATE() AS date)
  AND fd.IsDelivered = 1;


Input: Quelle est la Wilaya qui reçoit le plus gros volume de marchandises par semaine ?

Output:
WITH WeeklyVolume AS (
    SELECT
        g.Wilaya,
        d.week_num_in_year,
        SUM(fd.QuantiteDelivered) AS weekly_qty
    FROM FactDelivery fd
    INNER JOIN DimGeography g ON fd.GeographyKey = g.GeographyID
    INNER JOIN DimDate d ON fd.DeliveredDateKey = d.date_key
    GROUP BY g.Wilaya, d.week_num_in_year
)
SELECT TOP 1
    Wilaya,
    weekly_qty AS VolumeMarchandises
FROM WeeklyVolume
ORDER BY weekly_qty DESC;


Input: Quel pourcentage de commandes est livré totalement (sans aucun produit manquant) ?

Output:
SELECT CAST(100.0 * SUM(CASE WHEN IsDelivered = 1 THEN 1 ELSE 0 END) / COUNT(*) AS decimal(5,2)) AS PercentFullyDelivered
FROM FactOrders;


Input: Quel est le poids moyen d'une livraison pour la famille Frutty 1,25 L ?

Output:
SELECT AVG(p.Weight) AS AvgWeight
FROM FactDelivery d
JOIN DimProduct p ON d.ProductKey = p.ProductKey
WHERE p.ProductFamily = N'Frutty 1,25 L';


Input: Quelles sont les commandes qui traînent depuis plus de 3 jours sans être livrées ?

Output:
SELECT
    o.SalesOrderNum,
    o.SalesOrderLineID,
    o.CustomerKey,
    d.full_date AS OrderDate,
    o.AmountAfterDiscount
FROM FactOrders AS o
JOIN DimDate AS d ON o.OrderDateKey = d.date_key
WHERE o.IsDelivered = 0
  AND d.full_date <= DATEADD(day, -3, CAST(GETDATE() AS date))
ORDER BY d.full_date DESC;


Input: Quel est le volume total des marchandises livrées par la région Est hier ?

Output:
SELECT SUM(p.volume * fd.QuantiteDelivered) AS TotalVolumeDelivered
FROM FactDelivery fd
JOIN DimProduct p ON fd.ProductKey = p.ProductKey
JOIN DimGeography g ON fd.GeographyKey = g.GeographyID
JOIN DimDate d ON fd.DeliveredDateKey = d.date_key
WHERE g.Region = N'Est'
  AND d.full_date = CAST(DATEADD(day, -1, GETDATE()) AS date);


Input: Quelle est la région où le volume de livraison a le plus progressé ce mois-ci par rapport au mois précédent  ?

Output:
WITH DeliveryAgg AS (
    SELECT
        g.Region,
        d.year,
        d.month_num_in_year AS month,
        SUM(fd.QuantiteDelivered) AS total_qty
    FROM FactDelivery fd
    JOIN DimDate d ON fd.DeliveredDateKey = d.date_key
    JOIN DimGeography g ON fd.GeographyKey = g.GeographyID
    GROUP BY g.Region, d.year, d.month_num_in_year
),
CurrentMonth AS (
    SELECT *
    FROM DeliveryAgg
    WHERE year = YEAR(GETDATE())
      AND month = MONTH(GETDATE())
),
PreviousMonth AS (
    SELECT *
    FROM DeliveryAgg
    WHERE (
            (year = YEAR(GETDATE()) AND month = MONTH(GETDATE()) - 1)
            OR (MONTH(GETDATE()) = 1 AND year = YEAR(GETDATE()) - 1 AND month = 12)
          )
)
SELECT TOP 1
    cm.Region,
    (cm.total_qty - ISNULL(pm.total_qty, 0)) AS VolumeIncrease
FROM CurrentMonth cm
LEFT JOIN PreviousMonth pm
    ON cm.Region = pm.Region
ORDER BY VolumeIncrease DESC;


Input: Quelle est la capacité de chargement utilisée en moyenne par camion de livraison ?

Output:
SELECT
    dc.CamionID,
    dc.CamionDesignation,
    AVG(fd.QuantiteDelivered) AS AvgLoadUsed
FROM FactDelivery fd
INNER JOIN DimCamion dc ON fd.CamionKey = dc.CamionKey
WHERE fd.IsDelivered = 1 -- ne considérer que les livraisons effectivement réalisées
GROUP BY dc.CamionID, dc.CamionDesignation
ORDER BY AvgLoadUsed DESC;


Input: Quelle est la fréquence de livraison moyenne par client et par mois ?

Output:
WITH MonthlyDeliveries AS (
    SELECT
        fd.CustomerKey,
        dc.CustomerFullName,
        DATEPART(year, dd.full_date) AS [Year],
        DATEPART(month, dd.full_date) AS [Month],
        COUNT(*) AS DeliveryCount
    FROM FactDelivery fd
    JOIN DimDate dd ON fd.DeliveredDateKey = dd.date_key
    JOIN DimCustomer dc ON fd.CustomerKey = dc.CustomerKey
    GROUP BY
        fd.CustomerKey,
        dc.CustomerFullName,
        DATEPART(year, dd.full_date),
        DATEPART(month, dd.full_date)
)
SELECT
    CustomerKey,
    CustomerFullName,
    AVG(CAST(DeliveryCount AS float)) AS AvgDeliveriesPerMonth
FROM MonthlyDeliveries
GROUP BY
    CustomerKey,
    CustomerFullName
ORDER BY AvgDeliveriesPerMonth DESC;


Input: Quel est le taux de livraison moyen ( quantité livré/ quantité commandé) par type de commerce ce mois ci  ?

Output:
WITH OrdersCTE AS (
    SELECT o.CustomerKey, o.OrderQty
    FROM FactOrders o
    INNER JOIN DimDate d ON o.OrderDateKey = d.date_key
    WHERE d.year = YEAR(GETDATE())
      AND d.month_num_in_year = MONTH(GETDATE())
),
DeliveryCTE AS (
    SELECT fd.CustomerKey, fd.QuantiteDelivered
    FROM FactDelivery fd
    INNER JOIN DimDate dd ON fd.DeliveredDateKey = dd.date_key
    WHERE dd.year = YEAR(GETDATE())
      AND dd.month_num_in_year = MONTH(GETDATE())
)
SELECT c.BusinessType,
       CASE WHEN NULLIF(SUM(o.OrderQty), 0) = 0 THEN 0
            ELSE CAST(SUM(d.QuantiteDelivered) AS float) / SUM(o.OrderQty)
       END AS DeliveryRate
FROM DimCustomer c
LEFT JOIN OrdersCTE o ON c.CustomerKey = o.CustomerKey
LEFT JOIN DeliveryCTE d ON c.CustomerKey = d.CustomerKey
GROUP BY c.BusinessType
ORDER BY c.BusinessType;


Input: Quels produits ont vu leur volume de livraison doubler par rapport au mois dernier ?

Output:
WITH CurrentMonth AS (
    SELECT fd.ProductKey,
           SUM(fd.QuantiteDelivered) AS QtyCurrent
    FROM FactDelivery fd
    JOIN DimDate dd ON fd.DeliveredDateKey = dd.date_key
    WHERE dd.[year] = YEAR(GETDATE())
      AND dd.month_num_in_year = MONTH(GETDATE())
    GROUP BY fd.ProductKey
),
PrevMonth AS (
    SELECT fd.ProductKey,
           SUM(fd.QuantiteDelivered) AS QtyPrev
    FROM FactDelivery fd
    JOIN DimDate dd ON fd.DeliveredDateKey = dd.date_key
    WHERE dd.[year] = YEAR(DATEADD(month, -1, GETDATE()))
      AND dd.month_num_in_year = MONTH(DATEADD(month, -1, GETDATE()))
    GROUP BY fd.ProductKey
)
SELECT p.ProductName,
       p.ProductID,
       cm.QtyCurrent,
       pm.QtyPrev
FROM CurrentMonth cm
JOIN PrevMonth pm ON cm.ProductKey = pm.ProductKey
JOIN DimProduct p ON p.ProductKey = cm.ProductKey
WHERE cm.QtyCurrent >= 2 * pm.QtyPrev
ORDER BY cm.QtyCurrent DESC;


Input: Combien de clients ont reçu plus d'une livraison dans la même journée pendant cette semaine ?

Output:
WITH DeliveriesThisWeek AS (
    SELECT fd.CustomerKey, dd.full_date
    FROM FactDelivery fd
    JOIN DimDate dd ON fd.DeliveredDateKey = dd.date_key
    WHERE dd.year = YEAR(GETDATE())
      AND DATEPART(week, dd.full_date) = DATEPART(week, GETDATE())
)
SELECT COUNT(DISTINCT CustomerKey) AS ClientsAvecPlusDuneLivraison
FROM (
    SELECT CustomerKey, full_date, COUNT(*) AS cnt
    FROM DeliveriesThisWeek
    GROUP BY CustomerKey, full_date
    HAVING COUNT(*) > 1
) AS t;


Input: Quelle est la part des livraisons effectuées le samedi dans le volume total ?

Output:
SELECT CAST(100.0 * SUM(CASE WHEN d.day_name = 'Saturday' THEN fd.QuantiteDelivered ELSE 0 END) / NULLIF(SUM(fd.QuantiteDelivered), 0) AS decimal(5,2)) AS SaturdayDeliverySharePct
FROM FactDelivery fd
JOIN DimDate d ON fd.DeliveredDateKey = d.date_key;


Input: Quels créneaux horaires de livraison sont les plus denses en nombre de clients ?

Output:
SELECT
    dt.hour,
    dt.day_part,
    COUNT(DISTINCT fd.CustomerKey) AS ClientCount
FROM FactDelivery fd
JOIN DimTime dt ON fd.TimeKey = dt.time_key
GROUP BY dt.hour, dt.day_part
ORDER BY ClientCount DESC;


Input: Quels produits du catalogue ont été livrés à 100% sans aucun manquant cette année ?

Output:
WITH OrderAgg AS (
    SELECT fo.ProductKey,
           SUM(fo.OrderQty) AS TotalOrdered
    FROM FactOrders fo
    JOIN DimDate dd ON fo.OrderDateKey = dd.date_key
    WHERE dd.[year] = YEAR(GETDATE())
    GROUP BY fo.ProductKey
),
DeliveryAgg AS (
    SELECT fd.ProductKey,
           SUM(fd.QuantiteDelivered) AS TotalDelivered
    FROM FactDelivery fd
    JOIN DimDate dd ON fd.DeliveredDateKey = dd.date_key
    WHERE dd.[year] = YEAR(GETDATE())
    GROUP BY fd.ProductKey
)
SELECT p.ProductID,
       p.ProductName
FROM DimProduct p
JOIN OrderAgg o ON p.ProductKey = o.ProductKey
JOIN DeliveryAgg d ON p.ProductKey = d.ProductKey
WHERE o.TotalOrdered = d.TotalDelivered
  AND o.TotalOrdered > 0;


Input: Combien de clients ont été livrés pour une valeur supérieure à 12000 Da aujourd'hui ?

Output:
SELECT COUNT(DISTINCT fd.CustomerKey) AS ClientCount
FROM FactDelivery fd
JOIN DimDate dd ON fd.DeliveredDateKey = dd.date_key
WHERE dd.full_date = CAST(GETDATE() AS date)
  AND fd.AmountAfterDiscount > 12000;


Input: Quelle famille de produits occupe le plus de volume de livraison ce trimestre ?

Output:
SELECT TOP 1
    df.FamilleName AS ProductFamily,
    SUM(fd.QuantiteDelivered * dp.volume) AS TotalVolume
FROM FactDelivery fd
JOIN DimDate dd ON fd.DeliveredDateKey = dd.date_key
JOIN DimProduct dp ON fd.ProductKey = dp.ProductKey
JOIN DimFamille df ON dp.FamilleKey = df.FamilleKey
WHERE dd.year = YEAR(GETDATE())
  AND dd.quarter = DATEPART(QUARTER, GETDATE())
GROUP BY df.FamilleName
ORDER BY TotalVolume DESC;