Tsql 在sql查询中使用函数

Tsql 在sql查询中使用函数,tsql,user-defined-functions,Tsql,User Defined Functions,我的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 @Da

我的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
总计
将是基于此计算的值(
天数*计算单位*价格

例如,
@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参数和计算单位获得总值


感谢您的参与

是的。另一种选择(以及良好的数据库设计)是将计算单位存储为某个单位的系数。换句话说,如果选项为天和周,则存储天数(这意味着您将为当前显示为天的任何行存储
1
,为当前显示为周的任何行存储
7
),以便在计算中使用该天数。

是。另一种选择(以及良好的数据库设计)是将计算单位存储为某个单位的系数。换句话说,如果选项为天和周,则存储天数(这意味着您将为当前显示为天的任何行存储
1
,为当前显示为周的任何行存储
7
),以便在计算中使用该天数。

使用具有数据访问权限的存储函数“隐藏”在它们里面,是的,这会大大降低您的性能(主要是因为它们的执行频率可能比您第一眼看到的要高得多)


主要进行计算的函数(就像这里可能会出现的那样)不应该是一个大问题。

使用存储的函数,这些函数中有数据访问“隐藏”在它们内部,是的,这会大大降低性能(主要是因为它们的执行频率可能比乍一看要高)


主要进行计算的函数(可能在这里)不应该是一个大问题。

编辑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
实际上,将查询放入存储过程只是操作的一个练习

“设计”仍然在腐臭以下的某个地方,并且溃烂得更快


编辑:“问题”先前编辑的答案如下:

您可以使用以下案例进行操作:

select ItemId, Price,
  case
    when CalculationUnit = 'day' then @Days * Price
    when CalculationUnit = 'week' then @Days / 7 * Price
    else NULL
    end as 'Total'
  from MyIllConceivedTable
如前所述,这是一个糟糕的设计

在某些情况下,有一个查找表可能是有意义的,例如,可以让您将各种度量单位映射到某个公共基础。考虑重量及其克当量。(也是存储全名“盎司”和缩写“盎司”的方便位置,…)您的数据表将包含对单位表的引用

在某些情况下,以时间为单位是有意义的。计划的事件可能每天、每周、每月、每季度和每年都会发生。单位的长度有点灵活,用途也有点特殊。(我在每个月的第三个星期三吃午饭。见?)

关于性能,返回结果的计算并不糟糕。您可以使用计算列或视图来实现(邪恶的)目的。当您为每行调用函数时,性能会受到影响,例如,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!

编辑2012年2月10日:修改查询以对应修改后的样本输出:

-- 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
实际上,将查询放入存储过程只是操作的一个练习

“设计”仍然在腐臭以下的某个地方,并且溃烂得更快


编辑:“问题”先前编辑的答案如下:

您可以使用以下案例进行操作:

select ItemId, Price,
  case
    when CalculationUnit = 'day' then @Days * Price
    when CalculationUnit = 'week' then @Days / 7 * Price
    else NULL
    end as 'Total'
  from MyIllConceivedTable
如前所述,这是一个糟糕的设计

在某些情况下,有一个查找表可能是有意义的,例如,可以让您将各种度量单位映射到某个公共基础。考虑重量及其克当量。(也是存储全名“盎司”和缩写“盎司”的方便位置,…)您的数据表将包含对单位表的引用

在某些情况下,以时间为单位是有意义的。计划的事件可能每天、每周、每月、每季度和每年都会发生。单位的长度有点灵活,用途也有点特殊。(我在每个月的第三个星期三吃午饭。见?)

关于性能,返回结果的计算并不糟糕。您可以使用计算列或视图来实现(邪恶的)目的。当您为每行调用函数时,性能会受到影响,例如,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!

编写生成所需结果的查询的挑战之一是前两个结果行有三列,而后两个结果行有四列。大多数查询返回的每行列数相同。@user92546看起来那些没有尾随空格的逗号是十进制分隔符(请检查计算)…编写生成所需结果的查询的挑战之一是前两个结果行有三列,而后两个结果行有四列。大多数查询返回的每行列数相同。@user92546看起来像是没有尾随空格的逗号是分母