拆解组装SQL字符串全过程

本文介绍了一个复杂的SQL查询案例,该查询通过多个步骤将购买者的需求从数字ID转换为实际商品名称,并最终呈现为易于阅读的格式。文章详细解释了如何使用SQL Server 2005的CTE表达式和其他高级功能完成这一过程。

先看下面这段代码, 它将sql字符串先分割为行集,做一定处理后再合并为单行:

use tempdb
go

if ( object_id ( 't_Item' ) is not null ) drop table t_item
go
if ( object_id ( 't_Buy' ) is not null ) drop table t_Buy
go
create table t_Item ( Item_ID int , Item_Name varchar ( 10 ))
insert into t_Item select 1 , '面包' union select 2 , '衣服' union select 3 , '鞋子'
create table t_Buy ( Person varchar ( 10 ), WantBuy varchar ( 10 ))
insert into t_Buy select '小张' , '1,2' union select '小王' , '1,2,3'

go
/*原始表数据
Person WantBuy
---------- ----------
小张 1,2
小王 1,2,3
*/

/*要求查询结果
Person WantBuy
---------- -----------------
小王 面包,衣服,鞋子
小张 面包,衣服
*/

select Person , WantBuy = cast ( replace ( WantBuy , '</v><v>' , ',' ) as xml ). value ( '.' , 'varchar(max)' )
from ( select distinct Person from t_Buy ) ta outer apply (
select WantBuy = ( select WantBuy as v from
(
select Person , c . Item_Name as WantBuy from (
select Person , convert ( xml , '<v>' + replace ( WantBuy , ',' , '</v><v>' ) + '</v>' ) as WantBuy
from t_Buy ) a outer apply
(
select t . c . value ( '.' , 'varchar(max)' ) AS WantBuy from a . WantBuy . nodes ( '//v' ) AS t ( c )
)b inner join t_Item c on b . wantbuy = c . item_id
) d where person = ta . person for xml path ( '' ))
) tb

如果这段代码对于你来说是小case 那你就可以忽略此文,去论坛灌水去了。如果你还不了解他的工作原理,请继续耐心看完下面的分解过程。你需要单独理解以下内容:

SQL CTE(Common Table Expressions:公共表达式)

http://msdn.microsoft.com/zh-cn/library/ms190766.aspx

apply 关键字的用法

http://msdn.microsoft.com/zh-cn/library/ms175156.aspx

XQuery查询

http://blog.youkuaiyun.com/jinjazz/archive/2009/08/13/4443585.aspx

For XML子句

http://msdn.microsoft.com/zh-cn/library/ms190922.aspx

下面把上述语句分解为五个步骤,最后一个步骤就是最后需要的结果。

use tempdb
go

if ( object_id ( 't_Item' ) is not null ) drop table t_item
go
if ( object_id ( 't_Buy' ) is not null ) drop table t_Buy
go
create table t_Item ( Item_ID int , Item_Name varchar ( 10 ))
insert into t_Item select 1 , '面包' union select 2 , '衣服' union select 3 , '鞋子'
create table t_Buy ( Person varchar ( 10 ), WantBuy varchar ( 10 ))
insert into t_Buy select '小张' , '1,2' union select '小王' , '1,2,3'

go

/*第一步把WantBuy转为xml
Person WantBuy
---------- ----------------------------
小张 <v>1</v><v>2</v>
小王 <v>1</v><v>2</v><v>3</v>
*/

; with t1 as
(
select Person , convert ( xml , '<v>' + replace ( a . WantBuy , ',' , '</v><v>' ) + '</v>' ) as WantBuy
from t_Buy a
)


/*第二步把WantBuy字段拆分为多行
Person WantBuy
---------- --------
小张 1
小张 2
小王 1
小王 2
小王 3
*/
, t2 as
(
select a . Person , b . WantBuy from t1 a outer apply
(
select t . c . value ( '.' , 'varchar(max)' ) AS WantBuy from a . WantBuy . nodes ( '//v' ) AS t ( c )
)b
)
/*第三步把WantBuy字段转为物品的名称
person item_name
---------- ----------
小张 面包
小张 衣服
小王 面包
小王 衣服
小王 鞋子
*/
, t3 as
(
select a . person , b . item_name from t2 a inner join t_Item b on a . wantbuy = b . item_id
)
/*第四步把WantBuy字段按照人名来聚合
Person WantBuy
---------- ------------------------------------
小王 <v>面包</v><v>衣服</v><v>鞋子</v>
小张 <v>面包</v><v>衣服</v>
*/
, t4 as
(
select * from ( select distinct Person from t_Buy ) a outer apply
(
select WantBuy = ( select Item_Name as v from t3 where person = a . person for xml path ( '' ))
)b
)

/*第五步把XML字段转为逗号分割的普通字段
Person WantBuy
---------- -----------------
小王 面包,衣服,鞋子
小张 面包,衣服
*/
, t5 as
(
select Person , WantBuy = cast ( replace ( WantBuy , '</v><v>' , ',' ) as xml ). value ( '.' , 'varchar(max)' ) from t4
)
select * from t5

我们这里不得不夸奖一下SQLServer2005的CTE表达式,它可以把很复杂的嵌套查询分解为简单的多步查询。

不同编程语言有不同的拆解字符串的方法,以下为你介绍一些常见的方法: ### Python Python 可以使用`split()`方法进行字符串的拆分,该方法可以指定分隔符。示例如下: ```python s = 'John,Doe,john.doe@example.com,(408)-999-1111' contact = s.split(',') print(contact) ``` 上述代码使用逗号作为分隔符执行字符串的拆分[^1]。 ### C 语言 C 语言可以使用`strsep()`函数进行字符串分割。函数执行的过程,是在`*stringp`中查找分割符,并将其替换为`\0`,返回分割出的第一个字符串指针 (`NULL`表示到达字符串尾),并更新`*stringp`指向下一个字符串。示例如下: ```c #include <stdio.h> #include <string.h> int main(void) { char str[80] = "This is , hello world ,, test"; char *temp = str; char s[2] = ","; char *res; while(res = strsep(&temp, s)) { printf("%s\n", res); } return 0; } ``` 运行结果: ``` This is hello world test ``` ### C++ C++ 可以通过`find()`和`substr()`方法结合进行字符串拆解。示例如下: ```cpp #include <iostream> #include <string> #include <vector> void test1() { std::string str = "www.beijing.com.cn"; std::vector<std::string> v; int start = 0; int pos = -1; while (true) { pos = str.find(".", start); if (pos==-1) { //将cn截取出来 std::string tempStr = str.substr(start, str.size() - start); v.push_back(tempStr); break; } std::string tempStr = str.substr(start, pos - start); v.push_back(tempStr); start = pos + 1; } for (std::vector<std::string>::iterator it = v.begin(); it != v.end(); it++) { std::cout << *it << std::endl; } } ``` ### PHP PHP 中使用`str_split()`函数拆分中英文混合的字符串可能会出现乱码问题,对于特定编码(如 gb2312),可以找到相应的正确拆分函数,其他编码的字符串需要先转换编码[^2]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值