Нужна помощь с запросом агрегации SQL - PullRequest
3 голосов
/ 22 декабря 2009

Какой самый простой подход к созданию набора данных, который можно использовать в отчете служб отчетов SQL Server для отображения следующего:

SalesPerson        # Sales        # Gross        Profit
John Doe               100       $140,000       $25,000
Everyone Else (Avg.)  1200     $2,000,000      $250,000


Jane Smith              80       $100,000       $15,000
Everyone Else (Avg.)  1220     $2,040,000      $260,000


...and so on.

Это очень, очень упрощенный пример того, что я пытаюсь сделать (например, реальный сценарий включает показ «Все остальное» разбито на три категориальные строки), но он иллюстрирует основную цель отображения агрегата данные для каждого человека с сопоставлением со всеми остальными (эксклюзив). Псевдокод будет в порядке. Мой первый удар по коду SQL для этого довольно быстро запутался, и я знаю, что должен быть более прямой метод.

Любые советы приветствуются.

Ответы [ 4 ]

1 голос
/ 22 декабря 2009

Если вы не возражаете против форматирования позже, тогда, если мы предполагаем, что у вас есть что-то вроде:

sales_model_02

Сначала мне понадобятся вспомогательные переменные для общего количества

/* Few helper variables*/
DECLARE @TotalQuantity int
       ,@TotalAmount decimal(19, 4)
       ,@TotalProfit decimal(19, 4)
       ,@EveryoneElse int

Затем мы получаем общее количество для всех в данный период (ГОД = 2009)

/* Fetch totals in the period*/
SELECT  @TotalQuantity = sum(SalesQuantity)
       ,@TotalAmount = sum(SalesAmount)
       ,@TotalProfit = sum(Profit)
       ,@EveryoneElse = count(DISTINCT SalesPersonKey) - 1
FROM   factSales AS s
       JOIN dimDate AS d ON s.DateKey = d.DateKey
WHERE   [Year] = 2009

/* Now we have totals for everyone in the period */

А теперь для каждого человека против всех, но все в один ряд.

/* Totals for each sales person vs everyone else Average */
SELECT  FullName
       ,SUM(SalesQuantity) AS [PersonSalesCount]
       ,SUM(SalesAmount) AS [PersonSalesAmount]
       ,SUM(Profit) AS [PersonSalesProfit]
       ,( @TotalQuantity - SUM(SalesQuantity) ) / @EveryoneElse AS [EveryoneElseAvgSalesCount]
       ,( @TotalAmount - SUM(SalesAmount) ) / @EveryoneElse AS [EveryoneElseAvgSalesAmount]
       ,( @TotalProfit - SUM(Profit) ) / @EveryoneElse AS [EveryoneElseAvgSalesProfit]
FROM    factSales AS s
        JOIN dimDate AS d ON s.DateKey = d.DateKey
        RIGHT JOIN dimSalesPerson AS p ON p.SalesPersonKey = s.SalesPersonKey
WHERE   [Year] = 2009
GROUP BY FullName

Теперь вы можете упаковать все это в хранимую процедуру с параметром (ами) для интервала даты. Возможно, все еще нужно настроить количество продавцов, чтобы определить, кто был активен в определенный период и как считать тех, кто ничего не продавал. При этом EveryoneElse означает количество продавцов, которые продали что-то -1; так что если у вас есть 10 продавцов и только 5 продали что-то, то EveryoneElse = 4.

0 голосов
/ 22 декабря 2009

Я делаю некоторые предположения здесь, но если у вас есть такая таблица

If object_id('Sales') is not null 
  Drop table Sales

CREATE TABLE [dbo].[Sales]
(
 [Salesperson] [nvarchar](50) NULL,
 [Sales] [int] NULL,
 [Gross] [money] NULL,
 [Profit] [money] NULL,
)

Это заполнено данными, такими как

Insert into Sales values ('John Doe', 100, 200.00, 100.00)
Insert into Sales values ('John Doe', 125, 300.00, 100.00)
Insert into Sales values ('Jane Smith', 100, 200.00, 100.00)
Insert into Sales values ('Jane Smith', 125, 1.00, 0.50)
Insert into Sales values ('Joel Spolsky', 100, 2.00, 1.00)
Insert into Sales values ('Joel Spolsky', 125, 3.00, 1.00)

Тогда такая хранимая процедура может дать вам то, что вы ищете

If object_id('usp_SalesReport') is not null 
Drop procedure usp_SalesReport

Go


Create Procedure usp_SalesReport
as
Declare @results as table
(
 SalesPerson nvarchar(50),
 Sales int,
 Gross money,
 Profit money
)

Declare  @SalesPerson nvarchar(50)
Declare SalesSums CURSOR FOR

Select  distinct SalesPerson from Sales

Open SalesSums

Fetch SalesSums INTO @SalesPerson

While @@Fetch_Status = 0

Begin
 Insert into @results Select Sales.Salesperson, sum(sales), sum(Gross), sum(profit) from Sales group by Sales.Salesperson having Sales.Salesperson = @SalesPerson
 Insert into @results Select 'EveryoneElse', avg(sales), avg(Gross), avg(profit) from Sales where Salesperson <> @SalesPerson

Fetch SalesSums INTO @SalesPerson          
End
Select * from @results
Close SalesSums
Deallocate SalesSums
Return
0 голосов
/ 22 декабря 2009

В SSRS поместите строку дополнительной информации в вашу таблицу. Затем используйте параметр Scope для агрегатных функций и сделайте среднее из первых принципов.

Например:

(Sum(Fields!Sales.Value, "table1") - Fields!Sales.Value) 
/
(Sum(Fields!NumSales.Value, "table1") - Fields!NumSales.Value)
0 голосов
/ 22 декабря 2009

Почти наверняка не очень производительно, но декларативно ясно:

declare @i int = 0
declare @j int = 1

select * from
(
select (@i = @i + 2) as order_col, SalesPerson, sales, gross, profit
from myTable order by SalesPerson

union all

select (@j = @j + 2) as order_col, 'Everybody else'
, (select sum(sales) from myTable i where i.SalesPerson <> o.Salesperson)
, (select sum(gross) from myTable i where i.SalesPerson <> o.Salesperson)
, (select sum(profit) from myTable i where i.SalesPerson <> o.Salesperson)
from myTable o
order by SalesPerson
) x order by order_col

(Вторая часть UNION определенно может быть улучшена, но уже поздно, и я не могу думать прямо ...)

...