2009-12-21 5 views
3

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

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. 

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

Любые советы, оцененные.

+0

У вас есть возможность использовать SSAS. У этого есть некоторые возможности, которые делают это довольно легким. – DrewM

+1

Получение информации легко, ее форматирование в макете, которое вы предоставили, было бы больно.Обычно суммарные суммы и вычисления отображаются только в конце набора результатов. –

+0

+1 комментарий к Ponies. SQL не является правильным инструментом для форматирования вывода. –

ответ

1

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

sales_model_02

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

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

Затем мы получаем общее количество для каждого в заданном p eriod (YEAR = 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

Это прекрасно работает, когда все продавцы рассматриваются в одной категории. Как бы вы настроили его, чтобы обеспечить совокупные сравнения посредством трехуровневой иерархии (человек против филиала, человек против региона, человек против страны)? –

+0

Обеспечить, что лицо находится в отрасли, регионе, стране - 'WHERE [Year] = 2009 AND [Region] = 'North'', или' WHERE [Year] = 2009 AND [Country] =' Canada''; по существу фильтр на ветке, регионе, стране. –

+0

Спасибо, Дамир. Вы правы, это даст мне то, что мне нужно для одного человека. Я действительно думал о том, как запустить набор результатов для нескольких людей одновременно. Я не уверен, как легко будет работать эта группировка. Любые идеи? –

0

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

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 определенно может быть улучшен, но уже поздно, и я не могу думать прямо ..)

0

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

Например:

(Sum(Fields!Sales.Value, "table1") - Fields!Sales.Value) 
/
(Sum(Fields!NumSales.Value, "table1") - Fields!NumSales.Value) 
0

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

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