SQL存储过程帮助 - 对多个记录集执行操作然后比较结果

时间:2011-03-23 15:10:29

标签: sql vb.net stored-procedures

我对存储过程的体验有限,我希望这能解决我的工资问题。此外,对于我试图完成的事情,存储过程可能不是最好的答案。

我正在尝试使用Payroll函数,其中存储过程的目标是获取给定工资核算期间的数据,对第一个返回的员工进行数学运算,输出计算结果,然后移至下一个。让我解释一下......

根据存储过程的付款期ID,我希望它能够执行以下操作:

选择该期间的员工,添加他的工作总时数,然后添加员工总佣金(以较大者为准) - 返回该值(以及总计 - 例如总小时数和总佣金数) - 然后转到下一位员工,直到完成。

数据的布局如下:

  

工资核算期间表 PayrollID,DateBegin,DateEnd   存储过程在开始时被赋予工资单ID(作为QueryString),因此我必须采用相应的DateBegin& DateEnd数据,并从EmployeeTimeTable中获取DateTimeIn和DateTimeOut以获取相应的出勤记录。

PayrollID - 付款期的ID DateBegin - 支付期的开始日期 DateEnd - 支付期的结束日期。

  

员工时间表   EmployeeID,DateTimeIn,DateTimeOut,HourlyRate,CalculatedHours,AmountPaid - 每个工作日都有一个实例,因此存储过程将计算当天的工作时间。

EmployeeID - 与此有关的记录的员工的身份。
DateTimeIn - 员工打入的日期和时间。
DateTimeOut - 员工打孔的日期和时间 HourlyRate - 员工每小时支付的货币汇率 CalculatedHours - 此记录的工作小时数 AmountPaid - Simply HourlyRate x CalculatedHours。

  

佣金表 EmployeeID,PayrollID,AmountPaid - 每笔销售所获得的每个“佣金”都有一条记录。

EmployeeID - 与此有关的记录的员工的身份。
PayrollID - 支付期的ID AmountPaid - 此记录所赚取的佣金金额。

所以我的问题是 - 我如何创建描述的功能?它甚至可能吗?这需要奇迹才能完成!?或者我有更好的方法来解决这个问题吗?

另外,最后这理论上会输出到WebForm GridView。

2 个答案:

答案 0 :(得分:1)

@Damien_The_Unbeliever在他的建议中是正确的。

但是,我认为您有3种选择:

  • 编写单个SQL查询以进行检索 您正在寻找的数据。我认为 这是可能的,虽然它可能是一个 有点复杂。它将是 最快的解决方案,没有错。该 你做比较的方式可能是 通过联合和子查询。同 一个合适的架构,我相信人们会 在这个选项上有一个平底船。这是最纯粹的哲学方法,但如果你不是忍者级别的SQL,那也很棘手。
  • 编写一个查询以检索在工资核算期间活动的所有员工,将其返回到VB前端,并遍历结果集以运行单个查询以检索他们的工时和工资单;在VB中执行业务逻辑。这在性能方面略微次优,但允许您一步一步地工作,并使用VB IDE,这是一些开发人员更喜欢的。
  • 编写一个存储过程,在该过程中创建一个临时表来保存结果集,将员工记录插入该临时表中,以便在工资核算期内有效的所有员工,然后编写特定查询以使用他们的小时更新临时表工作,委托值等。这会将您的所有业务逻辑本地化,并且可能会很快执行;根据SQL的毛羽,它可能比选项1更快。它还允许您逐步处理业务逻辑,大多数开发人员发现这比在单个SQL语句中实现它更容易。

我在路上,并且没有可以使用的SQL Server实例,因此下面的示例可能包含一些语法错误,但选项3的工作原理如下:

       create proc calculatePaySlipForPeriod @periodID int
    as
    begin

    create table #results
    (emp_id   int,
    emp_name varchar(255), 
    commission_earnt money, 
    labour_earnt money,
    amount_to_pay money)

    insert into #results
    select emp_id
    from employee_time
    where timeIn between (select dateBegin from PayrollPeriod where PayrollID = @periodID)
          and (select dateEnd from PayrollPeriod where PayrollID = @periodID)

    insert into #results
    select emp_id 
    from Commission
    where payrollID = @periodID
    and emp_id not in
      (select emp_id from #results)
   /** We now have all the employees in the table, so we can populate their earnings **/

   update #results
   set labour_earnt_money = sum(AmountPaid)
   from #results   r, 
        employee_time et
   where r.emp_id = et.emp_id
    and timeIn between (select dateBegin from PayrollPeriod where PayrollID = @periodID)
          and (select dateEnd from PayrollPeriod where PayrollID = @periodID)

  update #results
  set    commission_earnt = sum(AmountPaid)
  from   #results r, 
         Commission c
  where r.emp_id = c.emp_id
  and   c.payroll_id = @periodID

  update #results
  set amount_to_pay = commission_earnt
  where commission_earnt > labour_earnt

  update #results
  set amount_to_pay = labour_earnt
  where labour_earnt >= commission_earnt

  /** We now have all the data populated, so we return the table to the front end. 

  select * from #results

  /** no need to explicitly drop the table, happens automatically at the end of the proc.

    end

这是大纲 - 您可能需要处理日期/时间的怪异(在运营期间操作员开始或结束时计算的班次?我假设开始)。

通过逐步建立结果,您可以轻松地计算出正在发生的事情;要进行调试,您可以在执行期间选择*形成临时表。

答案 1 :(得分:1)

假设EmployeeTime表看起来像这样:

CREATE TABLE EmployeeTime (
     EmployeeID int not null,
     DateTimeIn datetime not null,
     DateTimeOut datetime not null,
     HourlyRate decimal(10,2) not null,
     HoursWorked as (CONVERT(int,DATEDIFF(minute,DateTimeIn,DateTimeOut)/15.0)+1)/4.0,
     AmountPaid as (CONVERT(int,DATEDIFF(minute,DateTimeIn,DateTimeOut)/15.0)+1)/4.0 * HourlyRate
)

(不幸的是,您无法基于另一个计算列构建一个计算列。但是,您可以将公式(CONVERT(int,DATEDIFF(minute,DateTimeIn,DateTimeOut)/15.0)+1)/4.0移动到用户定义的函数中)

然后你会写一个如下所示的查询:

;WITH PayrollPayments as (
     SELECT PayrollID,EmployeeID, SUM(HoursWorked) as HoursWorkedTotal,SUM(AmountPaid) as TotalPay,0 as Commission from EmployeeTime et inner join Payroll p on p.DateBegin < et.DateTimeOn and p.DateEnd > et.DateTimeOut GROUP BY PayrollID,EmployeeID
     UNION ALL
     SELECT PayrollID,EmployeeID,0,SUM(AmountPaid) as TotalPay,1 from Commissions
)
SELECT PayrollID,EmployeeID,MAX(HoursWorkedTotal) as TotalHours,MAX(TotalPay) as MaxPay,MAX(CASE WHEN Commission=0 THEN TotalPay END) as TotalPayment,MAX(CASE WHEN Commission=1 THEN TotalPay END) as TotalCommission
FROM PayrollPayments
WHERE
     PayrollID = @PayrollID

如果您的EmployeeTime表看起来不像上面那样,并且您无法更改现有的EmployeeTime表,则始终可以在上面的查询中创建一个公用表表达式(类似于PayrollPayments)工作小时数/金额支付计算优先。