Использование функций в SQL-запросе - PullRequest
1 голос
/ 23 января 2012

Я структурировал свою таблицу sql следующим образом:

ItemID   Price   MaxPeople   CalculationUnit
1        10      4           people/item
2        70      2           item
3        30      8           week/item
4        50      2           week

и т.д.

Теперь я хотел бы запустить базовую хранимую процедуру, которая выглядит примерно так:

sp_return_items_total
@Days as int,
@Items as int
AS
select itemid, price, total from table

Total будет значением, основанным на этом расчете (number of days * calculation unit * price).

Например, для результатов @Days = 5 и '@Items = 2' будет:

1, 10, 400  (10 * 4 people * 2 items * 5 days)
2, 70, 140 (70 * 1 * 2 items * 1)
3, 30, 42.85 (30 * 1 * 2 items * 5/7 days)
4, 50, 35.71 (50 * 1 * 1 items * 5/7 days)

Я пытаюсь найти решение, как получить общее значение на основе параметров sp и единицы расчета.

Спасибо за участие

Ответы [ 3 ]

5 голосов
/ 23 января 2012

РЕДАКТИРОВАНИЕ 2/10/12: пересмотренный запрос, чтобы соответствовать пересмотренному примеру вывода:

-- Set up the test data. 
declare @AmalgamatedStuff as table ( ItemId int, Price int, MaxPeople int, CalculationUnit varchar(16) ) 
insert into @AmalgamatedStuff ( ItemId, Price, MaxPeople, CalculationUnit ) values 
  ( 1, 10, 4, 'people/item' ), 
  ( 2, 70, 2, 'item' ), 
  ( 3, 30, 8, 'week/item' ), 
  ( 4, 50, 2, 'week' ) 

-- Stored procedure parameters. 
declare @Days as int = 5 
declare @Items as int = 2 

-- The query. 
select ItemId, Price, 
  case CalculationUnit 
    when 'item' then Price * @Items
    when 'people/item' then Price * MaxPeople * @Items * @Days 
    when 'week' then round( Price * @Days / 7.0, 2 )
    when 'week/item' then round( Price * @Items * @Days / 7.0, 2 )
    else NULL 
    end as Total 
  from @AmalgamatedStuff

Обратите внимание, что 42,857142 не округляется до 42,85 в третьей строке результатов.


РЕДАКТИРОВАТЬ: учитывая, что предлагаемые результаты с переменным числом столбцов и неопределенными вычислениями не могут быть получены:

-- Set up the test data.
declare @AmalgamatedStuff as table ( ItemId int, Price int, MaxPeople int, CalculationUnit varchar(16) )
insert into @AmalgamatedStuff ( ItemId, Price, MaxPeople, CalculationUnit ) values
  ( 1, 10, 4, 'people/item' ),
  ( 2, 70, 2, 'item' ),
  ( 3, 30, 8, 'week/item' ),
  ( 4, 50, 2, 'week' )

-- Stored procedure parameters.
declare @Days as int = 5
declare @Items as int = 2

-- The query, give or take the correct calculations.
declare @SpuriousFactorToGetSuggestedResult as int = 2  
select ItemId, Price,
  case CalculationUnit
    when 'item' then Price * @Items
    when 'people/item' then Price * MaxPeople * @Items * @Days
    when 'week' then Price * @Items * @Days / 7
    when 'week/item' then Price * @Items * @Days * @SpuriousFactorToGetSuggestedResult / 7
    else NULL
    end as Total
  from @AmalgamatedStuff

На самом деле получение запроса в хранимую процедуру оставлено в качестве упражнения для OP.

«Дизайн» остается где-то ниже прогорклого и гноится все быстрее.


РЕДАКТИРОВАТЬ: Ответ на более раннее редактирование "вопрос" остается ниже:

Вы можете делать вещи, используя CASE, например:

select ItemId, Price,
  case
    when CalculationUnit = 'day' then @Days * Price
    when CalculationUnit = 'week' then @Days / 7 * Price
    else NULL
    end as 'Total'
  from MyIllConceivedTable

Как уже отмечалось, это плохой дизайн.

В некоторых случаях может иметь смысл иметь справочную таблицу, например, что-то, что позволяет вам сопоставить различные единицы измерения с общей базой Подумайте о весах и их грамм-эквивалентах. (Также удобное место для хранения полного имени "Унции" и сокращения "Oz", ....) Ваша таблица данных будет содержать ссылки на таблицу единиц.

В некоторых случаях это может иметь смысл в единицах времени. Запланированные мероприятия могут повторяться ежедневно, еженедельно, ежемесячно, ежеквартально и ежегодно. Длина блоков несколько гибкая, а использование, как правило, своеобразно. (У меня обед в 3-ю среду каждого месяца. Увидимся там?)

Что касается производительности, вычисления, которые дают результаты, неплохие. Вы можете использовать вычисляемый столбец или представление для достижения своей (гнусной) цели. Производительность падает, когда у вас есть функции, вызываемые для каждой строки, например, предложение WHERE, которое преобразует столбец DATETIME в строку и использует LIKE, чтобы определить, есть ли в строке 'R'.

Что бы вы ни выбрали, пожалуйста, не используйте ничего, кроме как:

declare @Today as Date
set @Today = SysDateTime()
select @Today,
  DateDiff(day, @Today, DateAdd( "day", 1, @Today ) ) as 'Days in a Day',
  DateDiff(day, @Today, DateAdd( "week", 1, @Today ) ) as 'Days in a Week',
  DateDiff(day, @Today, DateAdd( "month", 1, @Today ) ) as 'Days in a Month' -- Sometimes!
4 голосов
/ 23 января 2012

Да.Альтернативой (и хорошим дизайном базы данных) является сохранение единицы вычисления в виде коэффициента некоторой единицы.Другими словами, если доступны следующие параметры: день и неделя, сохраните количество дней (то есть вы бы сохранили 1 для любой строки, которая в данный момент говорит day и 7 для любой строки, которая в данный момент говорит week)так что вы можете использовать это в своих расчетах.

1 голос
/ 23 января 2012

Использование хранимых функций, у которых доступ к данным «скрыт» внутри них, да, это может значительно снизить вашу производительность (в основном из-за того, что они могут выполняться гораздо чаще, чем вы ожидаете, припервый взгляд).

Функции, которые в основном выполняют вычисления (как, вероятно, и здесь), не должны быть серьезной проблемой.

...