SQL为一组id选择连接字符串

时间:2009-07-15 14:16:53

标签: sql sql-server select join

我必须处理一个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 :(

4 个答案:

答案 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