本文为原创,如需转载,请注明作者和出处,谢谢!
最近做一个项目,遇到一个在分组的情况下,将某一列的字段值(varchar类型)连接起来的问题,类似于sum函数对int型字段值求和。 如有一个表t_table,结构和数据如图1
图1
其中要按着xh字段分组,并且将每一组name字段值连接起来。最终结果希望如图2所示
图2
表中的th字段值对于每一个xh值是唯一的,也是有限的,也就是说,对于一个xh值,th的值不会太多,如最多是10个(从1至10)。
以上需求最终想了三种方法来解决这个问题。
一、修改表结构
如果是新的项目,可以考虑修改一下表的结构。如果t_table的结构修改如下:
xh value1value2
value3 value4 .... .... value10
0001123456654321456789
000212abcd4d2r343343dfd
0003abcde3132323
这种方法将value的值纵向改为横向,也就是说,按每一个xh值,将value字段的值按逆时针旋转了90度。 但这种方法要有一个前提,就是假设xh的每一个值所对应的value值不会太多,如上面不超过10个,这样才有可能建立有限个字段。如果按着上面的字段结构,只需要将这些字段加一起就可以了,也不用分组。如下所示:
<!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->
selectxh,(value1+value2+value3++value10)asvaluefromt_table
但这种方法至少有如下三个缺陷:
1.需要修改表结构,这对于已经进行很长时间或是已经上线的项目产不适用
2.对每一个xh字段的value取值数有限制,如果太多,就得建立很多字段。这样性能会降低。
3.这样做虽然查询容易,但如果需要对每一个xh的不同值频繁修改或加入新的值时,如果把它们都放到一行,容易因为行锁而降低性能。
二、动态生成select语句
让我们先看三条SQL语句:
<!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->selectxh,valueasth1fromt_tablewhereth=1
selectxh,valueasth2fromt_tablewhereth=2
selectxh,valueasth3fromt_tablewhereth=3
这三条语句分别使用th字段按着所有th可能的值来查询t_table,这三条SQL语句所查询出来的记录如图3所示。
图 3
然后再使用下面的语句按着xh分组:
<!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->selectxhfromt_tablegroupbyxh
得到的结果如图4所示。
图4
然后使用left join,以图4所示的表为最左边的表,进行连接,SQL语句如下:
<!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->selecta.xh,b.th1,c.th2,d.th3from
(selectxhfromt_tablegroupbyxh)a
leftjoin
(selectxh,valueasth1fromt_tablewhereth=1)bona.xh=b.xh
leftjoin
(selectxh,valueasth2fromt_tablewhereth=2)cona.xh=c.xh
leftjoin
(selectxh,valueasth3fromt_tablewhereth=3)dona.xh=d.xh
之所以使用left join,是因为按着th查询后,有的表的某些xh值可以没有,如图3中的第三个表,就没有0003。如果使用内连接,0003就无法在记录集中体现。这面的SQL的查询结果如图5所示。
图5
然后我们就可以使用如下的语句来连接th1、th2和th3了。
<!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->selectxh,(th1+th2+th3)asthfrommyview
myview表示将上面用left join的语句保存成的视图。
下面可以将这个过程写成一条SQL语句:
<!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->selectxh,(th1+th2+th3)asthfrom
(
selecta.xh,(casewhenb.th1isnullthen''elseb.th1end)asth1,
(casewhenc.th2isnullthen''elsec.th2end)asth2,
(casewhend.th3isnullthen''elsed.th3end)asth3
from
(selectxhfromt_tablegroupbyxh)a
leftjoin
(selectxh,valueasth1fromt_tablewhereth=1)bona.xh=b.xh
leftjoin
(selectxh,valueasth2fromt_tablewhereth=2)cona.xh=c.xh
leftjoin
(selectxh,valueasth3fromt_tablewhereth=3)dona.xh=d.xh
)x
由于null加上任何字符串都为null,因此,使用case语句来将null转换为空串。上面的SQL就会得到图2所示的查询结果。也许有的读者会问,如果th的可能取值可变呢!如xh为0001的th值四个:1至4。
那上面的SQL不是要再加一个left join吗?这样不是很不通用。 要解决这个问题也很容易。可以使用程序(如C#、Java等)自动生成上述的SQL,然后由程序提交给数据库,再执行。 当然,这需要程序事先知道th值对于当前程序最多有几个值,然后才可以自动生成上述的SQL语句。
这种方法几乎适合于所有的数据库,不过如果th的取值比较多的话,可能SQL语句会很长,但是如果用程序自动生成的话,就不会管这些了。
三、使用C#实现SQL Server2005的扩展聚合函数(当然,也可以用VB.NET)
这一种方法笔者认为是最“酷”的方法。因为每一个人都只想写如下的SQL语句就可以达到目录。
<!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->selectxh, dbo.joinstr(value)fromt_tablegroupbyxh
其中joinstr是一个聚合函数,功能是将每一组的某个字符串列的值首尾连接。上面的SQL也可以查询图2所示的结果。但遗憾的是,sql server2005并未提供可以连接字符串的聚合函数。下面我们就来使用C#来实现一个扩展聚合函数。
首先用VS2008/VS2005建立一个SQL Server项目,如图6所示。
图6
点击“确定”按钮后,SQL Server项目会要求连接一个数据库,我们可以选择一个数据库,如图7所示。
图7
然后在工程中加入一个聚合类(joinstr.cs),如图8所示。
图8
joinstr.cs中的最终代码如下:
<!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->usingSystem;
usingSystem.Data;
usingMicrosoft.SqlServer.Server;
usingSystem.Data.SqlTypes;
usingSystem.IO;
usingSystem.Text;
[Serializable]
[SqlUserDefinedAggregate(
Format.UserDefined,//usecustomserializationtoserializetheintermediateresult
IsInvariantToNulls=true,//optimizerproperty
IsInvariantToDuplicates=false,//optimizerproperty
IsInvariantToOrder=false,//optimizerproperty
MaxByteSize=8000)//maximumsizeinbytesofpersistedvalue
]
publicstructjoinstr:IBinarySerialize
{
privateSystem.Text.StringBuilderintermediateResult;
publicvoidInit()
{
//在此处放置代码
intermediateResult=newSystem.Text.StringBuilder();
}
publicvoidAccumulate(SqlStringValue)
{
intermediateResult.Append(Value.Value);
}
publicvoidMerge(joinstrGroup)
{
intermediateResult.Append(Group.intermediateResult);
}
publicSqlStringTerminate()
{
returnnewSqlString(intermediateResult.ToString());
}
publicvoidRead(BinaryReaderr)
{
intermediateResult=newStringBuilder(r.ReadString());
}
publicvoidWrite(BinaryWriterw)
{
w.Write(this.intermediateResult.ToString());
}
}
由于本例需要聚合字符串,而不是已经被序列化的类型,如int等,因此,需要实现IBinarySerialize接口来手动序列化。使用C#实现SQL Server聚合函数,也会受到字符串最大长度为8000的限制。
在编写完上述代码后,可以使用Visual Studio来部署(右向工程,在弹出菜单上选“部署”即可)。也可以使用SQL语句来部署。假设上面的程序生成的dll为MyAggregate.dll,可以使用下面的SQL语句来部署:
<!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->CREATEASSEMBLYMyAggFROM'D:\test\MyAggregate.dll'
CREATEAGGREGATEjoinstr(@inputnvarchar(200))RETURNSnvarchar(max)
EXTERNALNAMEMyAgg.joinstr
要注意的是,字符串类型需要用nvarchar,而不能用varchar。
第一条SQL语句是装载dll,第二条SQL语句是注册joinstr聚合函数(每一个C#类就是一个聚合函数)
在执行上面的SQL语句之前,需要将SQL Server2005的clr功能打开。如图9所示。
图9
如果想删除上面建立的聚合函数,可以使用如下的SQL语句:
<!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->dropaggregatejoinstr
在删除聚合函数后,可以将MyAggregate.dll卸载。
<!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->dropassembly MyAgg
OK,现在可以使用joinstr来聚合字符串了。
这种方法虽然显示很“酷”,但却要求开发人员熟悉扩展聚合函数的开发方法,如果开发人员使有的不是微软的开发工具,如使用Java,恐怕这种方法就只能是空谈了(除非开发小组内有人会用微软的开发工具)。
当然,如果使用其他的数据库,如oracle、mysql,也是可以实现类似扩展函数的功能的,如oracle可以使用java来进行扩展。但这要求开发人员具有更高的素质。
以上介绍的三种方法仅供参考,至于采用哪种方法,可根据实际需要和具体情况而定。如果哪位读者有更好的方法,请跟贴!
分享到:
相关推荐
在本文中,我们将探讨三种不同的方法来按列连接字符串,这些方法适用于已经存在的表结构,无需进行重大改动。 首先,我们可以考虑对表结构进行修改。如果可能的话,可以将原本垂直存储的`value`字段变为水平存储,...
- **LocalDB连接字符串示例**:LocalDB是一种轻量级的SQL Server数据库实例,特别适用于开发和测试环境。它允许快速的实例创建,且易于配置和部署。 - **SQL Server Express连接字符串示例**:SQL Server Express是...
本文将深入探讨如何使用ADO连接SQL Server,并解析数据库连接字符串的构造及其不同场景下的应用。 ### ADO连接SQL Server的数据库连接字符串详解 #### ODBC与OLEDB连接方式对比 ADO通过ODBC或OLEDB驱动程序与SQL ...
SQL Server 连接字符串是数据库应用开发中必不可少的一部分,它用于定义应用程序如何连接到SQL Server数据库。在VS2010环境下,理解并正确构造连接字符串对于开发高效、可靠的数据库应用至关重要。本解决方案提供了...
该书解释并比较了SQL Server 2000和SQL Server 2005在数据库开发相关问题上的解决方案,深入讨论了SQL Server 2005中新增的T-SQL编程特性,包含了大量的代码示例、表示例和逻辑难题以帮助数据库开发人员和管理员理解...
本文将详细探讨标题中提到的四个数据库系统——jtds、MySQL、Oracle和SQL Server的驱动程序及其连接字符串。 首先,jtds是一个开源的Java数据库连接器,主要支持Microsoft SQL Server和Sybase数据库。它的优点在于...
在SQL Server中,将某一列的值拼接成字符串是一个常见的需求,这通常涉及到数据的格式化输出,比如创建报告或者导出数据。这个过程可以通过几种不同的方法来实现,其中包括使用FOR XML PATH子句和CONCAT函数。我们将...
SQL Server数据库连接字符串是应用程序与SQL Server数据库之间建立连接的关键配置信息,用于指定数据库服务器的位置、身份验证方式、数据库名称等参数。以下是一份详细的关于SQL Server连接字符串的知识点介绍: 1....
本文将详细介绍几种常见的SQL Server 2005连接字符串配置方法,帮助开发者更高效地进行数据库连接。 #### 二、基本概念 **连接字符串(Connection String):**用于定义应用程序如何与数据库服务器建立连接的一组...
在Java编程环境中,连接Microsoft SQL Server 2005数据库主要依赖于驱动程序和正确的连接字符串。本篇文章将深入探讨这两个关键元素,帮助你更好地理解和实施Java与SQL Server 2005之间的通信。 首先,我们需要引入...
——《Microsoft SQL Server 2005 技术内幕:T-SQL程序设计》、《Microsoft SQL Server 2005 技术内幕:T-SQL查询》、《Microsoft SQL Server 2005 技术内幕:查询、调整和优化》、《Microsoft SQL Server 2005 技术...
本文将详细讲解SQL Server数据库驱动以及如何创建有效的连接字符串,以帮助那些需要与SQL Server进行交互的开发者。 首先,SQL Server数据库驱动是允许应用程序与SQL Server进行通信的软件组件。主要有以下几种: ...
在SQL Server 2008中,将一列值转换为一个字符串是一个常见的需求,特别是在进行数据汇总或生成报告时。本篇文章将详细介绍如何利用SQL Server 2008中的功能来实现这一需求,并深入探讨背后的原理和技术要点。 ### ...
本文将深入探讨 SQL Server 的连接字符串编写方法及其身份验证机制,旨在帮助开发者更好地理解和掌握这些核心概念。 #### 二、连接字符串详解 连接字符串是用于指定应用程序如何连接到数据库的一组参数。对于 SQL ...
第2章 SQL Server 2005体系结构 2.1 SQL Server引擎组件 观测数据库引擎行为 协议 表格格式数据流(TDS)端点 关系引擎 存储引擎 SQLOS 2.2 内存 缓冲池和高速数据缓冲区 访问内存中...
VB连接SQL SERVER连接字符串,里面有几种写法,本人亲自测试过,非常好用。
Microsoft SQL Server 2005技术内幕: T-SQ程序设计 中文版本的 第一部分 第二部分地址:http://download.csdn.net/source/2680866
### SQL Server 2005 Express与速达的连接问题详解 #### 一、问题背景 在使用SQL Server 2005 Express时,如果遇到速达软件无法连接到数据库的情况,这通常是由多种因素导致的。根据描述,这里主要讨论的是安装了随...