SQL Server函数简介,其优缺点
什么是SQL函数?
使用T-SQL或CLR(公共语言运行时)例程,SQL Server函数可用于返回单个(定标)值或表,并且执行的计算量通常会比一般代码中要复杂的多。
什么时候使用函数而不是内联代码是一个好主意?
善用
函数可用于替换视图(返回表),作为表中的计算列,执行一致的查找操作或仅用于模块化代码以帮助减少所需的更改。
不良使用
我们一直在看到它,但是当您处理大型数据集时,不应使用函数代替联接来返回查找数据。即使每一行都已经遇到了该值,它也会调用相同的函数。在这些情况下,请使用联接。
定标器功能示例
Scaler函数最适合用于执行诸如基于行的重新格式化或计算之类的逻辑,因为按其性质,每行都会调用它们,它们可用于在另一个表中查找数据,但是通常,通过使用,可以获得更好的性能一个联接。为此,我们可以在以下链接上查看我们的年龄函数。
在他们填写表格时存储某人的年龄是没有意义的,因为稍后查询数据时将过时。更好的选择是捕获出生日期并即时对其进行计算。在我们的函数中,我们添加了一个字段直到,可以用来追溯计算的日期,或者更确切地说,可以计算出死亡的时间(此功能已扩展为NHS合同)。
Example
CREATE FUNCTION [Dates].[GetAge](@Date DATETIME2,@Until DATETIME2) RETURNS INT AS BEGINIF @Until IS NULL SET @Until=CONVERT(DATE,GETDATE())DECLARE @Age INT=DATEDIFF(YEAR,@Date,@Until)+(CASE WHEN DATEPART(DAYOFYEAR,@Date)>(DATEPART(DAYOFYEAR,@Until)+(CASE WHEN dbo.GetLeapYear(@Date)=1 AND DATEPART(DAYOFYEAR,@Date)>59 THEN 1 ELSE 0 END))THEN -1 ELSE 0 END)RETURN @AgeEND
定标器功能示例
要从虚构表中使用此表,我们只需使用该表即可提供当前年龄或死亡年龄。
Use in a select statement
SELECT [PersonID],[DateOfBirth],[dbo].[GetAge]([DateOfBirth],[DeceasedDate]) AgeAsFunction,--Simpler code to understand!DATEDIFF(YEAR,[DateOfBirth],[DeceasedDate])+(CASE WHEN DATEPART(DAYOFYEAR,[DateOfBirth])>(DATEPART(DAYOFYEAR,[DeceasedDate])+(CASE WHEN dbo.GetLeapYear([DateOfBirth])=1 AND DATEPART(DAYOFYEAR,[DateOfBirth])>59 THEN 1 ELSE 0 END))THEN -1 ELSE 0 END) AgeAsScript,[DeceasedDate]FROM [Person]
定标器功能示例
优点:一致,模块化,更紧凑,有可能减少更改次数
缺点:要查看代码,您需要在函数中查找
尽管通常有用,但此功能也非常精确,因为它利用了year年功能。它本质上是不确定的,因此永远不应将其存储为持久性数据。
表格栏示例
可以将已计算的列添加为持久性(数据时发生更改)或不持久性(每次选择该行时计算)。我们可以看看在内容管理系统中使用它们的两种方式。
注意:持久数据可能很难实现,因为它需要满足一组约束
非持久性:年龄
使用上面的age函数,我们可以将它添加到表中并从其他列中传递值。然后,我们只需将其选择为列即可。
Add to a table
CREATE TABLE [Person]([PersonID] [int] IDENTITY(1,1) NOT NULL,[DateOfBirth] [datetime] NULL,[Age] AS ([dbo].[GetAge]([DateOfBirth],[DeceasedDate])),[DeceasedDate] [datetime] NULL)
Select Statement
SELECT [PersonID],[DateOfBirth],[Age] AgeAsColumn,--Even simpler code to understand!DATEDIFF(YEAR,[DateOfBirth],[DeceasedDate])+(CASE WHEN DATEPART(DAYOFYEAR,[DateOfBirth])>(DATEPART(DAYOFYEAR,[DeceasedDate])+(CASE WHEN dbo.GetLeapYear([DateOfBirth])=1 AND DATEPART(DAYOFYEAR,[DateOfBirth])>59 THEN 1 ELSE 0 END))THEN -1 ELSE 0 END) AgeAsScript,[DeceasedDate]FROM [Person]
非持久性:年龄
优点:一致,模块化
缺点:不需要时会降低查询速度。
持续:精简的CSS
我们有一个功能,可将CSS所需的空间减少多达30%。定期调用它会减慢表的选择速度,并且由于很少更新数据,因此在插入/更新时执行计算是有意义的。通过将列创建为函数,我们也无需将这些操作作为触发器执行。
Add to a Table
CREATE TABLE CSS(CSSID INT IDENTITY(1,1) NOT NULL,CSSText NVARCHAR(MAX),CSSMin AS (ous.CSSProcessor([CSSText])) PERSISTED)
持续:精简的CSS
可以像选择普通列一样选择它,并且数据存储在表中。它还避免了使用大量的replace语句使我们的代码code肿。
优点:一致,模块化,更快的选择速度,无需扳机!
缺点:增加了桌子所需的空间,降低了插入速度
更换视图
除了在多个地方定期使用相同的联接之外,我们通常不使用视图。
即使在这些情况下,也没有理由不能更有效地使用表函数。我们使用的表可以在下面的链接上找到,我们有两个用法示例,一个通过函数,另一个通过视图。
Create a function
CREATE FUNCTION Dates.GetCalender(@DateFrom DATETIME2,@DateTo DATETIME2,@Function INT) RETURNS @D TABLE (CalenderDate DATETIME2(7) NOT NULL PRIMARY KEY,CalenderCA INT NULL,CalenderCD INT NULL,WeekDayID INT NULL,WeekDayName VARCHAR(9) NULL,HolidayType NVARCHAR(100)) AS BEGININSERT INTO @DSELECT c.*,HolidayTypeFROM [Utilities].[Dates].[Calender] cLEFT JOIN Utilities.Dates.CalenderHolidays h ON h.CalenderDate=c.CalenderDate AND CalenderFunction=@FunctionWHERE c.CalenderDate BETWEEN @DateFrom AND @DateTo RETURNENDGO
Create a view
CREATE VIEW Dates.GetCalenderView ASSELECT c.CalenderDate, CalenderCA, CalenderCD, WeekDayID, WeekDayName,h.HolidayType,c.CalenderFunctionFROM (SELECT CalenderDate, CalenderCA, CalenderCD, WeekDayID, WeekDayName, CalenderFunction FROM [Utilities].[Dates].[Calender],(SELECT DISTINCT CalenderFunction FROM Dates.CalenderHolidays) x) cLEFT JOIN Utilities.Dates.CalenderHolidays h ON h.CalenderDate=c.CalenderDate AND h.CalenderFunction=c.CalenderFunction
Usage
SELECT * FROM Dates.GetCalender('2018-01-01','2018-12-31',0) --England & WalesSELECT * FROM Dates.GetCalender('2018-01-01','2018-12-31',1) --Scotland----OR----SELECT * FROM Dates.GetCalenderView WHERE CalenderDate BETWEEN '2018-01-01' AND '2018-12-31' AND CalenderFunction=0
更换视图
好处:调用紧凑,带有主键(非常适合进一步联接)返回,可以在代码的早期使用参数。
缺点:要构建的代码较多,灵活性较差
用于申请联接
表函数非常适合在“应用联接”中使用,因为可以逐行传递数据。我们使用TextToRows函数在SQL Server中将字符串分开。在下面的示例中,我们使用了double apply来使用不同的定界符将数据拆分两次。
SQL Code
DECLARE @TestText TABLE(TextToSplit NVARCHAR(100))INSERT INTO @TestText SELECT 'Text,To,Tows:Split,One'INSERT INTO @TestText SELECT 'Text,To,Tows:Split,Two'SELECT t.TextToSplit,s1.WordInt,s1.WordStr,s2.WordInt,s2.WordStrFROM @TestText tOUTER APPLY dbo.TextToRows(':',TextToSplit) s1OUTER APPLY dbo.TextToRows(',',WordStr) s2
Further detail
Some of the functions we have written can be found below.