SQLServer查詢多行轉換爲一行的方法

SQLServer查詢多行轉換爲一行的合併問題(FOR XML PATH應用)
以下主講sql多行轉爲一行的合併問題,並在sql2000和2005得到驗證
問題描述:將如下形式的數據按id字段合併value字段。
id    value
—– ——
1     aa
1     bb
2     aaa
2     bbb
2     ccc
需要得到結果:
id     value
—— ———–
1      aa,bb
2      aaa,bbb,ccc
即:group by id, 求 value 的和(字符串相加)

定義表:
create table tb(id int, value varchar(10))
insert into tb values(1, ‘aa’)
insert into tb values(1, ‘bb’)
insert into tb values(2, ‘aaa’)
insert into tb values(2, ‘bbb’)
insert into tb values(2, ‘ccc’)
go
一、sql2000中要用自定義的函數解決
create function dbo.f_str(@id int) returns varchar(100)
as
begin
    declare @str varchar(1000)
    set @str = ”
    select @str = @str + ‘,’ + cast(value as varchar) from tb where id = @id
    set @str = right(@str , len(@str) – 1)
    return @str
end
go
–調用函數
select id , value = dbo.f_str(id) from tb group by id
–drop function dbo.f_str
–drop table tb
二、sql2005中可以用FOR XML PATH語句來實現
大家都知道在SQL Server中利用 FOR XML PATH 語句能夠把查詢的數據生成XML數據,下面是它的一些應用示例。
DECLARE @TempTable table(UserID int , UserName nvarchar(50));
insert into @TempTable (UserID,UserName) values (1,’a')
insert into @TempTable (UserID,UserName) values (2,’b')
select UserID,UserName from @TempTable FOR XML PATH
運行這段腳本,將生成如下結果:
<row>
  <UserID>1</UserID>
  <UserName>a</UserName>
</row>
<row>
  <UserID>2</UserID>
  <UserName>b</UserName>
</row>
可以看到兩行數據生成了兩個節點,修改一下PATH的參數:
select UserID,UserName from @TempTable FOR XML PATH(‘test’)
運行上述腳本,將生成如下的結果:
<test>
  <UserID>1</UserID>
  <UserName>a</UserName>
</test>
<test>
  <UserID>2</UserID>
  <UserName>b</UserName>
</test>
其實PATH() 括號內的參數是控制節點名稱的,那如果是空字符串(不是沒有參數)會是什麼結果呢?
select UserID,UserName from @TempTable FOR XML PATH(”)
執行上面這段腳本將生成結果:
<UserID>1</UserID>
<UserName>a</UserName>
<UserID>2</UserID>
<UserName>b</UserName>
這樣就不顯示上級節點了,在PATH模式中,列名或列別名被作爲XPath表達式來處理,也就是說,是列的名字,試一下不給指定列名和別名會是怎麼樣?
select CAST(UserID AS varchar) + ”,UserName + ” from @TempTable FOR XML PATH(”)
運行上面這句將生成結果
1a2b
所有數據都生成一行,而且沒有連接字符,還可以再變化一下:
select CAST(UserID AS varchar) + ‘,’,UserName + ”,’;’ from @TempTable FOR XML PATH(”)
生成結果
1,a;2,b;
也就是說可以通過控制參數來生成自己想要的結果,例如:
select ‘{‘ + CAST(UserID AS varchar) + ‘,’,'”‘ +UserName + ‘”‘,’}’ from @TempTable FOR XML PATH(”)
生成結果
{1,”a”}{2,”b”}
還可以生成其他格式,大家可以根據自己需要的格式進行組合。
下面是一個數據統計的應用,希望大家可以通過下面的實例想到更多的應用
DECLARE @T1 table(UserID int , UserName nvarchar(50),CityName nvarchar(50));
insert into @T1 (UserID,UserName,CityName) values (1,’a',’上海’)
insert into @T1 (UserID,UserName,CityName) values (2,’b',’北京’)
insert into @T1 (UserID,UserName,CityName) values (3,’c',’上海’)
insert into @T1 (UserID,UserName,CityName) values (4,’d',’北京’)
insert into @T1 (UserID,UserName,CityName) values (5,’e',’上海’)
SELECT B.CityName,LEFT(UserList,LEN(UserList)-1) FROM (
SELECT CityName,
    (SELECT UserName+’,’ FROM @T1 WHERE CityName=A.CityName  FOR XML PATH(”)) AS UserList
FROM @T1 A
GROUP BY CityName
) B
生成結果(每個城市的用戶名)
北京 b,d
上海 a,c,e
回到上面的例子就是執行如下語句:
select id, [value] = stuff((select ‘,’ + [value] from tb t where id = tb.id for xml path(”)) , 1 , 1 , ”)
from tb
group by id
–drop table tb
(STUFF函數用法
1、作用:刪除指定長度的字符,並在指定的起點處插入另一組字符。
2、語法:STUFF ( character_expression , start , length ,character_expression )
3、示例:在第一個字符串abcdef中刪除從第2個位置(字符b)開始的3個字符,然後在刪除的起始位置插入第二個字符串ijklmn,從而創建並返回一個新字符串
SELECT STUFF(‘abcdef’, 2, 3, ‘ijklmn’)
GO
下面是結果集:aijklmnef
4、參數:character_expression,一個字符數據表達式。character_expression可以是常量、變量,也可以是字符列或二進制數據列。
start,一個整數值,指定刪除和插入的開始位置。如果start或length爲負,則返回空字符串。如果start比第一個character_expression長,則返回空字符串。start可以是bigint類型。
length,一個整數,指定要刪除的字符數。如果length比第一個character_expression長,則最多刪除到最後一個 character_expression中的最後一個字符。length可以是bigint類型。
5、返回類型:如果 character_expression 是受支持的字符數據類型,則返回字符數據。如果 character_expression 是一個受支持的 binary 數據類型,則返回二進制數據。
6、備註:如果結果值大於返回類型支持的最大值,則產生錯誤。)
三、使用遊標來合併數據,這個方法無版本限制
declare @t table(id int,value varchar(100))–定義結果集表變量
–定義遊標並進行合併處理
declare my_cursor cursor local for
select id, value from tb
declare @id_old int, @id int, @value varchar(10), @s varchar(100)
open my_cursor
fetch my_cursor into @id, @value
select @id_old = @id, @s=”
while @@FETCH_STATUS = 0
begin
    if @id = @id_old
       select @s = @s + ‘,’ + cast(@value as varchar)
    else
      begin
        insert @t values(@id_old , stuff(@s,1,1,”))
        select @s = ‘,’ + cast(@value as varchar) , @id_old = @id
      end
    fetch my_cursor into @id , @value
END
insert @t values(@id_old , stuff(@s,1,1,”))
close my_cursor
deallocate my_cursor

select * from @t
–drop table tb

這個一般常見用於數據統計,平常用的不多。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章