SQL server 自定義工資公式設計

目的:

      工資系統中,在計算各工資項目的時候,用戶能自定義公式。這裏的講述是從數據庫方設計方面考慮,做簡要的數據模擬和實體、存儲過程的設計。

 

收集數據:

      1.Employee員工信息數據(EmployeeID,Name,Sex,Department,Position,Joindate(到職日期),DimissionDate(離職日期)… …)

      2.Salay員工工資清單(SalaryMonth(工資月份),Employee(員工),基本工資,崗位津貼,技術津貼,住宿費,上月餘額,應得工資,本月餘額,實得工資 … …)

分析:

       這裏只是作爲Demo,就製作一個簡單的數據分析。

       1.Employee員工信息就認爲一個對象實體,不做詳細的數據提取篩分。

       2.在Salay員工工資清單,可以把“基本工資,崗位津貼,技術津貼,住宿費 。。。”這些項提取出來,歸類爲SalaryItem工資項目;SalaryItem工資項目還可以再分類爲“公式項”與“非公式項”。(注:“公式項”是指可以使用公式來計算非手工輸入的工資項目)當然還可以根據實際的需要分類的更詳細,清晰。

image

數據表:

    根據上面的簡單分析,可以設計出作Demo使用的表,

   1.Emplyee:員工信息表。

   2.Salary:員工工資表

   3.SalaryItem:工資項目表

   4.Formulary:公式表

   5.SysSalaryItemTypeMTR:工資項目分類表

 

SalaryItem1

 

 

 

 

建表:

 

 

複製代碼
USE [test]

GO

/*建表腳本*/

If object_id('Salary') Is Not Null Drop Table Salary

If object_id('Formulary') Is Not Null Drop Table Formulary

If object_id('Employee') Is Not Null Drop Table Employee

If object_id('SalaryItem') Is Not Null Drop Table SalaryItem

If object_id('SysSalaryItemTypeMTR') Is Not Null Drop Table SysSalaryItemTypeMTR

Go

CREATE TABLE [SysSalaryItemTypeMTR](

    [ID] [smallint] IDENTITY(1,1) NOT NULL,

    [Name] [nvarchar](50) COLLATE Chinese_PRC_CI_AS NULL,

CONSTRAINT [PK_SysSalaryItemTypeMTR] PRIMARY KEY CLUSTERED

(

    [ID] ASC

)

)

CREATE TABLE [Employee](

    [ID] [int] IDENTITY(1,1) NOT NULL,

    [EmployeeNo] [nvarchar](50) COLLATE Chinese_PRC_CI_AS NULL,

    [Name] [nvarchar](50) COLLATE Chinese_PRC_CI_AS NULL,

    [Sex] [nchar](1) COLLATE Chinese_PRC_CI_AS NOT NULL,

    [Department] [nvarchar](50) COLLATE Chinese_PRC_CI_AS NULL,

    [Position] [nvarchar](50) COLLATE Chinese_PRC_CI_AS NULL,

    [JoinDate] [datetime] NULL,

    [DimissionDate] [datetime] NULL,

CONSTRAINT [PK_Employee] PRIMARY KEY CLUSTERED

(

    [ID] ASC

)

)

CREATE TABLE [SalaryItem](

    [ID] [smallint] IDENTITY(1,1) NOT NULL,

    [ItemType] [smallint] NOT NULL,

    [Name] [nvarchar](50) COLLATE Chinese_PRC_CI_AS NULL,

CONSTRAINT [PK_SalaryItem] PRIMARY KEY CLUSTERED

(

    [ID] ASC

)

)

ALTER TABLE [SalaryItem]  WITH CHECK ADD  CONSTRAINT [FK_SalaryItem_SysSalaryItemTypeMTR] FOREIGN KEY([ItemType])

REFERENCES [SysSalaryItemTypeMTR] ([ID])

CREATE TABLE [Salary](

    [ID] [int] Identity(1,1)NOT NULL,

    [EmployeeID] [int] NOT NULL,

    [SalaryMonth] [datetime] NULL,

    [SalaryItemID] [smallint] NOT NULL,

    [Amount] [money] NULL,

CONSTRAINT [PK_Salary] PRIMARY KEY CLUSTERED

(

    [ID] ASC

)

)

ALTER TABLE [Salary]  WITH CHECK ADD  CONSTRAINT [FK_Salary_Employee] FOREIGN KEY([EmployeeID])

REFERENCES [Employee] ([ID])

ALTER TABLE [Salary]  WITH CHECK ADD  CONSTRAINT [FK_Salary_SalaryItem] FOREIGN KEY([SalaryItemID])

REFERENCES [SalaryItem] ([ID])

Create Table Formulary

(

    ID int Identity(1,1) Not Null,

    SalaryItemID Smallint Not Null,

    Definition nvarchar(4000) Null,

    Sequence smallint Null,

    EffectiveDate datetime Null,

    ExpiryDate datetime Null,

    Constraint PK_Formulary Primary Key(ID Asc),

    Constraint FK_Formulary_SalaryItem Foreign Key (SalaryItemID) References SalaryItem(ID)

)

CREATE NONCLUSTERED INDEX [IX_Employee_EmployeeNo] ON [Employee]

(

    [EmployeeNo] ASC

)

CREATE NONCLUSTERED INDEX [IX_Formulary_SalaryItemID] ON [Formulary]

(

    [SalaryItemID] ASC

)

CREATE NONCLUSTERED INDEX [IX_Salary_EmployeeID] ON [Salary]

(

    [EmployeeID] ASC

)

CREATE NONCLUSTERED INDEX [IX_Salary_SalaryMonth_EmployeeID] ON [Salary]

(

    [SalaryMonth] ASC,

    [EmployeeID] ASC

)

插入測試數據:

Use test
Go
If Not Exists(Select 1 From SysSalaryItemTypeMTR)
    Insert Into SysSalaryItemTypeMTR(Name)
        Select N'上月項' Union All
        Select N'固定項' Union All
        Select N'輸入項' Union All
        Select N'公式項' Union All
        Select N'文本項'

If Not Exists(Select 1 From SalaryItem)
    Insert Into SalaryItem(ItemType,Name)
        Select 2,N'基本工資' Union All
        Select 3,N'其他扣款' Union All
        Select 3,N'崗位津貼' Union All
        Select 3,N'技術津貼' Union All
        Select 3,N'住宿費'     Union All
        Select 1,N'上月餘額' Union All
        Select 4,N'應得工資' Union All
        Select 4,N'本月餘額' Union All
        Select 4,N'實得工資'

If Not Exists(Select 1 From Formulary)
    Insert Into Formulary(SalaryItemID,Definition,Sequence,EffectiveDate,ExpiryDate)
        Select 1,N'Isnull([1],0)',1,'20090101','21001231' Union ALl
        Select 2,N'Isnull([2],0)',2,'20090101','21001231' Union ALl
        Select 3,N'Isnull([3],0)',3,'20090101','21001231' Union ALl
        Select 4,N'Isnull([4],0)',4,'20090101','21001231' Union ALl
        Select 5,N'Isnull([5],0)',5,'20090101','21001231' Union ALl
        Select 6,N'Isnull([8],0)',6,'20090101','21001231' Union ALl
        Select 7,N'Isnull([1],0)+Isnull([2],0)+Isnull([3],0)+Isnull([4],0)+Isnull([5],0)+Isnull([6],0)',7,'20090101','21001231' Union ALl
        Select 8,N'Case Convert(char(6),DimissionDate,112)+''01'' When SalaryMonth Then 0 Else Isnull([7],0)%10 End ',8,'20090101','21001231' Union ALl
        Select 9,N'Case Convert(char(6),DimissionDate,112)+''01'' When SalaryMonth Then Isnull([7],0) Else Isnull([7],0)-Isnull([8],0) End',9,'20090101','21001231'

If Not Exists(Select 1 From Employee)
    Insert Into Employee(EmployeeNo,Name,Sex,Department,Position,JoinDate,DimissionDate)
        Select N'N0001',N'A1',N'男',N'Dep1',N'Pos1','20080101',Null Union All
        Select N'N0002',N'A2',N'女',N'Dep2',N'Pos2','20080101','20090514' Union All
        Select N'N0003',N'A3',N'男',N'Dep3',N'Pos3','20080101',Null

If Not Exists(Select 1 From Salary)
    Insert Into Salary(EmployeeID,SalaryMonth,SalaryItemID,Amount)
        Select 1,'20090401',1,1000 Union All
        Select 2,'20090401',1,2000 Union All
        Select 3,'20090401',1,3000 Union All
        Select 1,'20090401',2,-10 Union All
        Select 2,'20090401',2,-20 Union All
        Select 3,'20090401',2,-30 Union All
        Select 1,'20090401',3,0 Union All
        Select 2,'20090401',3,0 Union All
        Select 3,'20090401',3,0 Union All
        Select 1,'20090401',4,105 Union All
        Select 2,'20090401',4,0 Union All
        Select 3,'20090401',4,107 Union All
        Select 1,'20090401',5,-60 Union All
        Select 2,'20090401',5,-60 Union All
        Select 3,'20090401',5,-60 Union All
        Select 1,'20090401',6,0 Union All
        Select 2,'20090401',6,0 Union All
        Select 3,'20090401',6,0 Union All
        Select 1,'20090401',7,0 Union All
        Select 2,'20090401',7,0 Union All
        Select 3,'20090401',7,0 Union All
        Select 1,'20090401',8,0 Union All
        Select 2,'20090401',8,0 Union All
        Select 3,'20090401',8,0 Union All
        Select 1,'20090401',9,0 Union All
        Select 2,'20090401',9,0 Union All
        Select 3,'20090401',9,0 Union All

        Select 1,'20090501',1,1000 Union All
        Select 2,'20090501',1,2000 Union All
        Select 3,'20090501',1,3000 Union All
        Select 1,'20090501',2,-25 Union All
        Select 2,'20090501',2,-25 Union All
        Select 3,'20090501',2,-25 Union All
        Select 1,'20090501',3,20 Union All
        Select 2,'20090501',3,10 Union All
        Select 3,'20090501',3,10 Union All
        Select 1,'20090501',4,150 Union All
        Select 2,'20090501',4,20 Union All
        Select 3,'20090501',4,150 Union All
        Select 1,'20090501',5,-62 Union All
        Select 2,'20090501',5,-62 Union All
        Select 3,'20090501',5,-62 Union All
        Select 1,'20090501',6,0 Union All
        Select 2,'20090501',6,0 Union All
        Select 3,'20090501',6,0 Union All
        Select 1,'20090501',7,0 Union All
        Select 2,'20090501',7,0 Union All
        Select 3,'20090501',7,0 Union All
        Select 1,'20090501',8,0 Union All
        Select 2,'20090501',8,0 Union All
        Select 3,'20090501',8,0 Union All
        Select 1,'20090501',9,0 Union All
        Select 2,'20090501',9,0 Union All
        Select 3,'20090501',9,0
Go
複製代碼

建測試存儲過程:

 

複製代碼
Use test
GO
If object_id('up_SalarySUM') Is Not Null
    Drop Proc up_SalarySUM
Go
Create Proc up_SalarySUM
(
    @SalaryMonth datetime
)
As
Set Nocount On

Declare @SalaryItemID nvarchar(50),
        @ItemType smallint,
        @Sql nvarchar(4000),
        @Definition nvarchar(4000),
        @Cols nvarchar(4000)

If object_id('tempdb..#Salary') Is Not Null
    Drop Table #Salary

Create Table #Salary(EmployeeID int,DimissionDate datetime,SalaryMonth datetime)

Select @Cols=Isnull(@Cols+',','')+Rtrim(Quotename(a.ID))
        From SalaryItem As a
            Inner Join Formulary As b On b.SalaryItemID=a.ID
        Where b.EffectiveDate<=@SalaryMonth
                And b.ExpiryDate>@SalaryMonth

Set @Sql=N'Alter Table #Salary Add '+Replace(@Cols,',',' money,')+' money'
Exec sp_executesql @Sql

Set @Sql=N'
;With CTE_Salary As
(
    Select a.EmployeeID,b.DimissionDate,SalaryMonth,a.SalaryItemID,a.Amount
        From Salary As a
            Inner Join Employee As b On b.ID=a.EmployeeID
        Where SalaryMonth In(@SalaryMonth,Dateadd(month,-1,@SalaryMonth))
)
Insert Into #Salary
    Select *
        From  CTE_Salary
        Pivot(Max(Amount) For SalaryItemID In('+@Cols+')) As b
'
Exec sp_executesql @Sql,N'@SalaryMonth datetime',@SalaryMonth

Declare Cur_SalaryItem Cursor For
    Select Quotename(a.ID) As ID,a.ItemType,b.Definition 
        From SalaryItem As a
            Inner Join Formulary As b On b.SalaryItemID=a.ID
        Where b.EffectiveDate<=@SalaryMonth
                And b.ExpiryDate>@SalaryMonth
                And a.ItemType In(1,4)
        Order By b.Sequence
    For Read Only

Open Cur_SalaryItem
Fetch Next From Cur_SalaryItem Into @SalaryItemID,@ItemType,@Definition
While @@Fetch_status=0
Begin
    If @ItemType=4 --本月可計算的工資項
        Set @sql='Update #Salary Set '+@SalaryItemID+'='+@Definition +' Where SalaryMonth=@SalaryMonth'
    Else            --計算上月工資項
        Set @sql='Update a  Set a.'+@SalaryItemID+'=(Select '+@Definition +' From #Salary Where EmployeeID=a.EmployeeID And SalaryMonth=Dateadd(Month,-1,a.SalaryMonth)) From #Salary As a Where SalaryMonth=@SalaryMonth'

    Exec sp_executesql @sql,N'@SalaryMonth datetime',@SalaryMonth

    Fetch Next From Cur_SalaryItem Into @SalaryItemID,@ItemType,@Definition
End
Close Cur_SalaryItem
Deallocate Cur_SalaryItem

Set @sql=(N'
;With CTE_Salary As
(
    Select * From #Salary Unpivot(Amount For SalaryItemID In('+@Cols+')) As up Where SalaryMonth=@SalaryMonth
)
Update a
    Set a.Amount=b.Amount
    From Salary As a
        Inner Join CTE_Salary As b On b.SalaryMonth=a.SalaryMonth
                And b.EmployeeID=a.EmployeeID
                And b.SalaryItemID=a.SalaryItemID
')
Exec sp_executesql @sql,N'@SalaryMonth datetime',@SalaryMonth

Drop Table #Salary
Go
複製代碼

--執行工資計算

 

Exec up_SalarySUM '20090401'
Exec up_SalarySUM '20090501'
Go

 

---查看計算結果

 

複製代碼
Declare @Cols nvarchar(4000),
        @SalaryMonth datetime,
        @Sql nvarchar(4000)

Set @SalaryMonth='20090501'

Select @Cols=Isnull(@Cols+',','')+Rtrim(Quotename(a.Name))
        From SalaryItem As a
            Inner Join Formulary As b On b.SalaryItemID=a.ID
        Where b.EffectiveDate<=@SalaryMonth
                And b.ExpiryDate>@SalaryMonth

Set @Sql=N'
;With CTE_Salary As
(
    Select a.EmployeeID,b.DimissionDate,SalaryMonth,c.Name As SalaryItem,a.Amount
        From Salary As a
            Inner Join Employee As b On b.ID=a.EmployeeID
            Inner Join SalaryItem As c On c.ID=a.SalaryItemID
        Where SalaryMonth=@SalaryMonth
)
    Select *
        From  CTE_Salary
        Pivot(Max(Amount) For SalaryItem In('+@Cols+')) As b
'
Exec sp_executesql @Sql,N'@SalaryMonth datetime',@SalaryMonth

Go
複製代碼

 

Demo效果如圖:

image

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章