sql >> Database >  >> RDS >> Sqlserver

Hoe toetreden tot een tabel die meerdere waarden in de kolom heeft?

U zou moeten zien:"Arrays en lijsten in SQL Server 2005 en verder, When Table Waardeparameters Do Not Cut it" door Erland Sommarskog , dan zijn er veel manieren om strings in SQL Server te splitsen. Dit artikel behandelt de voor- en nadelen van zowat elke methode. in het algemeen moet u een split-functie maken. Zo kan een splitsingsfunctie worden gebruikt om rijen samen te voegen:

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

Ik geef de voorkeur aan de getallentabelbenadering om een ​​string in TSQL te splitsen maar er zijn talloze manieren om strings in SQL Server te splitsen, zie de vorige link, waarin de voor- en nadelen van elk worden uitgelegd.

Om de Numbers Table-methode te laten werken, moet u deze eenmalige tijdtabelconfiguratie uitvoeren, waardoor een tabel Numbers wordt gemaakt die rijen van 1 tot 10.000 bevat:

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)

Zodra de Numbers-tabel is ingesteld, maakt u deze splitsfunctie:

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 

U kunt nu eenvoudig een CSV-tekenreeks in een tabel splitsen en eraan deelnemen:

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

UITGANG:

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)

je kunt de XML-truc gebruiken om de rijen weer samen te voegen:

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

UITGANG:

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)

Dit geeft hetzelfde resultaat als hierboven, maar presteert mogelijk beter:

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. Is het in strijd met de licentie om de prestatietest van Oracle en SQL Server te publiceren?

  2. Upgraden naar PostgreSQL13

  3. geldige UUID is geen geldige UUID

  4. MySQL my.cnf-bestand - Gevonden optie zonder voorafgaande groep