SQL Server中的函数

SQL Server中的函数,sql,sql-server,ssms-2014,Sql,Sql Server,Ssms 2014,我们正在将数据库后端从Access移动到SQL Server,并请求帮助如何在SQL Server中实现我们以前在Access中使用的用户定义函数。或者,如果有一个更直接的解决方案来解决我们正在做的事情,比如说只使用一个比我熟悉的更复杂的SQL语句,那也可以 因此,我们目前有一个类似以下内容的查询: SELECT StaffLine(Docket, Lead, Reviewer) AS OfficeStaff, Docket, FiledDate, Lead, Reviewer, Status,

我们正在将数据库后端从Access移动到SQL Server,并请求帮助如何在SQL Server中实现我们以前在Access中使用的用户定义函数。或者,如果有一个更直接的解决方案来解决我们正在做的事情,比如说只使用一个比我熟悉的更复杂的SQL语句,那也可以

因此,我们目前有一个类似以下内容的查询:

SELECT StaffLine(Docket, Lead, Reviewer) AS OfficeStaff, Docket, FiledDate, Lead, Reviewer, Status, [a lot of other fields]
FROM tCases
WHERE Status = 1;
Office Staff:  John Doe (lead), Bob Jones, Billy Bob, Pat Jones, Jane Doe (reviewer)
这里,OfficeStaff是从StaffLine函数计算出来的。StaffLine是一个函数,它只构建所有指定工作人员的完整语句,从存储数据的两个不同表中提取。团队主要成员团队负责人和审阅人存储在主表tCases中。然后,其他团队成员的所有名称都存储在一个名为tMembers的相关表中。因此OfficeStaff的值通常如下所示:

SELECT StaffLine(Docket, Lead, Reviewer) AS OfficeStaff, Docket, FiledDate, Lead, Reviewer, Status, [a lot of other fields]
FROM tCases
WHERE Status = 1;
Office Staff:  John Doe (lead), Bob Jones, Billy Bob, Pat Jones, Jane Doe (reviewer)
我们想要实现一个类似于StaffLine函数的函数,但是要在SQL Server中实现。我已经在下面粘贴了我们的StaffLine函数。我在SQLServer管理工作室中研究了如何使用可编程性构建用户定义的函数,但是我还没有从我找到的文档中理解足够的意义。因此,非常感谢在ManagementStudio中实现该功能时提供的任何帮助,以及我将把它放在何处

Access中当前的VBA用户定义函数:

Public Function StaffLine(Docket As String, _
                          Lead As Variant, _
                          Reviewer As Variant _
                          ) As String
    ' Lead and Reviewer are Variants because they are sometimes Null, and String can't handle Nulls.

    ' Start off building string by adding text for Lead
    StaffLine = "Office Staff: " & Lead & " (lead), "

    ' Next add text for any non-lead team members
    Dim rs As DAO.Recordset
    Set rs = CurrentDb.OpenRecordset("SELECT MemberName FROM tMembers WHERE mDocket = '" & Docket & "'")

    ' Check to see if the recordset actually contains rows
    If Not (rs.EOF And rs.BOF) Then
        rs.MoveFirst
        Do Until rs.EOF = True
            StaffLine = StaffLine & rs!MemberName & ", "
            'Move to the next record.
            rs.MoveNext
        Loop
    End If

    ' Finally, add text for reviewer
    StaffLine = StaffLine & Reviewer & " (reviewer)"

End Function

下面是SQL的实现方法

首先创建此视图:

CREATE VIEW Staff_String AS
(
  SELECT Docket, 'Office Staff : ' || COALESCE(C.Lead || ' (lead),','') || 
                  STRING_AGG(M.MemberName,', ') ||
                  C.Reviewer || '(reviewer)' as OfficeStaff
  FROM tCases C
  JOIN tMembers M ON M.mDocket = C.Docket
  GROUP BY C.Docket, C.Lead, C.Reviewer
)
在SQL中,此视图的作用类似于函数或映射-它定义了如何为所有摘要编号生成人员字符串

在SQL中,我们喜欢在集合上工作——在SQL中,我们不应该使用循环进行迭代,循环是邪恶的

然后,要进行选择,只需加入即可:

SELECT Staff_String.OfficeStaff, Docket, FiledDate, Lead, Reviewer, Status, [a lot of other fields]
FROM tCases 
LEFT JOIN Staff_string ON tCases.Docket = Staff_string.Docket
WHERE tCases.Status = 1;

泰达!简单。

以下是SQL的方法

首先创建此视图:

CREATE VIEW Staff_String AS
(
  SELECT Docket, 'Office Staff : ' || COALESCE(C.Lead || ' (lead),','') || 
                  STRING_AGG(M.MemberName,', ') ||
                  C.Reviewer || '(reviewer)' as OfficeStaff
  FROM tCases C
  JOIN tMembers M ON M.mDocket = C.Docket
  GROUP BY C.Docket, C.Lead, C.Reviewer
)
在SQL中,此视图的作用类似于函数或映射-它定义了如何为所有摘要编号生成人员字符串

在SQL中,我们喜欢在集合上工作——在SQL中,我们不应该使用循环进行迭代,循环是邪恶的

然后,要进行选择,只需加入即可:

SELECT Staff_String.OfficeStaff, Docket, FiledDate, Lead, Reviewer, Status, [a lot of other fields]
FROM tCases 
LEFT JOIN Staff_string ON tCases.Docket = Staff_string.Docket
WHERE tCases.Status = 1;

泰达!简单。

下面是一个使用xml和交叉应用的完整工作示例:

declare @tCases table (
    tCasesID int identity(1,1) not null primary key clustered
,   docketID int not null
,   staffID  int not null
,   GivenName nvarchar(255) not null
,   SurName nvarchar(255) not null
,   Role_   nvarchar(255) not null
)

insert into @tCases (docketID, staffID, GivenName, SurName, Role_)

select 1, 100, 'bob', 'richards', 'reviewer' union all
select 1, 110, 'john', 'doe', 'lead' union all
select 1, 112, 'jane', 'doe', 'reviewer';

declare @tMember table (
    tMemberID int identity(1,1) not null primary key clustered
,   docketID int not null
,   staffID     int not null
,   GivenName   nvarchar(255) not null
,   SurName     nvarchar(255) not null
);

insert into @tMember (docketID, staffID, GivenName, SurName)

select 1, 133, 'Mary', 'Jones' union all
select 1, 134, 'Tom', 'Jones' union all
select 1, 105, 'Jimmy', 'Jon' union all
select 1, 109, 'Marsha', 'Marsha';


;with cte as (
    select docketid
         , GivenName
         , SurName
      from @tCases

    union all

     select docketid
         , GivenName
         , SurName
       from @tMember
       )

    select distinct a.docketID
         , x.list
      from @tCases a
    cross apply (

                select stuff 
                            ( 
                            (select  ', ' +GivenName + ' ' + SurName 
                  from cte b
                 where a.docketid = b.docketid
                 for xml path ('')
                 )  , 1, 1, '') as list ) as x
以下是结果集:

docketID    list
1           bob richards, john doe, jane doe, Mary Jones, Tom Jones, Jimmy Jon, Marsha Marsha

下面是一个使用xml和交叉应用的完整工作示例:

declare @tCases table (
    tCasesID int identity(1,1) not null primary key clustered
,   docketID int not null
,   staffID  int not null
,   GivenName nvarchar(255) not null
,   SurName nvarchar(255) not null
,   Role_   nvarchar(255) not null
)

insert into @tCases (docketID, staffID, GivenName, SurName, Role_)

select 1, 100, 'bob', 'richards', 'reviewer' union all
select 1, 110, 'john', 'doe', 'lead' union all
select 1, 112, 'jane', 'doe', 'reviewer';

declare @tMember table (
    tMemberID int identity(1,1) not null primary key clustered
,   docketID int not null
,   staffID     int not null
,   GivenName   nvarchar(255) not null
,   SurName     nvarchar(255) not null
);

insert into @tMember (docketID, staffID, GivenName, SurName)

select 1, 133, 'Mary', 'Jones' union all
select 1, 134, 'Tom', 'Jones' union all
select 1, 105, 'Jimmy', 'Jon' union all
select 1, 109, 'Marsha', 'Marsha';


;with cte as (
    select docketid
         , GivenName
         , SurName
      from @tCases

    union all

     select docketid
         , GivenName
         , SurName
       from @tMember
       )

    select distinct a.docketID
         , x.list
      from @tCases a
    cross apply (

                select stuff 
                            ( 
                            (select  ', ' +GivenName + ' ' + SurName 
                  from cte b
                 where a.docketid = b.docketid
                 for xml path ('')
                 )  , 1, 1, '') as list ) as x
以下是结果集:

docketID    list
1           bob richards, john doe, jane doe, Mary Jones, Tom Jones, Jimmy Jon, Marsha Marsha

下面是如何创建函数,您需要用变量的实际大小更新参数的最大大小

    CREATE FUNCTION  [dbo].[StaffLine](@Docket varchar(max), @Lead Varchar(max) = null, @Reviewer Varchar(Max) = null)  RETURNS varChar(max)
    AS  
    BEGIN 
        Declare @StaffLine as varChar(max) = ''
        Declare @Temp TABLE (ID int identity, MemberName varchar(100))
        Declare @row_count as int = 1
        Declare @total_records as int

        --Fill hte table to loop
        Insert Into @Temp
        SELECT MemberName 
        FROM tMembers WHERE mDocket = @Docket

        Set @StaffLine = 'Office Staff: ' + ISNULL(@Lead, '') + ' (lead), '

        Set @total_records = (Select Count(*) from @Temp) -- Get total records to loop
        While @row_count <= @total_records
        Begin            
            Set @StaffLine += (Select MemberName +  ', '
            From @Temp Where ID = @row_count)

            Set @row_count += 1
        End
        SET @StaffLine +=  ISNULL(@Reviewer, '') + ' (reviewer)'
        RETURN @StaffLine
    END

下面是如何创建函数,您需要用变量的实际大小更新参数的最大大小

    CREATE FUNCTION  [dbo].[StaffLine](@Docket varchar(max), @Lead Varchar(max) = null, @Reviewer Varchar(Max) = null)  RETURNS varChar(max)
    AS  
    BEGIN 
        Declare @StaffLine as varChar(max) = ''
        Declare @Temp TABLE (ID int identity, MemberName varchar(100))
        Declare @row_count as int = 1
        Declare @total_records as int

        --Fill hte table to loop
        Insert Into @Temp
        SELECT MemberName 
        FROM tMembers WHERE mDocket = @Docket

        Set @StaffLine = 'Office Staff: ' + ISNULL(@Lead, '') + ' (lead), '

        Set @total_records = (Select Count(*) from @Temp) -- Get total records to loop
        While @row_count <= @total_records
        Begin            
            Set @StaffLine += (Select MemberName +  ', '
            From @Temp Where ID = @row_count)

            Set @row_count += 1
        End
        SET @StaffLine +=  ISNULL(@Reviewer, '') + ' (reviewer)'
        RETURN @StaffLine
    END

请提供当前输出的一个小示例,好吗?SQL Server中的函数速度很慢。为什么不直接左键连接表并使用concat或+来构建字符串呢?就我个人而言,我只是将它们作为单独的列添加,并在前端构建字符串,以便数据保持规范化。不要忘记在连接过程中使用isnull,以防止在任何单个元素为空时整个字符串为nullnull@Emily贝丝-这里有三个答案,你能标出你用过的那一个吗?还在研究它们对不起,我是新手,速度慢。坚持下去,会很有趣的!请提供当前输出的一个小示例,好吗?SQL Server中的函数速度很慢。为什么不直接左键连接表并使用concat或+来构建字符串呢?就我个人而言,我只是将它们作为单独的列添加,并在前端构建字符串,以便数据保持规范化。不要忘记在连接过程中使用isnull,以防止在任何单个元素为空时整个字符串为nullnull@Emily贝丝-这里有三个答案,你能标出你用过的那一个吗?还在研究它们对不起,我是新手,速度慢。坚持下去,会很有趣的!字符串_AGG?OP被标记为ssms-2014:@MatBailie-哦,这太可悲了。如果没有STRING_AGG,那么可以使用XML构建逗号sep.列表。这很难看,但比循环更好。下面是我2009年写的答案,看起来像是10年前写的?OP被标记为ssms-2014:@MatBailie-哦,这太可悲了。如果没有STRING_AGG,那么可以使用XML构建逗号sep.列表。这很难看,但比循环更好。下面是我在2009年写的答案,看起来好像是10年前写的。