在sql中格式化数据

时间:2018-02-20 06:36:42

标签: sql-server

我有几张桌子,基本上我正在研究telerik报告。我得到的结构和样本数据如下:

IF EXISTS(SELECT 1 FROM sys.tables WHERE object_id = OBJECT_ID('Leave'))
BEGIN;
    DROP TABLE [Leave];
END;
GO

IF EXISTS(SELECT 1 FROM sys.tables WHERE object_id = OBJECT_ID('Addition'))
BEGIN;
    DROP TABLE [Addition];
END;
GO

IF EXISTS(SELECT 1 FROM sys.tables WHERE object_id = OBJECT_ID('Deduction'))
BEGIN;
    DROP TABLE [Deduction];
END;
GO

IF EXISTS(SELECT 1 FROM sys.tables WHERE object_id = OBJECT_ID('EmployeeInfo'))
BEGIN;
    DROP TABLE [EmployeeInfo];
END;
GO

CREATE TABLE [EmployeeInfo] (
[EmpID] INT NOT NULL PRIMARY KEY,
[EmployeeName] VARCHAR(255)
);


CREATE TABLE [Addition] (
    [AdditionID] INT NOT NULL PRIMARY KEY,
    [AdditionType] VARCHAR(255), 
    [Amount] VARCHAR(255),
    [EmpID] INT FOREIGN KEY REFERENCES EmployeeInfo(EmpID)
);


CREATE TABLE [Deduction] (
    [DeductionID] INT NOT NULL PRIMARY KEY,
    [DeductionType] VARCHAR(255), 
    [Amount] VARCHAR(255),
    [EmpID] INT FOREIGN KEY REFERENCES EmployeeInfo(EmpID)
);


CREATE TABLE [Leave] (
    [LeaveID] INT NOT NULL PRIMARY KEY,
    [LeaveType] VARCHAR(255) NULL,
    [DateFrom] VARCHAR(255),
    [DateTo] VARCHAR(255),
    [Approved] Binary,
    [EmpID] INT FOREIGN KEY REFERENCES EmployeeInfo(EmpID)
);
GO


INSERT INTO EmployeeInfo([EmpID], [EmployeeName]) VALUES
(1, 'Marcia'),
(2, 'Lacey'),
(3, 'Fay'),
(4, 'Mohammad'),
(5, 'Mike')


INSERT INTO Addition([AdditionID], [AdditionType], [Amount], [EmpID]) VALUES
(1, 'Bonus', '2000', 2),
(2, 'Increment', '5000', 5)


INSERT INTO Deduction([DeductionID], [DeductionType], [Amount], [EmpID]) VALUES
(1, 'Late Deductions', '2000', 4),
(2, 'Delayed Project Completion', '5000', 1)


INSERT INTO Leave([LeaveID],[LeaveType],[DateFrom],[DateTo], [Approved], [EmpID]) VALUES
(1, 'Annual Leave','2018-01-08 04:52:03','2018-01-10 20:30:53', 1, 1),
(2, 'Sick Leave','2018-02-10 03:34:41','2018-02-14 04:52:14', 1, 2),
(3, 'Casual Leave','2018-01-04 11:06:18','2018-01-05 04:11:00', 1, 3),
(4, 'Annual Leave','2018-01-17 17:09:34','2018-01-21 14:30:44', 1, 4),
(5, 'Casual Leave','2018-01-09 23:31:16','2018-01-12 15:11:17', 1, 3),
(6, 'Annual Leave','2018-02-16 18:01:03','2018-02-19 17:16:04', 1, 2)

我用来获取输出的查询是这样的:

SELECT  Info.EmployeeName, Addition.AdditionType, Addition.Amount, Deduction.DeductionType, Deduction.Amount,
        Leave.LeaveType, 
        SUM(DATEDIFF(Day, Leave.DateFrom, Leave.DateTo)) [#OfLeaves], 
        DatePart(MONTH, Leave.DateFrom)
FROM    EmployeeInfo Info
        LEFT JOIN Leave
          ON Info.EmpID = Leave.EmpID
          LEFT JOIN Addition
          ON Info.EmpID = Addition.EmpID
          LEFT JOIN Deduction
          ON Info.EmpID = Deduction.EmpID
WHERE   Approved = 1 
GROUP   BY Info.EmployeeName, Addition.AdditionType, Addition.Amount, Deduction.DeductionType, Deduction.Amount,
         Leave.LeaveType, 
         DatePart(MONTH, Leave.DateFrom) 

我实际上想要得到我能够在报告上显示的输出,但不知何故,因为我正在使用连接,数据在同一用户的多行上重复,这就是为什么它也会在报告上多次出现。 我得到的输出是这样的

Fay         NULL    NULL    NULL                        NULL    Casual Leave    4   1
Lacey       Bonus   2000    NULL                        NULL    Annual Leave    3   2
Lacey       Bonus   2000    NULL                        NULL    Sick Leave      4   2
Marcia      NULL    NULL    Delayed Project Completion  5000    Annual Leave    2   1
Mohammad    NULL    NULL    Late Deductions             2000    Annual Leave    4   1

虽然我想要它看起来像这样:

Fay         NULL    NULL    NULL                        NULL    Casual Leave    4   1
Lacey       Bonus   2000    NULL                        NULL    Annual Leave    3   2
Lacey       NULL    NULL    NULL                        NULL    Sick Leave      4   2
Marcia      NULL    NULL    Delayed Project Completion  5000    Annual Leave    2   1
Mohammad    NULL    NULL    Late Deductions             2000    Annual Leave    4   1

由于只有一个奖金,并且没有多次分配,所以它应该出现一次。我被困在格式化表格布局中,所以我想我可能会在查询中格式化输出的提示,所以我不必那么做。

最佳,

2 个答案:

答案 0 :(得分:2)

我对此案例的建议是通过以下方式将左连接更改为单个表:

select 
info.employeename, additiontype, additionamount, deductiontype, deductionamount, leavetype, #ofleaves, leavemth
from Employeeinfo info
join
(
Select
Leave.empid,  null as additiontype, null as additionamount, null as deductiontype, null as deductionamount, leave.leavetype, DATEDIFF(Day, Leave.DateFrom, Leave.DateTo) [#OfLeaves], DatePart(MONTH, DateFrom) leavemth
  from leave 
where approved = 1
  Union all
 Select 
Addition.empid, additiontype, amount, null, null, null, null, null
From addition
Union all
Select empid, null, null, deductiontype, amount, null, null, null
From deduction
  ) payadj on payadj.empid= info.empid

这种方法将不同的薪酬调整分为不同的列,并确保您不会在此加入时添加多个员工ID。

您可能需要为每个Union明确命名所有空列 - 我还没有对其进行测试,但我认为您只需要在union中命名列一次。

输出的格式如下:

employeename     bonus     leavetype
Lacey            2000      null
Lacey            null      Sick Leave
Lacey            null      Annual Leave

这里没有输入完整的结果集,而是指向sqlfiddle的链接; http://sqlfiddle.com/#!18/935e9/5/0

答案 1 :(得分:1)

您遇到的问题取决于您如何一起加入表格。这不是语法必然是错误的,而是我们如何看待数据以及我们如何理解表之间的关系。在执行LEFT JOIN时,您的查询能够在每个表中找到EmpID,并且对此感到满意并抓取记录(如果没有与EmpID匹配的记录,则返回NULL)。这不是你真正想要的,因为它可以加入太多。所以让我们看看为什么会这样。如果我们将连接取出到Addition表,您的结果将如下所示:

Fay         NULL                        NULL    Casual Leave    4   1
Lacey       NULL                        NULL    Annual Leave    3   2
Lacey       NULL                        NULL    Sick Leave      4   2
Marcia      Delayed Project Completion  5000    Annual Leave    2   1
Mohammad    Late Deductions             2000    Annual Leave    4   1

你仍然为Lacey留下两排。这两行的原因是由于与Leave表的连接。莱西已经带走了两片缺席。一个用于病假,另一个用于年假。这两个记录共享相同的EmpID为2.因此,当您在EmpID上加入Addition表(和/或其余表)时,联接会查找所有匹配的记录以完成该连接。有一个Addition记录匹配在EmpID上加入的两个Leave记录。因此,您最终得到两个奖励结果 - 两个请假记录的相同添加记录。尝试运行此查询并检查结果,它还应说明问题:

SELECT l.LeaveType, l.EmpID, a.AdditionType, a.Amount
FROM Leave l
LEFT JOIN Addition a ON a.EmpID = l.EmpID

使用您提供的数据的结果将是:

Annual Leave    1    NULL        NULL
Sick Leave      2    Bonus       2000
Casual Leave    3    NULL        NULL
Annual Leave    4    NULL        NULL
Casual Leave    3    NULL        NULL
Annual Leave    2    Bonus       2000

所以数据本身并没有错。只是当以这种方式加入EmpID时,关系可能会令人困惑。

所以问题是Leave表和其他表之间的关系。在EmpID上直接加入Leave给Addition或Deduction表是没有意义的,因为看起来Lacey可能会因为每次请假而获得奖金。这就是你在这里遇到的。

我建议三个单独的查询(可能还有三个报告)。一个用于返回休假数据,另一个用于添加和扣除数据。类似的东西:

--Return each employee's leaves of absence
SELECT e.EmployeeName
      , l.LeaveType
      , SUM(DATEDIFF(Day, l.DateFrom, l.DateTo)) [#OfLeaves]
      , DatePart(MONTH, l.DateFrom)
FROM EmployeeInfo e
LEFT JOIN Leave l ON e.EmpID = l.EmpID
WHERE l.Approved = 1 

--Return each employee's Additions
SELECT e.EmployeeName
     , a.AdditionType
     , a.Amount
FROM EmployeeInfo e
LEFT JOIN Addition a ON e.EmpID = a.EmpID

--Return each employee's Deductions
SELECT e.EmployeeName
     , d.DeductionType
     , d.Amount
FROM EmployeeInfo e
LEFT JOIN Deduction d ON e.EmpID = d.EmpID

有三个查询应该更好地表示EmployeeInfo表与其他每个查询之间的关系以及单独的关注点。从那里你可以GROUP BY不同类型的数据并聚合值并获得总计数和总和。

如果您还没有找到这些资源,可以提供以下资源:

SQL连接的说明:https://blog.codinghorror.com/a-visual-explanation-of-sql-joins/

SQL Join示例:https://www.w3schools.com/sql/sql_join.asp

Telerik报告文档:https://docs.telerik.com/reporting/overview