2010-11-04 90 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 
相關問題