sql代码重构——使用自定义函数(一)

一、什么是用户自定义函数?

  (UDF) 是准备好的代码片段,它可以接受参数,处理逻辑,然后返回某些数据。其实和众多其他编程语言里的函数基本是一个道理。

二、为什么需要?

  总的来说,我总结出了三个点:第一,是为了更好的复用代码,不需要再傻傻的复制粘贴。第二、使得sql代码,可读性大大增强。第三、使得sql代码的可维护性大大提高。不过,我想,即使我说千万个理由。也不如让你看一下下面这两段代码来的更直接。

  重构前的sql代码:

 

USE SubjectDB
GO
   
WITH    viewLogicBuilding
          AS ( SELECT   LPLB.Code ,
                        LPLB.CnName ,
                        LPLB.ConstructionArea ,
                        LPLB.SaleableArea ,
                        LPLB.VersionStartTime ,
                        '1' AS StageCode ,
                        LPLB.StageAreaCode ,
                        LSA.ProjectInfoCode
               FROM     LandObtained.PlanLogicBuilding LPLB
                        INNER JOIN LandObtained.StageArea LSA ON LSA.Code = LPLB.StageAreaCode
                                                              AND LSA.VersionEndTime IS NULL
                                                              AND LSA.ValidStatus = 1
               WHERE    LPLB.VersionEndTime IS NULL
                        AND LPLB.ValidStatus = 1
               UNION ALL
               SELECT   PDLBP.Code ,
                        PDLBP.CnName ,
                        PDLBP.ConstructionArea ,
                        PDLBP.SaleableArea ,
                        PDLBP.VersionStartTime ,
                        '2' AS StageCode ,
                        PDLBP.StageAreaCode ,
                        LSA.ProjectInfoCode
               FROM     ProDefine.DesignLogicBuildingInPlanStage PDLBP
                        INNER JOIN LandObtained.StageArea LSA ON LSA.Code = PDLBP.StageAreaCode
                                                              AND LSA.VersionEndTime IS NULL
                                                              AND LSA.ValidStatus = 1
               WHERE    PDLBP.VersionEndTime IS NULL
                        AND PDLBP.ValidStatus = 1
               UNION ALL
               SELECT   PDLBE.Code ,
                        PDLBE.CnName ,
                        PDLBE.ConstructionArea ,
                        PDLBE.SaleableArea ,
                        PDLBE.VersionStartTime ,
                        '4' AS StageCode ,
                        PDLBE.StageAreaCode ,
                        LSA.ProjectInfoCode
               FROM     ProDefine.DesignLogicBuildingInEngineerStage PDLBE
                        INNER JOIN LandObtained.StageArea LSA ON LSA.Code = PDLBE.StageAreaCode
                                                              AND LSA.VersionEndTime IS NULL
                                                              AND LSA.ValidStatus = 1
               WHERE    PDLBE.VersionEndTime IS NULL
                        AND PDLBE.ValidStatus = 1
             )
			 
    SELECT  CC.ProjectCode AS '项目编码' ,
            CCCB.BuildingCode AS '楼栋编码' ,
            VLB.CnName AS '楼栋名称' ,
            CCC.CostCategoryCode AS '科目编码' ,
            FCC.CnName AS '科目名称' ,
            ( CASE WHEN CCC.ApportionmentWayCode = '2'

			then (case when (SELECT    SUM(VLBS.ConstructionArea)
                              FROM      viewLogicBuilding VLBS
                                        INNER JOIN Contract_trade.dbo.ContractCostCategory_Building CCCCB1 ON CCCCB1.ContractCostCategoryCode = CCC.Code
                                                              AND CCCCB1.ResourceID = CCC.ResourceID
                                                              AND VLBS.Code = CCCCB1.BuildingCode
                              WHERE     VLBS.StageCode = VLB.StageCode) <> 0 then 
							   CCC.CurrentPayAmount * VLB.ConstructionArea
                          / ( SELECT    SUM(VLBS.ConstructionArea)
                              FROM      viewLogicBuilding VLBS
                                        INNER JOIN Contract_trade.dbo.ContractCostCategory_Building CCCCB1 ON CCCCB1.ContractCostCategoryCode = CCC.Code
                                                              AND CCCCB1.ResourceID = CCC.ResourceID
                                                              AND VLBS.Code = CCCCB1.BuildingCode
                              WHERE     VLBS.StageCode = VLB.StageCode
                            )
							else (CCC.CurrentPayAmount / ( SELECT    Count(CCCCB1.ContractCostCategoryCode)
                              FROM      viewLogicBuilding VLBS
                                        INNER JOIN Contract_trade.dbo.ContractCostCategory_Building CCCCB1 ON CCCCB1.ContractCostCategoryCode = CCC.Code
                                                              AND CCCCB1.ResourceID = CCC.ResourceID
                                                              AND VLBS.Code = CCCCB1.BuildingCode
                              WHERE     VLBS.StageCode = VLB.StageCode
                            )) end)
            
                   WHEN CCC.ApportionmentWayCode = '1'

				   THEN(CASE WHEN (SELECT SUM(VLBS.SaleableArea)
							FROM viewLogicBuilding VLBS
							INNER JOIN Contract_trade.dbo.ContractCostCategory_Building CCCCB2 ON CCCCB2.ContractCostCategoryCode = CCC.Code
                                                              AND CCCCB2.ResourceID = CCC.ResourceID
                                                              AND VLBS.Code = CCCCB2.BuildingCode
                              WHERE     VLBS.StageCode =VLB.StageCode) <> 0
							  THEN CCC.CurrentPayAmount * VLB.SaleableArea
                          / ( SELECT    SUM(VLBS.SaleableArea)
                              FROM      viewLogicBuilding VLBS
                                        INNER JOIN Contract_trade.dbo.ContractCostCategory_Building CCCCB2 ON CCCCB2.ContractCostCategoryCode = CCC.Code
                                                              AND CCCCB2.ResourceID = CCC.ResourceID
                                                              AND VLBS.Code = CCCCB2.BuildingCode
                              WHERE     VLBS.StageCode =VLB.StageCode
                            ) 
							ELSE (CCC.CurrentPayAmount / ( SELECT    Count(CCCCB1.ContractCostCategoryCode)
                              FROM      viewLogicBuilding VLBS
                                        INNER JOIN Contract_trade.dbo.ContractCostCategory_Building CCCCB1 ON CCCCB1.ContractCostCategoryCode = CCC.Code
                                                              AND CCCCB1.ResourceID = CCC.ResourceID
                                                              AND VLBS.Code = CCCCB1.BuildingCode
                              WHERE     VLBS.StageCode = VLB.StageCode
                            )) END
							 )
                   ELSE CCCB.CurrentPayAmount
              END ) AS '支付金额' ,
			
			 currentPayedUntaxAmount=(CCCB.CurrentPayAmount), --'不含税的支付金额':也应该分三种情况进行处理:可售面积、楼栋面积、其他
            PFIN.TradeDate AS '支付时间'
    FROM    Contract_trade.dbo.ContractCostCategory CCC
            INNER JOIN SubjectDB.Contract.Contract CC ON CC.Code = CCC.ContractCode
                                                         AND CC.ContractTypeCode IN (
                                                         '3', '4', '7' )
                                                         AND CC.VersionEndTime IS NULL
                                                         AND CC.ValidStatus = 1
            INNER JOIN Contract_trade.dbo.ContractCostCategory_Building CCCB ON CCCB.ContractCostCategoryCode = CCC.Code
                                                              AND CCCB.ResourceID = CCC.ResourceID
            INNER JOIN SubjectDB.LandObtained.EditContractPlan LECP ON LECP.Code = CCC.ContractPlanCode
                                                              AND LECP.VersionEndTIme IS NULL
                                                              AND LECP.ValidStatus = 1
            INNER JOIN viewLogicBuilding VLB ON VLB.Code = CCCB.BuildingCode
                                                AND VLB.StageCode = '4'
            INNER JOIN SubjectDB.Finance.CostCategory FCC ON FCC.Code = CCC.CostCategoryCode
                                                             AND FCC.VersionEndTime IS NULL
                                                             AND FCC.ValidStatus = 1
            INNER JOIN SINOOCEAN_FINANCE.dbo.PaymentFormNew PFN ON PFN.Code = CCC.CurrentResourceID
                                                             AND PFN.Status = '2'
            INNER JOIN SINOOCEAN_FINANCE.dbo.PaymentFormInformationNew PFIN ON PFIN.PaymentFormCode = PFN.Code
			inner join subjectdb.contract.contractpayplan scc on scc.code = pfn.EventID
															  and pfn.status = '2'
    WHERE   ( CCC.CurrentResourceID IS NOT NULL
              AND CCC.CurrentResourceID <> ''
            ) 	
   and CC.ProjectCode in ('AE64C444-D91C-47ED-8FF0-FAA6235368B9')

  重构后的sql代码:

 

--查询建设成本
--作者:刘文彬
--日期:2016-7-9
USE SubjectDB
GO          
	SELECT  CC.ProjectCode AS '项目编码' ,
            CCCB.BuildingCode AS '楼栋编码' ,
            VLB.PlanLogicBuildingCnName AS '楼栋名称' ,
            CCC.CostCategoryCode AS '科目编码' ,
            FCC.CnName AS '科目名称',
			[contract].[fnGetPayedAmount](ccc.ApportionmentWayCode,ccc.Code,ccc.ResourceID,ccc.CurrentPayAmount,CCCB.CurrentPayAmount,vlb.StageCode,vlb.PlanLogicBuildingSaleableArea,vlb.PlanLogicBuildingConstructionArea) AS '支付金额',
			[contract].[fnGetPayedAmount](ccc.ApportionmentWayCode,ccc.Code,ccc.ResourceID,ccc.CurrentPayAmount,CCCB.CurrentPayAmount,vlb.StageCode,vlb.PlanLogicBuildingSaleableArea,vlb.PlanLogicBuildingConstructionArea) * [contract].[fnGetUnTaxAmountRate](scc.Code,scc.Amount) as '不含税的支付金额',
            PFIN.TradeDate AS '支付时间'
    FROM    Contract_trade.dbo.ContractCostCategory CCC
            INNER JOIN SubjectDB.Contract.Contract CC ON CC.Code = CCC.ContractCode
                                                         AND CC.ContractTypeCode IN (
                                                         '3', '4', '7' )
                                                         AND CC.VersionEndTime IS NULL
                                                         AND CC.ValidStatus = 1
            INNER JOIN Contract_trade.dbo.ContractCostCategory_Building CCCB ON CCCB.ContractCostCategoryCode = CCC.Code
                                                              AND CCCB.ResourceID = CCC.ResourceID
            INNER JOIN SubjectDB.LandObtained.EditContractPlan LECP ON LECP.Code = CCC.ContractPlanCode
                                                              AND LECP.VersionEndTIme IS NULL
                                                              AND LECP.ValidStatus = 1
            INNER JOIN [contract].[fnCreateViewLogicBuilding]() VLB ON VLB.PlanLogicBuildingCode = CCCB.BuildingCode
                                                AND VLB.StageCode = '4'
            INNER JOIN SubjectDB.Finance.CostCategory FCC ON FCC.Code = CCC.CostCategoryCode
                                                             AND FCC.VersionEndTime IS NULL
                                                             AND FCC.ValidStatus = 1
            INNER JOIN SINOOCEAN_FINANCE.dbo.PaymentFormNew PFN ON PFN.Code = CCC.CurrentResourceID
                                                             AND PFN.Status = '2'
            INNER JOIN SINOOCEAN_FINANCE.dbo.PaymentFormInformationNew PFIN ON PFIN.PaymentFormCode = PFN.Code
			inner join subjectdb.contract.contractpayplan scc on scc.code = pfn.EventID
															  and pfn.status = '2'	
    WHERE   ( CCC.CurrentResourceID IS NOT NULL
              AND CCC.CurrentResourceID <> ''
            ) 	
   and CC.ProjectCode in ('AE64C444-D91C-47ED-8FF0-FAA6235368B9')

三、使用场景:

  1、什么情况下使用?

应该说,这个其实已经不用我多说了吧。当你的sql代码中有比较复杂的处理逻辑,代码冗长的时候。当你的sql代码有较多重复性代码的时候。当你看到一个sql语句,像上面那样的时候……

  2、什么情况下不使用?

其实,这个问题就是一个寻求平衡点的问题,在性能和可维护性的权衡下做出一个更符合你需求的选择。

例如:假定有一个执行 SQL SELECT 语句的 UDF,执行该语句需要一秒钟。如果此 UDF 在 SELECT 或 WHERE 子句中使用,它将为每一行执行。因此,执行主查询所花费的时间会急剧增加,这取决于评估和返回的行数以及适当的索引类型这样的因素。如果是这种情况,则在使用 UDF 之前,要仔细地权衡所作的选择并进行一些性能测试

四、如何使用?(后续更新中,敬请期待!)

五、对比分析:(后续更新中,敬请期待!)

  1、函数和自定义函数

  2、函数和存储过程

六、小结:(后续更新中,敬请期待!)


你可能感兴趣的:(●数据库,------【SQL】)