Mar*_*s L 4 sql t-sql sql-server
我正在编写一个导出函数,我需要将联系人导出到Excel,而且我遇到了技术问题 - 或者我的SQL技能差距可能更接近事实了.;)
这是场景:我在数据库中有很多联系人.每个联系人都可以有许多不同的角色,例如联系人可以是C#Developer和DBA,也可以是DBA和IT-manager.这些分为三个表,如下所示:
------------------- ------------------- -------------------
* Contact * * ContactRole * * Role *
------------------- ------------------- -------------------
* ID * * ContactID * * ID *
* Name * * RoleID * * Name *
* Address * ------------------- -------------------
-------------------
Run Code Online (Sandbox Code Playgroud)
不太难以遵循.有一组联系人和一组角色.这些由各个ID上的ContactRole表连接.
当我导出联系人时,我需要在导出中有一个列,所有角色都以逗号分隔,例如C# Developer, DBA或DBA, IT-manager.导出将从ASP.NET/C#代码隐藏完成,所以我想我可以在代码中执行此操作,但我觉得可以在SQL中执行此操作.
数据来自SQL Server 2005.
仅仅因为你使用SQL Server 2005(如果你很幸运并且正确设置了所有XML设置),这里是你的简单SQL查询(纯SQL而没有函数):
SELECT c.ID, c.Name, c.Address,
( SELECT r.Name + ','
FROM "ContactRole" cr
INNER JOIN "Role" r
ON cr.RoleID = r.ID
WHERE cr.ContactID = c.ID
ORDER BY r.ID --r.Name
FOR XML PATH('')
) AS "Roles"
FROM "Contact" c
Run Code Online (Sandbox Code Playgroud)
要测试它是否适合您,只需执行以下整个代码段:
WITH "Contact" (ID, Name, Address) AS (
SELECT 1, 'p1-no role', NULL
UNION ALL SELECT 2, 'p2-one role', NULL
UNION ALL SELECT 3, 'p3-two roles', NULL
)
, "Role" (ID, Name)AS (
SELECT 1, 'teacher'
UNION ALL SELECT 2, 'student'
)
, "ContactRole" (ContactID, RoleID) AS (
SELECT 2, 1
UNION ALL SELECT 3, 1
UNION ALL SELECT 3, 2
)
SELECT c.ID, c.Name, c.Address,
( SELECT r.Name + ','
FROM "ContactRole" cr
INNER JOIN "Role" r
ON cr.RoleID = r.ID
WHERE cr.ContactID = c.ID
ORDER BY r.ID --r.Name
FOR XML PATH('')
) AS "Roles"
FROM "Contact" c
Run Code Online (Sandbox Code Playgroud)
你应该得到以下结果:
ID Name Address Roles
----------- ------------ ----------- ------------------
1 p1-no role NULL NULL
2 p2-one role NULL teacher,
3 p3-two roles NULL teacher,student,
Run Code Online (Sandbox Code Playgroud)
您可以使用CLR用户定义的聚合来获得此类结果.可以像用户定义的聚合(例如SUM或MAX)一样调用用户定义的聚合,并且它不使用游标.
using System;
using System.Data;
using Microsoft.SqlServer.Server;
using System.Data.SqlTypes;
using System.IO;
using System.Text;
[Serializable()]
[SqlUserDefinedAggregate(
Format.UserDefined,
IsInvariantToNulls=true,
IsInvariantToDuplicates=false,
IsInvariantToOrder=false,
MaxByteSize=8000)]
public class Concat : IBinarySerialize
{
#region Private fields
private string separator;
private StringBuilder intermediateResult;
#endregion
#region IBinarySerialize members
public void Read(BinaryReader r)
{
this.intermediateResult = new StringBuilder(r.ReadString());
}
public void Write(BinaryWriter w)
{
w.Write(this.intermediateResult.ToString());
}
#endregion
#region Aggregation contract methods
public void Init()
{
this.separator = ", ";
this.intermediateResult = new StringBuilder();
}
public void Accumulate(SqlString pValue)
{
if (pValue.IsNull)
{
return;
}
if (this.intermediateResult.Length > 0)
{
this.intermediateResult.Append(this.separator);
}
this.intermediateResult.Append(pValue.Value);
}
public void Merge(Concat pOtherAggregate)
{
this.intermediateResult.Append(pOtherAggregate.intermediateResult);
}
public SqlString Terminate()
{
return this.intermediateResult.ToString();
}
#endregion
}
Run Code Online (Sandbox Code Playgroud)
在这篇文章中,您将找到代码以及我遇到的调试问题的解决方案.
我在生产环境中使用了这个聚合,它表现得非常好.