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

Это значения, которые мне нужно вернуть из хранимой процедуры:

Description
Week 1 Usage
Week 2 Usage
Usage Variance
Week 1 Price
Week 2 Price
Price Variance
% of Price Variance

Три поля с «Отклонением» в названии являются вычисляемыми полями на основе других значений, а разделы «Неделя» должны рассчитываться на основе параметров даты. Таким образом, фактические (наиболее важные) поля, которые находятся в таблицах базы данных:

Description
Usage
Price
InvoiceDate

Параметры, предоставляемые пользователем:

Unit
DateBegin
DateEnd

Переменные, которые, я думаю, мне нужно будет объявить в хранимой процедуре:

DECLARE 
@Week1Begin datetime, 
@Week1End datetime, 
@Week2Begin datetime, 
@Week2End datetime, 
@Week1Usage varchar(30),
@Week2Usage varchar(30),
@Week1Price varchar(30),
@Week2Price varchar(30),
@UsageVariance varchar(30),
@PriceVariance varchar(30),
@PercentageOfPriceVariance varchar(30)

Week1Begin и Week1End должны быть вычислены на основе значения, предоставленного пользователем в параметре DateBegin (например, если DateBegin будет 27.12.15, Week1Begin будет 27.12.2015, а Week1End будет 02.01.2016) ;

Week2Begin и Week2End будут похожи, но их период может быть менее семи дней, а если дольше, то максимум 7 дней (Week2End будет "сокращаться" до предыдущей даты по мере необходимости).

Таким образом, несмотря на то, что выполняется много вычислений, необработанных данных довольно мало. В основном это четыре поля, упомянутые выше (Описание, Использование, Цена и Дата счета), которые доступны из таблицы InvoiceDetail.

Моя самая большая дилемма заключается в том, что большая часть этих данных возвращается из существующей хранимой процедуры, которую лучше скопировать и расширить, но я никоим образом не являюсь экспертом по SQL - я могу писать простые операторы SELECT и UPDATE и т. д., но танцевать с временными таблицами и такими реляционными оборотами мне не по силам.

Таким образом, создание новой хранимой процедуры на основе существующей кажется опасным; OTOH, интересно, можно ли получить нужные мне данные, используя довольно минимальную хранимую процедуру со сложным оператором запроса, содержащим несколько подзапросов.

Опять же, сложный SQL ни в коем случае не является моей сильной стороной, поэтому я могу быть «далеким», но вот мой псевдо-SQL:

CREATE Procedure [dbo].[myFunkySP]
    @Unit varchar(25),
    @BegDate datetime,
    @EndDate datetime
As

// Create a mostly-empty-for-now temp table
Select  Description,
    Week1Begin,
    Week1End,
    Week2Begin,
    Week2End,
    Week1Usage,
    Week2Usage,
    Week1Price,
    Week2Price,
    UsageVariance,
    PriceVariance
    PercentageOfPriceVariance
    Into    #TempItems
    From    InvoiceDetail Ind
    Where   Ind.Unit = @Unit
    and Ind.InvoiceDate Between @BegDate and @EndDate


begin

    Update #TempItems set 
    Week1Begin = // val from@BegDate
    Week1End = // do some date math to determine; maybe a Function called GetEndOfWeek(Week1Begin)? 
    Week2Begin = // do some date math to determine (1 day beyond Week1End val)
    Week2End = // val from@EndDate
    Week1Usage = SELECT SUM(USAGE) FROM InvoiceDetail WHERE UNIT = @UNIT, DATE BETWEEN Week1Begin AND Week1End 
    Week2Usage = SELECT SUM(USAGE) FROM InvoiceDetail WHERE UNIT = @UNIT, DATE BETWEEN Week2Begin AND Week2End 
    Week1Price = SELECT SUM(PRICE) FROM InvoiceDetail WHERE UNIT = @UNIT, DATE BETWEEN Week1Begin AND Week1End
    Week2Price = SELECT SUM(PRICE) FROM InvoiceDetail WHERE UNIT = @UNIT, DATE BETWEEN Week2Begin AND Week2End
    UsageVariance = (Week2Usage - Week1Usage)
    PriceVariance = (Week2Price - Week1Price)
    PercentageOfPriceVariance = (PriceVariance div week2Price)

    // now select * from the temp table to return everything?

В противном случае (если вышеописанное не сработает или невыполнимо), я подумал, что мне, возможно, придется выполнить запрос 9-X-Uglier-than-a-of-butts, загрязненный подзапросами beaucoup, что-то вроде:

SELECT DESCRIPTION, 
    (SELECT SUM(USAGE) FROM InvoiceDetail
        WHERE UNIT = @UNIT, InvoiceDate BETWEEN :firstWeekBegin AND :firstWeekEnd as Week1Usage), 
    (SELECT SUM(USAGE) FROM InvoiceDetail
        WHERE UNIT = @UNIT, InvoiceDate BETWEEN :secondWeekBegin AND :secondWeekEnd as Week2Usage), 
    SELECT PRICE FROM InvoiceDetail 
        WHERE UNIT = @UNIT, InvoiceDate = firstWeekBegin as Week1Price), 
    (SELECT PRICE FROM InvoiceDetail    
        WHERE UNIT = @UNIT, InvoiceDate = secondWeekBegin as Week2Price), 
FROM InvoiceDetail
WHERE UNIT = @UNIT, InvoiceDate BETWEEN @BEGDATE AND @ENDATE ORDER BY PRODUCTS

Скажи, что это не так, Джо!

Даже если этот запутанный запрос работает, он все равно не дает мне расчетных значений, которые мне нужны (UsageVariance, PriceVariance и PercentageOfPriceVariance).

Итак, что мне нужно сделать, чтобы создать хранимую процедуру, которая будет возвращать нужные мне результаты?


person B. Clay Shannon    schedule 13.01.2016    source источник
comment
В качестве примечания: почему так много носителей английского языка так часто пишут хранимые процедуры? Насколько я знаю английский, вы пишете слова с заглавной буквы только в начале предложения или когда они обозначают что-то святое, королевское или географическое место — ни то, ни другое здесь не применимо — это просто процедура который хранится внутри вашей базы данных (в данном случае SQL Server) — почему так хочется использовать эти инициалы с большой буквы? </rant>   -  person marc_s    schedule 13.01.2016
comment
Я предпочитаю немецкий метод написания всех существительных с заглавной буквы; у каждого языка, наверное, есть свои плюсы. Мне нравятся перевернутые знаки вопроса и восклицательные знаки, которые в испанском языке используются в начале предложения, и его как можно короче у (или иногда е) вместо и, о (или иногда у) вместо или и а вместо того.   -  person B. Clay Shannon    schedule 13.01.2016


Ответы (3)


Расширенный комментарий, а не ответ
Часть UPDATE не нужна. Сначала вам нужно рассчитать week1end и week2bigin в начале SP. После этого инструкция SELECT довольно прямолинейна:

    DECLARE @Week1End datetime ,@Week2begin datetime

    Select  Description,
    @BegDate  BegDate,
    @Week1End Week1End,
    @Week1End Week2Begin,
    @EndDate EndDate,
    SUM(CASE WHEN Ind.InvoiceDate BETWEEN @BegDate AND @Week1End THEN Ind.Usage ELSE 0 END) Week1Usage,
    SUM(CASE WHEN Ind.InvoiceDate BETWEEN @Week2Begin AND @EndDate THEN Ind.Usage ELSE 0 END) Week2Usage,
    SUM(CASE WHEN Ind.InvoiceDate BETWEEN @BegDate AND @Week1End THEN Ind.Price ELSE 0 END) Week1Price,
    SUM(CASE WHEN Ind.InvoiceDate BETWEEN @Week2Begin AND @EndDate THEN Ind.Price ELSE 0 END) -
   SUM(CASE WHEN Ind.InvoiceDate BETWEEN @BegDate AND @Week1End THEN Ind.Usage ELSE 0 END) UsageVariance,
    SUM(CASE WHEN Ind.InvoiceDate BETWEEN @Week2Begin AND @EndDate THEN Ind.Usage ELSE 0 END)  -
    SUM(CASE WHEN Ind.InvoiceDate BETWEEN @BegDate AND @Week1End THEN Ind.Price ELSE 0 END) PriceVariance,
    (SUM(CASE WHEN Ind.InvoiceDate BETWEEN @Week2Begin AND @EndDate THEN Ind.Usage ELSE 0 END)  -
    SUM(CASE WHEN Ind.InvoiceDate BETWEEN @BegDate AND @Week1End THEN Ind.Price ELSE 0 END) )
    /     SUM(CASE WHEN Ind.InvoiceDate BETWEEN @BegDate AND @Week1End THEN Ind.Price ELSE 0 END)     
    PercentageOfPriceVariance
    From    InvoiceDetail Ind
    Where   Ind.Unit = @Unit
    AND @Ind.InvoiceDate BETWEEN @BegDate AND @EndDate
person Horaciux    schedule 13.01.2016
comment
Мне это кажется очень похожим на ответ, но, сравнивая это с другим ответом Рамазана Бинарбаси, возвращает ли это таблицу или мне нужно добавить что-то еще, чтобы это произошло с кодом выше? - person B. Clay Shannon; 13.01.2016
comment
Я пытаюсь создать SP почти точно так же, чтобы посмотреть, какие результаты я получу, но он не будет компилироваться; Я задал новый квест об этой проблеме по адресу stackoverflow.com/questions/34772214/ - person B. Clay Shannon; 13.01.2016
comment
Кажется, я пропустил запятую, SQLFiddle в то время не работал, SQL не было, извините. - person Horaciux; 13.01.2016

Вы должны создать функцию, которая возвращает таблицу.

https://technet.microsoft.com/en-us/library/ms191165(v=sql.105).aspx

person Ramazan Binarbasi    schedule 13.01.2016