如何在联合表中对多列的多行进行分组,并按1列分组

时间:2014-11-30 05:27:46

标签: sql-server group-by for-xml-path

我有一个来自3个不同表格的联合表。

Select DoctorTable.Doctor, NurseTable.Nurse , PatientTable.Patents 

FROM PatientTable

LEFT JOIN DoctorTable on DoctorTable.DoctorCode = PatientTable.DoctorCode

LEFT JOIN NurseTable on DoctorTable.DoctorCode = NurseTable.DoctorCode


Patient     Doctor        Nurse
John        Peter         Mary
John        Peter         Amy
Kate        Terry         Mary
Kate        Leo           Ivy
Paul        NULL          NULL
Emily       NULL          NULL

我想在' Doctor'中使用逗号加入具有相同值的行。列的结果如下

Patient     Doctor        Nurse
John        Peter         Mary, Amy
Kate        Terry, Leo    Mary, Ivy
Paul        Null          Null
Emily       NULL          NULL

由于我仍然有一些列要加入此表,还需要使用','对行进行分组,使用FOR XML PATH('')对每个列进行分组会很慢。那么如何有效地对这个表进行分组呢?

1 个答案:

答案 0 :(得分:1)

我认为答案是使用聚合函数来连接组中的行。太糟糕的TSQL没有(这有多难?),但如果你不介意使用SQLCLR,这里是如何在MSDN中用.NET创建用户定义的聚合连接函数:

MSDN String Utility Functions Sample

<Serializable(), Microsoft.SqlServer.Server.SqlUserDefinedAggregate(Microsoft.SqlServer.Server.Format.UserDefined, IsInvariantToNulls:=True, IsInvariantToDuplicates:=False, IsInvariantToOrder:=False, MaxByteSize:=8000)> _
Public Class Concatenate : Implements Microsoft.SqlServer.Server.IBinarySerialize

    Private Builder As StringBuilder

    Public Sub Init()
        Builder = New StringBuilder
    End Sub

    Public Sub Accumulate(ByVal value As SqlString)
        If value.IsNull Then Return
        Builder.Append(",").Append(value.Value)
    End Sub

    Public Sub Merge(ByVal other As Concatenate)
        Builder.Append(other.Builder)
    End Sub

    Public Function Terminate() As SqlString
        If Builder Is Nothing Then Return New SqlString("")
        Return New SqlString(Builder.ToString.Substring(1))
    End Function

    Public Sub Read(ByVal r As BinaryReader) Implements Microsoft.SqlServer.Server.IBinarySerialize.Read
        If r Is Nothing Then Throw New ArgumentNullException("r")
        Builder = New StringBuilder(r.ReadString())
    End Sub

    Public Sub Write(ByVal w As BinaryWriter) Implements Microsoft.SqlServer.Server.IBinarySerialize.Write
        If w Is Nothing Then Throw New ArgumentNullException("w")
        w.Write(Builder.ToString())
    End Sub

End Class

然后,您可以执行以下操作:

SELECT PatientCode, Patient, dbo.Concatenate(Doctor), dbo.Concatenate(Nurse) 
FROM PatientTable
LEFT JOIN DoctorTable on DoctorTable.DoctorCode = PatientTable.DoctorCode
LEFT JOIN NurseTable on DoctorTable.DoctorCode = NurseTable.DoctorCode
GROUP BY PatientCode, Patient