替换SQL Server中的逗号分隔值

时间:2014-12-02 11:53:26

标签: sql sql-server sql-server-2008 tsql

我有两个SQL表EmployeeMst和EmployeeCity

EmployeeMst
SrNo  Name 
1     abc
2     xyz
3     pqr
4     def

EmployeeCity
srno  City     EmplSrNo
1     Delhi    1,2,3,4
2     Mumbai   2,3,1
3     New York 3,2

我想从EmployeeMst获取具有选择查询的员工姓名

输出如下:

srno City          EmployeeName
1    Delhi         abc,xyz,pqr,def
2    Mumbai        xyz,pqr,abc
3    New York      pqr,xyz

此表中有几个数据。请告诉我如何才能这样做

我使用charindex,但需要更多时间。

3 个答案:

答案 0 :(得分:5)

我仍然认为无论桌子是旧的还是新的,你都应该花时间尽快修复糟糕的设计。你只是在推迟不可避免的事情。因此,这可以帮助您开始规范化设计:

-- CREATE CITY TABLE
CREATE TABLE dbo.City
(
    SrNo INT,
    City VARCHAR(50)
);

-- POPULATE FROM EXISTING TABLE
INSERT dbo.City (SrNo, City)
SELECT  SrNo, City
FROM    dbo.EmployeeCity;

-- CREATE CITY-EMPLOYEE JUNCTION TABLE USING EXISTING
-- DATA, AND XML METHOD TO SPLIT COMMA SEPARATED VALUES
-- INTO ROWS
CREATE TABLE dbo.EmployeeCity2 (CitySrNo, EmployeeSrNo)
SELECT  SrNo, i.value('.', 'INT')
FROM    (   SELECT  SrNo,
                    x = CONVERT(XML, '<i>' + 
                                REPLACE(EmplSrNo, ',', '</i><i>') + 
                                '</i>')
            FROM    dbo.EmployeeCity
        ) AS t
        CROSS APPLY t.x.nodes('i') rx (i);

-- DROP EXISTING TABLE SO THAT WE CAN CREATE A VIEW OF THE SAME NAME
DROP TABLE dbo.EmployeeCity;
GO

-- CREATE A VIEW THAT REPLICATES THE FORMAT OF THE CURRENT TABLE SO
-- THAT EXISTING SELECT QUERIES ARE NOT AFFECTED
CREATE VIEW dbo.EmployeeCity
AS
    SELECT  c.SrNo,
            c.City,
            EmplSrNo = STUFF((  SELECT  ',' + CAST(EmployeeSrNo AS VARCHAR(10))
                                FROM    dbo.EmployeeCity2 AS ec
                                WHERE   ec.CitySrNo = c.SrNo
                                FOR XML PATH(''), TYPE
                            ).value('.', 'VARCHAR(MAX)'), 1, 1, '')
    FROM    dbo.City AS c;
GO

-- FINALLY, THE QUERY YOU NEED TO GET THE OUTPUT IN THE QUESTION
SELECT  c.SrNo,
        c.City,
        EmployeeName = STUFF((  SELECT  ',' + m.Name
                                FROM    dbo.EmployeeCity2 AS ec
                                        INNER JOIN EmployeeMst AS m
                                            ON m.SrNo = ec.EmployeeSrNo
                                WHERE   ec.CitySrNo = c.SrNo
                                FOR XML PATH(''), TYPE
                            ).value('.', 'VARCHAR(MAX)'), 1, 1, '')
FROM    dbo.City AS c;

您仍然需要修改数据的插入/更新/删除方式,但是发生这种情况的位置应该比选择的位置少得多,并且视图会覆盖您现有的所有选择查询。

要进一步阅读上面使用的几个原则来分割逗号分隔的字符串,然后再将它重新组合在一起,请参阅:

答案 1 :(得分:2)

使用它。的 Fiddler Demo

  CREATE FUNCTION EmployeeName(@Expr1 AS VARCHAR(MAX))
    RETURNS VARCHAR(MAX)
    BEGIN
        DECLARE @res AS VARCHAR(MAX)

        SET @res =  (SELECT ',' + B.name AS A FROM 
            (SELECT
                 Split.a.value('.', 'VARCHAR(100)') AS CVS  
            FROM  
            (
                SELECT CAST ('<M>' + REPLACE(@Expr1, ',', '</M><M>') + '</M>' AS XML) AS CVS 
            ) AS A CROSS APPLY CVS.nodes ('/M') AS Split(a)) AS A

        INNER JOIN EmployeeMst AS B ON A.CVS = B.id 

        FOR XML PATH(''), TYPE).value('.', 'varchar(max)')

        RETURN STUFF(@res, 1,1,'')
    END 

SELECT srno, city, dbo.EmployeeName(EmplSrNo) AS EmployeeName FROM EmployeeCity

答案 2 :(得分:1)

[SQL Fiddle][1]
--------------------------------------------------------
--create temp table for using in split
IF OBJECT_ID('tempdb..#Tally') IS NOT NULL 
    DROP TABLE #Tally
CREATE TABLE #Tally ( N INT )
DECLARE @i AS INT = 1
WHILE @i != 1000 
    BEGIN
        INSERT  INTO #Tally
                ( N )
        VALUES  ( @i )
        SET @i = @i + 1
    END
--------------------------------------------------------
--Create temp table EmployeeMst
IF OBJECT_ID('tempdb..#EmployeeMst') IS NOT NULL 
    DROP TABLE #EmployeeMst
CREATE TABLE #EmployeeMst
    (
      SrNo INT ,
      EmpNo VARCHAR(10),
    )
INSERT  INTO #EmployeeMst
VALUES  ( 1, 'abc' ),
        ( 2, 'xyz' ),
        ( 3, 'pqr' ),
        ( 4, 'def' )
--------------------------------------------------------
--Create temp table EmployeeCity
IF OBJECT_ID('tempdb..#EmployeeCity') IS NOT NULL 
    DROP TABLE #EmployeeCity
CREATE TABLE #EmployeeCity
    (
      srno INT ,
      City VARCHAR(20) ,
      EmplSrNo VARCHAR(MAX)
    )
INSERT  INTO #EmployeeCity
VALUES  ( 1, 'Delhi', '1,2,3,4' ),
        ( 2, 'Mumbai', '2,3,1' ),
        ( 3, 'New York', '3,2' )
--------------------------------------------------------
--Get output as in example 
;
WITH    EmployeeCityUpdated
          AS ( SELECT   E.srno ,
                        E.City ,
                        CONVERT(INT, REPLACE(f4.EmpNoUpd, ',', '')) AS EmployeeName
               FROM     #EmployeeCity AS E
                        JOIN #Tally AS T ON SUBSTRING(',' + E.EmplSrNo, T.N, 1) = ','
                                            AND T.N < LEN(EmplSrNo) + 1
                        CROSS APPLY ( SELECT    string = SUBSTRING(' '
                                                              + EmplSrNo + ',',
                                                              T.N + 1,
                                                              LEN(EmplSrNo)
                                                              + 1)
                                    ) f1
                        CROSS APPLY ( SELECT    p1 = CHARINDEX(',', string)
                                    ) f2
                        CROSS APPLY ( SELECT    EmpNoUpd = SUBSTRING(EmplSrNo,
                                                              T.N, p1)
                                    ) f4
             )
    SELECT  EC.srno ,
            EC.City ,
            SUBSTRING(( SELECT  ',' + CONVERT(VARCHAR, EM.EmpNo)
                        FROM    EmployeeCityUpdated AS ECU
                                JOIN #EmployeeMst AS EM ON ECU.EmployeeName = EM.SrNo
                        WHERE   ECU.srno = EC.srno
                      FOR
                        XML PATH('')
                      ), 2, 1000) AS EmployeeName
    FROM    #EmployeeCity AS EC
--------------------------------------------------------
--srno City          EmployeeName
--1    Delhi         abc,xyz,pqr,def
--2    Mumbai        xyz,pqr,abc
--3    New York      pqr,xyz