从3个表创建SQL函数/过程

时间:2019-06-22 11:57:35

标签: sql tsql stored-procedures sql-server-2016

我有3个表,类别,资源人员和人力资源计划。

enter image description here

我要计算按类别分组的金额

我创建了此SQL查询:

select 
    CostCategory.CostCategory, sum(isnull(HRPplan.Amount, 0))
from 
    CostCategory
left join 
    HRPplan on HRPplan.Month between 1 and 3 
            and HRPplan.Year = 2019 
            and HRPplan.IDRPH in (select HumanResource.IDRPH 
                                  from HumanResource
                                  where HumanResource.IDCostCategory = CostCategory.IDCostegory)
group by  
    CostCategory.CostCategory

,它返回一个结果,但是我还有另外两个与人力资源和HPlan完全一样的表,要用它来计算数量,因此,如果我使用上面提到的相同代码,查询性能将不佳。而且我不怎么在SQL中使用函数/过程,因为年和月将作为参数插入。

2 个答案:

答案 0 :(得分:1)

为了提高性能,您可以避免使用in子句

select CostCategory.CostCategory, sum(isnull(HRPplan.Amount,0))
from CostCategory
left join HRPplan on HRPplan.Month between 1 and 3  and HRPplan.Year = 2019 
LEFT JOIN HumanResource ON HumanResource.IDCostCategory = CostCategory.IDCostegory
  and umanResource.IDRPH  = HRPplan.IDRPH 
group by CostCategory.CostCategory 

答案 1 :(得分:1)

在问题中获取DDL和样本数据DML可以更轻松地提供快速解决方案。另外,查询中使用的列与您提供的屏幕截图并不完全相似,因此我将根据提供的屏幕截图提供这些方法。

准备好的DDL和测试数据:

DROP TABLE IF EXISTS CostCategory;
GO

CREATE TABLE CostCategory
(
    IDCostCategory  INT
    ,CostCategory   VARCHAR(10)
) ON [PRIMARY]
GO
INSERT INTO CostCategory
VALUES
(1, 'A'), (2, 'B'), (3, 'C')
GO


DROP TABLE IF EXISTS HumanResource;
GO

CREATE TABLE HumanResource
(
    IDHR            INT
    ,IDCostCategory INT
) ON [PRIMARY]
GO
INSERT INTO HumanResource
VALUES
(1, 1), (2, 2), (3, 2)
GO



DROP TABLE IF EXISTS HRPlan;
GO

CREATE TABLE HRPlan
(
    IDHRPlan        INT
    ,IDHR           INT
    ,Amount         INT
    ,Month          INT
    ,Year           INT
) ON [PRIMARY]
GO
INSERT INTO HRPlan
VALUES
    (1, 1, 10 , 1, 2019)
,   (2, 1, 12 , 2, 2019)
,   (3, 1, 15 , 2, 2019)
,   (4, 2, 50 , 1, 2019)
,   (5, 2, 0 , 2, 2019)
,   (6, 2, 100 , 3, 2019)
,   (4, 3, 40 , 1, 2019)
,   (5, 3, 50 , 2, 2019)
,   (6, 3, 30 , 3, 2019)
GO

要跟踪性能,您可以将IO和时间统计信息设置为“开”:

SET STATISTICS IO ON;
SET STATISTICS TIME ON;

解决方案1 ​​:使用外部应用(比下面的解决方案2更好的性能)

SELECT  CC.CostCategory, ISNULL(OA.Amount, 0)
FROM    CostCategory CC
        OUTER APPLY (
                        SELECT  Amount = SUM(ISNULL(HP.Amount, 0))
                        FROM    HRPlan HP
                        WHERE   HP.Month BETWEEN 1 AND 3
                        AND     HP.Year = 2019  
                        AND     EXISTS  (
                                            SELECT  1
                                            FROM    HumanResource HR
                                            WHERE   HR.IDCostCategory = CC.IDCostCategory
                                            AND     HR.IDHR = HP.IDHR
                                        )
                    ) OA;

解决方案2:使用左联接

SELECT  CC.CostCategory, ISNULL(SUM(HP.Amount), 0)
FROM    CostCategory CC
        LEFT JOIN HumanResource HR
            ON  CC.IDCostCategory = HR.IDCostCategory
        LEFT JOIN HRPlan HP
            ON HR.IDHR = HP.IDHR
            AND HP.Month BETWEEN 1 AND 3
            AND HP.Year = 2019
GROUP   BY CC.CostCategory;

注意:-您可以考虑在HRPlan表上创建列存储索引,并在其他两个表上创建行存储/列存储索引,这些表涵盖了联接和选定的列,以提高性能。