2010-11-04 43 views
1

我有一个人员表,其中包含一个错误代码字段,可以包含多个错误代码(001,002,003 ...)。我知道这是一个架构问题,但是这是一个供应商应用程序,我无法控制架构,所以我必须处理我所拥有的。如何加入列中具有多个值的表格?

还有一个包含ErrorCode(char(3))和Descript(char(1000))的错误表。在我的查询中,Person.ErrorCode被加入到Error.ErrorCode中以获取相应描述的值。

对于只有一个错误代码的人员记录,我可以毫无问题地得到相应的描述。我想要做的是以某种方式将Descript值连接为存在多个错误的记录。

例如,这里是从错误中的示例数据:

ErrorCode  Descript 
001   Problem with person file 
002   Problem with address file 
003   Problem with grade 

下面是我的个人选择产生与错误使用JOIN列:

Person.RecID Person.ErrorCode Error.Descript 
12345   001    Problem with person file 
12346   003    Problem with grade 
12347   002,003 

我试图得到的是这样的:

Person.RecID Person.ErrorCode Error.Descript 
12345   001    Problem with person file 
12346   003    Problem with grade 
12347   002,003   Problem with address file, Problem with grade 

建议感激!

回答

-2

通过分组错误一起,它们串联为一个选项:与error.errorcode

在连接前

SELECT *, GROUP_CONCAT(Person.ErrorCode) FROM Person 
GROUP BY Person.RecID 
+1

SQL Server没有GROUP_CONCAT。 – 2010-11-04 15:27:16

+1

GROUP_CONCAT不是SQL Server中的关键字。你可能会想到MySQL(?) – 2010-11-04 15:27:58

1

去正规化person.errorcode我不是说非规范化桌子上的水平,我意味着一个视图或sql代码。

+1

OP在问题中说:“我知道这是一个模式问题,但这是一个供应商应用程序,我无法控制模式,所以我必须使用我的工作。 ' – 2010-11-04 16:29:03

5

您应该看到:"Arrays and Lists in SQL Server 2005 and Beyond, When Table Value Parameters Do Not Cut it" by Erland Sommarskog,然后有很多方法可以在SQL Server中拆分字符串。本文涵盖了几乎所有方法的PRO和CON。一般来说,你需要创建一个分割函数。这是一个分裂的功能如何被用于加入行:

SELECT 
    * 
    FROM dbo.yourSplitFunction(@Parameter) b 
     INNER JOIN YourCodesTable   c ON b.ListValue=c.CodeValue 

I prefer the number table approach to split a string in TSQL但也有许多方法来拆分在SQL Server中的字符串,见前面的链接,这说明各的优点和缺点。

对于数字表的方法来工作,你需要做的这一次表的设置,这将创建一个包含从1到10000行的表Numbers

SELECT TOP 10000 IDENTITY(int,1,1) AS Number 
    INTO Numbers 
    FROM sys.objects s1 
    CROSS JOIN sys.objects s2 
ALTER TABLE Numbers ADD CONSTRAINT PK_Numbers PRIMARY KEY CLUSTERED (Number) 

一旦Numbers表格设置,创建此分割功能:

CREATE FUNCTION [dbo].[FN_ListToTable] 
(
    @SplitOn char(1)  --REQUIRED, the character to split the @List string on 
    ,@List  varchar(8000)--REQUIRED, the list to split apart 
) 
RETURNS TABLE 
AS 
RETURN 
(

    ---------------- 
    --SINGLE QUERY-- --this will not return empty rows 
    ---------------- 
    SELECT 
     ListValue 
     FROM (SELECT 
        LTRIM(RTRIM(SUBSTRING(List2, number+1, CHARINDEX(@SplitOn, List2, number+1)-number - 1))) AS ListValue 
        FROM (
          SELECT @SplitOn + @List + @SplitOn AS List2 
         ) AS dt 
         INNER JOIN Numbers n ON n.Number < LEN(dt.List2) 
        WHERE SUBSTRING(List2, number, 1) = @SplitOn 
      ) dt2 
     WHERE ListValue IS NOT NULL AND ListValue!='' 

); 
GO 

您现在可以轻松地拆分CSV字符串转换成表格,并加入就可以了:

DECLARE @ErrorCode table (ErrorCode varchar(20), Description varchar(30)) 
INSERT @ErrorCode VALUES ('001','Problem with person file') 
INSERT @ErrorCode VALUES ('002','Problem with address file') 
INSERT @ErrorCode VALUES ('003','Problem with grade') 

DECLARE @Person table (RecID int, ErrorCode varchar(20)) 
INSERT @Person VALUES (12345 ,'001' ) 
INSERT @Person VALUES (12346 ,'003' ) 
INSERT @Person VALUES (12347 ,'002,003') 


SELECT 
    p.RecID,c.ListValue,e.Description 
    FROM @Person          p 
     CROSS APPLY dbo.FN_ListToTable(',',p.ErrorCode) c 
     INNER JOIN @ErrorCode       e ON c.ListValue=e.ErrorCode 

OUTPUT:

RecID  ListValue  Description    
----------- ------------- ------------------------- 
12345  001   Problem with person file 
12346  003   Problem with grade  
12347  002   Problem with address file 
12347  003   Problem with grade  

(4 row(s) affected) 

可以使用XML招行串连到一起:

SELECT 
    t1.RecID,t1.ErrorCode 
     ,STUFF(
        (SELECT 
         ', ' + e.Description 
         FROM @Person          p 
          CROSS APPLY dbo.FN_ListToTable(',',p.ErrorCode) c 
          INNER JOIN @ErrorCode       e ON c.ListValue=e.ErrorCode 
         WHERE t1.RecID=p.RecID 
         ORDER BY p.ErrorCode 
         FOR XML PATH(''), TYPE 
        ).value('.','varchar(max)') 
        ,1,2, '' 
      ) AS ChildValues 
    FROM @Person t1 
    GROUP BY t1.RecID,t1.ErrorCode 

OUTPUT:

RecID  ErrorCode   ChildValues 
----------- -------------------- ----------------------------------------------- 
12345  001     Problem with person file 
12346  003     Problem with grade 
12347  002,003    Problem with address file, Problem with grade 

(3 row(s) affected) 

这将返回相同的结果如上设置,但可能表现更好:

SELECT 
    t1.RecID,t1.ErrorCode 
     ,STUFF(
        (SELECT 
         ', ' + e.Description 
         FROM (SELECT ListValue FROM dbo.FN_ListToTable(',',t1.ErrorCode)) c 
          INNER JOIN @ErrorCode e ON c.ListValue=e.ErrorCode 
         ORDER BY c.ListValue 
         FOR XML PATH(''), TYPE 
        ).value('.','varchar(max)') 
        ,1,2, '' 
      ) AS ChildValues 
    FROM @Person t1 
    GROUP BY t1.RecID,t1.ErrorCode 
+1

+1非常彻底。 – 2010-11-04 15:43:20

+0

非常有条不紊的做法。 +1 – 2010-11-04 16:04:55

0

您可以使用公用表表达式假装的人表是否正常:

;WITH PersonPrime as (
    SELECT RecID,ErrorCode,CAST(null as varchar(100)) as Remain from Person where Value not like '%,%' 
    UNION ALL 
    SELECT RecID,SUBSTRING(ErrorCode,1,CHARINDEX(',',ErrorCode)-1),SUBSTRING(ErrorCode,CHARINDEX(',',ErrorCode)+1,100) from Person where Value like '%,%' 
    UNION ALL 
    SELECT RecID,Remain,null FROM PersonPrime where Remain not like '%,%' 
    UNION ALL 
    SELECT RecID,SUBSTRING(Remain,1,CHARINDEX(',',Remain)-1),SUBSTRING(Remain,CHARINDEX(',',Remain)+1,100) from PersonPrime where Remain like '%,%' 
) 
SELECT RecID,ErrorCode from PersonPrime 

而现在使用PersonPrime在那里你会在你的原始查询已使用的人。您需要对与Person表中的ErrorCode一样宽的varchar列进行CAST验证。

0

将错误说明连接起来可能不是一种好的方法。它增加了SQL语句中不必要的复杂性,这对于调试来说是非常有问题的。今后任何对SQL的添加或更改也将很困难。最好的办法是生成一个标准化的结果集,即使你的模式不是。

SELECT Person.RecID, Person.ErrorCode, Error.ErrorCode, Error.Descript 
    FROM Person INNER JOIN Error 
    ON REPLACE(Person.ErrorCode, ' ', '') LIKE '%,' + CONVERT(VARCHAR,Error.ErrorCode) + ',%' 

如果一个人有多个错误代码集,那么这将为指定的每个错误返回一行(忽略重复项)。用你的例子,它会返回这个。

Person.RecID Person.ErrorCode Error.ErrorCode Error.Descript 
12345   001    001    Problem with person file 
12346   003    003    Problem with grade 
12347   002,003   002    Problem with address file 
12347   002,003   003    Problem with grade 
相关问题