我有一个包含一个错误代码字段可以包含多个错误代码(001,002,003 ...)的人表。 我知道这是一个架构问题,但这是一个供应商的应用程序,我有超过架构无法控制,所以我有我有什么工作。
还存在包含错误码(炭(3))和一个DESCRIPT误差表(炭(1000))。 在我的查询Person.ErrorCode结合到Error.ErrorCode得到相应的说明的值。
对于人的记录,其中只有一个错误代码,我可以没有问题得到相应的DESCRIPT。 我想要做的就是以某种方式对的concat那里有多个错误记录的DESCRIPT值。
例如,这里是从错误中的示例数据:
ErrorCode Descript
001 Problem with person file
002 Problem with address file
003 Problem with grade
下面是我对人造成SELECT与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
建议表示赞赏!
您应该看到: “数组和列表在SQL Server 2005及以后,当表值参数不剪”的厄兰Sommarskog ,那么有很多方式在SQL Server中拆分字符串。 本文介绍了几乎每一个方法的优点和缺点。 在一般情况下,你需要创建一个分裂的功能。 这是一个分裂的功能如何被用于加入行:
SELECT
*
FROM dbo.yourSplitFunction(@Parameter) b
INNER JOIN YourCodesTable c ON b.ListValue=c.CodeValue
我更喜欢数字表方法将拆分TSQL字符串 ,但也有许多方法来拆分在SQL Server中的字符串,见前面的链接,这说明各的优点和缺点。
对于数字表的方法来工作,你需要做的这一次表的设置,这将创建一个表Numbers
包含行从1到10000:
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
非规范化person.errorcode前与error.errorcode加盟
我不是说非规范化桌子上的水平,我指的是一个视图或SQL代码。
您可以使用公用表表达式假装的人表是正常的:
;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在那里你会在你的原始查询已使用的人。 你要的是空宽转换为VARCHAR列错误代码的人表
拼接错误的描述可能不是要走的路。 它增加了不必要的复杂的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
通过分组错误一起,它们串联为一个选项:
SELECT *, GROUP_CONCAT(Person.ErrorCode) FROM Person
GROUP BY Person.RecID