在SQL中,我可以转换为“|”将ID列表分隔为其值列表?

时间:2009-10-30 20:50:41

标签: sql sql-server tsql

以状态为例,我当前的数据看起来像

StateAbbrev  | NumOfResults
-----------    ------------
MD           | 5
VA           | 2
DC           | 7
MD|VA        | 2
CA|NY|VA     | 1

我希望输出以下内容

StateName                    | NumOfResults
---------                      ------------
Maryland                     | 5
Virginia                     | 2
District of Columbia         | 7
Maryland,Virginia            | 2
California,New York,Virginia | 1

我有一个可以将StateAbbrev映射到StateName

的表

我可以创建一个函数,如果管道分隔的ID并且吐出逗号分隔的列表,只会取列表,但我有超过1个表与此场景,所以我正在寻找一个更清洁的解决方案。 谢谢!

4 个答案:

答案 0 :(得分:1)

我使用以下UDF来处理拆分(通过4guysfromrolla

set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[Split]
(
    @List nvarchar(2000),
    @SplitOn nvarchar(5)
)  
RETURNS @RtnValue table 
(       
    Id int identity(1,1),
    Value nvarchar(100)
) 
AS  
BEGIN
    While (Charindex(@SplitOn,@List)>0)
    Begin 
        Insert Into @RtnValue (value)
        Select
            Value = ltrim(rtrim(Substring(@List,1,Charindex(@SplitOn,@List)-1))) 
        Set @List = Substring(@List,Charindex(@SplitOn,@List)+len(@SplitOn),len(@List))
    End 

    Insert Into @RtnValue (Value)
    Select Value = ltrim(rtrim(@List))

    Return
END

以下是如何使用UDF的示例:

select [Value] from [dbo].Split('CA|NY|VA', '|')

哪个会返回一个包含3行的表,每个状态一个。

更新:

以下是完成第一次翻译的完整调用:

declare @cslist varchar(2056)
select @cslist = coalesce(@cslist+',', '') + translated_states.full_state
FROM (

    select T2.full_state from [dbo].Split('CA|NY|VA', '|') as T1
    JOIN test as T2
    on T2.abbr_state = T1.[Value]

) translated_states
select @cslist

如果您对需要更新的内容有任何疑问,请与我联系,以使其适用于您的表而不是我的测试表。

答案 1 :(得分:0)

您可以编写C#函数,然后使用SQLCLR执行此操作:http://msdn.microsoft.com/en-us/library/ms345136%28SQL.90%29.aspx

或者您可以编写一个T-SQL函数来执行此操作。

答案 2 :(得分:0)

我想出了以下内容,但我不得不使用临时表来完成它;由于某种原因,子查询不适用于SUBSTRING。

DECLARE @T TABLE ( col VARCHAR(1000) )

INSERT  INTO @T
        ( col 
        )
        SELECT  'MD'
        UNION ALL
        SELECT  'MD|CA'
        UNION ALL
        SELECT  'MD|CA|VA'

DECLARE @states TABLE
    (
      abbr VARCHAR(2) ,
      StateName VARCHAR(10)
    )

INSERT  INTO @states
        SELECT  'MD' ,
                'Maryland'
        UNION ALL
        SELECT  'CA' ,
                'California'
        UNION ALL
        SELECT  'VA' ,
                'Virginia'



SELECT  col ,
        word = SUBSTRING('|' + col + '|', Number + 1,
                         CHARINDEX('|', '|' + col + '|', Number + 1) - Number
                         - 1) ,
        Number
INTO    #tmp
FROM    ( SELECT /*use a table of numbers if you have one instead of this subquery*/
                    ROW_NUMBER() OVER ( ORDER BY ( ac1.Object_ID ) ) AS Number
          FROM      Master.sys.columns ac1
        ) Numbers
        CROSS APPLY @t t
WHERE   Number >= 1
        AND Number < LEN('|' + col + '|') - 1
        AND SUBSTRING('|' + col + '|', Number, 1) = '|'
ORDER BY col ,
        Number

SELECT  t1.col ,
        StateName = REPLACE(( SELECT    StateName AS [data()]
                              FROM      #tmp t
                                        JOIN @states s ON t.word = s.abbr
                              WHERE     t1.col = t.col
                              ORDER BY  COL ,
                                        Number
                            FOR
                              XML PATH('')
                            ), ' ', '|')
FROM    #tmp t1



DROP TABLE #tmp

答案 3 :(得分:0)

这是一个非UDF解决方案,它使用Numbers表,XML和CROSS APPLY(两次):

DECLARE @Numbers TABLE (Num INT);

INSERT INTO @Numbers VALUES (1);
INSERT INTO @Numbers VALUES (2);
INSERT INTO @Numbers VALUES (3);
INSERT INTO @Numbers VALUES (4);
INSERT INTO @Numbers VALUES (5);
INSERT INTO @Numbers VALUES (6);
INSERT INTO @Numbers VALUES (7);
INSERT INTO @Numbers VALUES (8);
INSERT INTO @Numbers VALUES (9);

DECLARE @Results TABLE (StateAbbrevs VARCHAR(255), NumOfResults INT);

INSERT INTO @Results VALUES ('MD', 5);
INSERT INTO @Results VALUES ('VA', 2);
INSERT INTO @Results VALUES ('DC', 7);
INSERT INTO @Results VALUES ('MD|VA', 2);
INSERT INTO @Results VALUES ('CA|NY|VA', 1);

DECLARE @Abbrev TABLE (StateAbbrev VARCHAR(2), StateName VARCHAR(255));

INSERT INTO @Abbrev VALUES ('MD', 'Maryland');
INSERT INTO @Abbrev VALUES ('VA', 'Virginia');
INSERT INTO @Abbrev VALUES ('DC', 'District of Columbia');
INSERT INTO @Abbrev VALUES ('CA', 'California');
INSERT INTO @Abbrev VALUES ('NY', 'New York');

--SELECT * FROM @Results;
--
--SELECT * FROM @Abbrev;

SELECT  STUFF(StateNames, 1, 1, '') AS StateNames,
        NumOfResults
FROM    @Results AS RESULTS0
        CROSS APPLY ( SELECT    ',' + ABBREV.StateName
                      FROM      ( SELECT    PVT.StateAbbrev,
                                            RESULTS.StateAbbrevs
                                  FROM      @Results AS RESULTS
                                            CROSS APPLY ( SELECT    SUBSTRING(RESULTS.StateAbbrevs, NUMBERS.Num, CHARINDEX('|', RESULTS.StateAbbrevs + '|', NUMBERS.Num) - NUMBERS.Num) AS StateAbbrev
                                                          FROM      @Numbers AS NUMBERS
                                                          WHERE     NUMBERS.Num <= LEN(RESULTS.StateAbbrevs)
                                                                    AND SUBSTRING('|' + RESULTS.StateAbbrevs, NUMBERS.Num, 1) = '|'
                                                        ) AS PVT
                                ) AS X
                                LEFT JOIN @Abbrev AS ABBREV ON ABBREV.StateAbbrev = X.StateAbbrev
                      WHERE     StateAbbrevs = RESULTS0.StateAbbrevs
                    FOR
                      XML PATH('')
                    ) AS Y ( StateNames )