(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、函数和存储过程