0

Ich habe mehrere Tabellen mit derselben Struktur, die jeweils einen anderen Kunden repräsentieren. In jeder dieser Tabellen gibt es mehrere Spalten mit verschiedenen Strings von Daten, bei denen die Werte durch ein Leerzeichen getrennt sind, etwa so:So analysieren Sie Werte aus einer SQL-Spalte in einer Schleife mit einer gespeicherten Prozedur

Domain_Name | Account_ID | SiteID | Account_Name | BotExceptions | BlockCountries | BlockedURLs |BlockedIPs 
www.Domain1.com | 123456 |987654 | account1 | TR Sites24x7 Tools/ | UK FR IR| www.url1.com/someRsc www.url2.com/someRsc|46.218.22.145 64.129.104.70 92.44.168.111 
www.Domain2.com | 345678|321098| account2 | TR Sites24x7 Tools/ | ES GR AX BE| www.url1.com/someRsc www.url2.com/someRsc|46.218.22.145 64.129.104.70 92.44.168.111 

So in jeder Spalte alle Elemente (IPs/Bot Namen/Länder/URLs) werden zu einer einzelnen Zeichenfolge verkettet, die durch einen einzelnen Leerraum begrenzt ist. Zum Beispiel "TR Sites24x7 Tools /" ist eigentlich "TR", "Sites24x7" und "Tools /". Ich bin auf der Suche nach einem Weg, um eine gespeicherte Prozedur erstellen und mithilfe von SQL/Tsql, die Zeichenfolge in jeder Spalte analysieren und die Elemente in Zeilen ähnlich dem Platz:

Domain_Name | Account_ID | SiteID | Account_Name | BotExceptions | BlockCountries | BlockedURLs |BlockedIPs 
www.Domain1.com| 123456 | 987654 | account1  | TR   | UK    | www.url1.com/someRsc  | 46.218.22.145 
www.Domain1.com| 123456 | 987654 | account1  | Sites24x7  | FR    | www.url2.com/someRsc  | 64.129.104.70 

Mit anderen Worten stellen die einzelnen Werte in einer Reihe für sich, während die ersten 4 Spalten in der gesamten Tabelle statisch bleiben. Da die Daten bereits in Tabellen in der SQL Server 2012 DB enthalten sind, dachte ich mir, dass es einfacher wäre, einen SP oder eine Funktion zu haben, die dieses Parsen durchführen würde, aber ich bin mit dieser Sprache nicht sehr vertraut und könnte etwas Hilfe gebrauchen. Vielen Dank.

+0

Dies ist ein schreckliches Design. Erstens, ** Niemals ** halte mehrere Werte in einer einzelnen Spalte, und zweitens, Es gibt fast nie eine Rechtfertigung, mehrere Tabellen mit derselben Struktur und derselben Bedeutung zu behalten. Ihr Zieldesign ist auch nicht gut. Der richtige Entwurf wäre das Hinzufügen einer Tabelle für jede Spalte, in der Sie derzeit mehrere Werte haben, die einen Schlüssel für die Ersetzung der primären Tabelle und einen einzelnen Wert enthalten. Vereinheitlichen Sie auch die verschiedenen Kunden-Tabellen in einer einzigen Tabelle. –

+0

Ich stimme @ZoharPeled zu, aber ich hoffe, dass ein Teil des Grundes, dass Sie das fragen, ist, weil Sie versuchen, die Daten ein wenig zu normalisieren. Es ist wirklich ziemlich schrecklich ... – 3BK

+0

Ich stimme zu, dass das ursprüngliche Tischdesign weniger als optimal ist. Es ist das Ergebnis eines externen Skripts, das ich nicht kontrollieren kann, daher sind diese Rohdaten standardmäßig in der Struktur, die ich oben gezeigt habe. Es kann sich lohnen, mein Zieldesign nach dem Parsen in mehrere Tabellen zu ändern, jede für eine der Spalten in den ursprünglichen Tabellen. – ArielH

Antwort

1

Erstellen und füllen Beispieltabelle (Bitte speichern uns diesen Schritt in Ihrer zukünftigen Fragen)

DECLARE @T AS TABLE 
(
    Domain_Name varchar(200), -- or whatever length suits your needs 
    Account_ID int, 
    SiteID int, 
    Account_Name varchar(200),  
    BotExceptions varchar(200), 
    BlockCountries varchar(200) 
) 

INSERT INTO @T VALUES 
('www.Domain1.com', 123456, 987654, 'account1', 'TR Sites24x7 Tools/', 'UK FR IR'), 
('www.Domain2.com', 21478, 987654, 'account1', 'TR Sites24x7 Tools/', 'USA IT FR') 

Hier ist, wie ich die Zieltabellen

CREATE TABLE DomainAccounts 
(
    Id int identity(1,1), 
    Domain_Name varchar(200), -- or whatever length suits your needs 
    Account_ID int, 
    SiteID int, 
    Account_Name varchar(200),-- or whatever length suits your needs 
    CONSTRAINT PK_DomainAccounts PRIMARY KEY (Id) 
) 

CREATE TABLE BotExceptions 
(
    DomainAccounts_Id int, 
    BotName varchar(200), -- or whatever length suits your needs 
    CONSTRAINT FK_BotExceptions_DomainAccounts FOREIGN KEY (DomainAccounts_Id) REFERENCES DomainAccounts(Id) 
) 

CREATE TABLE BlockCountries 
(
    DomainAccounts_Id int, 
    CountryName varchar(200), -- or whatever length suits your needs 
    CONSTRAINT FK_BlockCountries_DomainAccounts FOREIGN KEY (DomainAccounts_Id) REFERENCES DomainAccounts(Id) 
) 

auch schaffen würde, Erstellen Sie 2 weitere Tabellen auf die gleiche Weise - BlockedURLs und BlockedIPs

Dann erstellen Sie eine String Splitting-Funktion. Ich habe eine Funktion basierend auf Jeff Modens Splitter aus Aaron Bertrands S plit strings the right way – or the next best way verwendet. Fühlen Sie sich frei, einen anderen zu verwenden.

CREATE FUNCTION dbo.SplitStrings 
(
    @List NVARCHAR(MAX), 
    @Delimiter NVARCHAR(255) 
) 
RETURNS TABLE 
WITH SCHEMABINDING AS 
RETURN 
    WITH E1(N)  AS (SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 
         UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 
         UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1), 
     E2(N)  AS (SELECT 1 FROM E1 a, E1 b), 
     E4(N)  AS (SELECT 1 FROM E2 a, E2 b), 
     E42(N)  AS (SELECT 1 FROM E4 a, E2 b), 
     cteTally(N) AS (SELECT 0 UNION ALL SELECT TOP (DATALENGTH(ISNULL(@List,1))) 
         ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E42), 
     cteStart(N1) AS (SELECT t.N+1 FROM cteTally t 
         WHERE (SUBSTRING(@List,t.N,1) = @Delimiter OR t.N = 0)) 
    SELECT Item = SUBSTRING(@List, s.N1, ISNULL(NULLIF(CHARINDEX(@Delimiter,@List,s.N1),0)-s.N1,8000)) 
    FROM cteStart s; 

Schließlich, Legen Sie die Datensätze aus der Quelltabelle in die Zieltabellen:

0

Sie eine Funktion wie diese verwenden:

CREATE FUNCTION [dbo].[UDF_StringDelimiter] 
/********************************************************* 
** Takes Parameter "LIST" and transforms it for use ** 
** to select individual values or ranges of values. ** 
**              ** 
** EX: 'This,is,a,test' = 'This' 'Is' 'A' 'Test'  ** 
*********************************************************/ 
    (
      @LIST    VARCHAR(8000) 
     ,@DELIMITER  VARCHAR(255) 
    ) 

RETURNS @TABLE TABLE 
    ( 
     [RowID] INT IDENTITY 
     ,[Value] VARCHAR(255) 
    ) 
WITH SCHEMABINDING 
AS 
BEGIN 
    DECLARE 
     @LISTLENGTH AS SMALLINT 
     ,@LISTCURSOR AS SMALLINT 
     ,@VALUE AS VARCHAR(255) 
    ; 
    SELECT 
     @LISTLENGTH = LEN(@LIST) - LEN(REPLACE(@LIST,@DELIMITER,'')) + 1 
     ,@LISTCURSOR = 1 
     ,@VALUE = '' 
    ; 
    WHILE @LISTCURSOR <= @LISTLENGTH 
    BEGIN 

     INSERT INTO @TABLE (Value) 
     SELECT 
      CASE 
       WHEN @LISTCURSOR < @LISTLENGTH 
        THEN SUBSTRING(@LIST,1,PATINDEX('%' + @DELIMITER + '%',@LIST) - 1) 
       ELSE SUBSTRING(@LIST,1,LEN(@LIST)) 
      END 
     ; 
     SET @LIST = STUFF(@LIST,1,PATINDEX('%' + @DELIMITER + '%',@LIST),'') 
     ;  
     SET @LISTCURSOR = @LISTCURSOR + 1 
     ; 
    END 
    ; 
    RETURN 
    ; 
END 
; 

In diesem Fall würden Sie es wie folgt verwenden:

SELECT * FROM dbo.UDF_StringDelimiter(BotExceptions,' ') 
; 

Dies würde eine Liste von Werten wie folgt zurück:

RowID   Value 
-------------------- 
1    TR 
2    Sites24x7 
3    Tools 

Mit verschiedenen Methoden (a JOIN oder CROSS APPLY) können Sie die Verwenden Sie dies, um neue Zeilen in die Tabelle einzufügen.

Ich würde mir vorstellen, dass Sie zu diesen Funktionsergebnissen WHERE RowID >= 2, die nur eine zweite, dritte, vierte, n-te Zeile hinzufügen würde. Die erste Zeile, in der die ursprüngliche Zeichenfolge enthalten war, kann aktualisiert werden, um alle nachfolgenden Werte in einem zweiten Stapel zu entfernen, indem die gleiche Funktion WHERE RowID = 1 verwendet wird.

Würde das helfen?

Verwandte Themen