我必须处理一个mssql数据库以及如下表所示的信息:
Users:
ID Name Countries
--------------------
1 User1 1,2,3
2 User2 2,5
Countries:
ID Country
----------
1 Australia
2 Germany
3 USA
4 Norway
5 Canada
现在,我正在寻找的是一个select语句,它会给我一个这样的结果:
Result:
ID User CountriesByName
-----------------------------
1 User1 Australia, Germany, USA
2 User2 Germany, Canada
我更喜欢一种不依赖特殊MSSQL语法的解决方案,但是我无法使用一些LINQ-magic :(
答案 0 :(得分:6)
首先,您需要拆分该字符串。这是一个可行的分割功能:
Create Function [dbo].[split]
(@input varChar(8000) -- List of delimited items
,@delimit varChar(8000) = ',') -- delimiter that separates items
Returns @List Table ([item] varChar(8000)) As
Begin
Declare @item VarChar(8000);
while charIndex(@delimit, @input, 0) <> 0 Begin
Select
@item = rTrim(lTrim(subString(@input, 1, charIndex(@delimit, @input, 0) - 1))),
@input = rTrim(lTrim(subString(@input, charIndex(@delimit, @input, 0) + Len(@delimit), Len(@input))));
If Len(@item) > 0 Insert Into @List Select @item
End
If Len(@input) > 0 Insert Into @List Select @input
Return;
End
然后,您需要将值加入到您的国家/地区表中,然后重新加入它们。这将帮助您完成大部分工作:
Select ID
,[Name] as [User]
,(
Select [country] + ', '
From [Countries]
Where [ID] In (
Select Cast([item] As Integer)
From dbo.split(U.Countries, ',')
Where IsNumeric(item) = 1)
Order By [country]
For XML Path('')) As [CountriesByName]
From [Users] As U
然而,这留下了一个逗号。您可能希望在其他某个层上删除它,但为了防止您必须在SQL中执行此操作,这应该有效:
Select ID
,[User]
,Left([CountriesByName], Len([CountriesByName]) - 1) As [CountriesByName]
From (
Select ID
,[Name] as [User]
,(
Select [country] + ', '
From [Countries]
Where [ID] In (
Select Cast([item] As Integer)
From dbo.split(U.Countries, ',')
Where IsNumeric(item) = 1)
Order By [country]
For XML Path('')) As [CountriesByName]
From [Users] As U) As [Results]
答案 1 :(得分:1)
尝试Common Table Expression查询。 Simple-Talk有一个非常好的walkthrough,它解释了SQL流行的不同方法,并提供了使用CTE的示例(查找WITH语句)。
答案 2 :(得分:0)
如果您将数据规范化为三个表,则以下内容适用于您要执行的操作。这是使用我自己的架构,因为我必须敲一些表来测试它。)
Select
UserId, UserName,
(
Select
CountryName + ','
From
Country As C
Inner Join
UserCountry As UC
On C.CountryId = UC.CountryId
Where
UC.UserId = [User].UserId
ORDER BY
CountryName
FOR XML PATH('')
) As Countries
从 [用户];
答案 3 :(得分:0)
首先,我将创建一个存储过程,该过程采用一串国家/地区ID并使用动态sql返回国家/地区名称列表。
create proc dbo.getCoutries(@ids nvarchar(200))
as
begin
declare @sql nvarchar(200)
set @sql = 'select @countries = @countries + Country+
'', '' from Countries where ID in ('+@ids+')'
declare @countries nvarchar(200)
set @countries = ''
DECLARE @ParmDefinition nvarchar(500);
SET @ParmDefinition = N'@countries nvarchar(200) OUTPUT';
EXECUTE sp_executesql @sql,
@ParmDefinition,
@countries=@countries OUTPUT;
select substring(@countries,1,len(@countries)-1) Countries
end
go
所以现在exec getCoutries'2,5'返回“德国,加拿大”。 一旦完成,我们现在需要运行下面的代码 返回看起来像的表:
Name Countries
User1 Australia, Germany, USA
User2 Germany, Canada
--The variable we will use to loop thru the user ids
declare @userId int
set @userId = 0
-- hold the string of country ids
declare @countryIds varchar(30)
-- a temp table that we will populate
-- it will have the users ID and then the
-- string of countries (i.e "Germany, Canada")
declare @results as
table
(userId int,
countries varchar(200))
--Loop thru each row in the Users table.
while 1=1
begin
select @userId=min(ID)
from Users
where ID > @userId
if @userId is null
break
--get the string of country ids for this user
select @countryIds=Countries
from Users
where ID = @userId
--use our stored proc to bring back the string of names
insert into @results
(countries)
exec getCoutries @countryIds
--update the userId for our new row
update @results
set UserId = @UserId
where UserId is null
end
-- return the user and his list of countries
select u.Name, r.Countries
from Users u
inner join @results r
on u.ID = r.UserId
GO