Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sql-server-2005/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 如何连接到列中有多个值的表?_Sql Server_Sql Server 2005_Tsql - Fatal编程技术网

Sql server 如何连接到列中有多个值的表?

Sql server 如何连接到列中有多个值的表?,sql-server,sql-server-2005,tsql,Sql Server,Sql Server 2005,Tsql,我有一个person表,它包含一个错误代码字段,可以包含多个错误代码001、002、003。。。。我知道这是一个模式问题,但这是一个供应商应用程序,我无法控制模式,因此我必须使用现有的模式 还有一个错误表,其中包含错误代码char3和描述符char1000。在我的查询中,Person.ErrorCode与Error.ErrorCode相连,以获得相应描述的值 对于只有一个错误代码的个人记录,我可以毫无问题地获得相应的描述。我试图做的是,在存在多个错误的记录中,以某种方式计算描述符值 例如,以下是

我有一个person表,它包含一个错误代码字段,可以包含多个错误代码001、002、003。。。。我知道这是一个模式问题,但这是一个供应商应用程序,我无法控制模式,因此我必须使用现有的模式

还有一个错误表,其中包含错误代码char3和描述符char1000。在我的查询中,Person.ErrorCode与Error.ErrorCode相连,以获得相应描述的值

对于只有一个错误代码的个人记录,我可以毫无问题地获得相应的描述。我试图做的是,在存在多个错误的记录中,以某种方式计算描述符值

例如,以下是错误表中的一些示例数据:

ErrorCode     Descript
001           Problem with person file
002           Problem with address file
003           Problem with grade
以下是“我的选择对象”和“加入对象”错误导致的列:

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

感谢您的建议

通过将错误分组在一起并将它们连接在一起是一种选择:

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

通过将错误分组在一起并将它们连接在一起是一种选择:

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

在使用error.errorcode联接之前,取消person.errorcode的规范化


我不是指在表级别上反规范化,我是指使用视图或sql代码。

在连接之前使用error.errorcode反规范化person.errorcode

我不是指在表级别上进行非规范化,我是指使用视图或sql代码。

您应该看到:,那么在sql Server中有很多方法可以拆分字符串。本文介绍了几乎每种方法的优缺点。通常,您需要创建一个拆分函数。以下是使用拆分函数连接行的方式:

SELECT
    * 
    FROM dbo.yourSplitFunction(@Parameter) b
        INNER JOIN YourCodesTable          c ON b.ListValue=c.CodeValue
但是在SQLServer中有很多方法可以分割字符串,请参见前面的链接,其中解释了每种方法的优缺点

要使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)
设置数字表后,创建此拆分函数:

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 
输出:

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)
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)
您可以使用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
输出:

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)
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
您应该看到:,那么在SQL Server中有很多方法可以拆分字符串。本文介绍了几乎每种方法的优缺点。通常,您需要创建一个拆分函数。以下是使用拆分函数连接行的方式:

SELECT
    * 
    FROM dbo.yourSplitFunction(@Parameter) b
        INNER JOIN YourCodesTable          c ON b.ListValue=c.CodeValue
但是在SQLServer中有很多方法可以分割字符串,请参见前面的链接,其中解释了每种方法的优缺点

要使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)
设置数字表后,创建此拆分函数:

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 
输出:

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)
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)
您可以使用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
输出:

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)
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表是正常的:

;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。您需要将该null强制转换为与Person表中的ErrorCode一样宽的varchar列

您可以使用公共表表达式来假装Person表是正常的:

;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。您可能希望将该null强制转换为与Person表中的ErrorCode一样宽的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

连接错误描述可能不是一个好办法。它给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

SQL Server没有组\u CONCAT。组\u CONCAT不是SQL Server中的关键字。您可能认为MySQLSQL Server没有GROUP_CONCAT。GROUP_CONCAT不是SQL Server中的关键字。你可能会想到MySQLOP在问题中说的,我知道这是一个模式问题,但这是一个供应商应用程序,我对模式没有控制权,所以我必须使用我得到的。OP在问题中说,我知道这是一个模式问题,但 is是一个供应商应用程序,我对模式没有控制权,因此我必须使用现有的模式。