2012-06-13 26 views
12

Realmente me gustaría obtener algunos consejos aquí, para dar algunos antecedentes. Estoy trabajando con la inserción de registros de seguimiento de mensajes de Exchange 2007 en SQL. Como tenemos millones y millones de filas por día, estoy usando una declaración de inserción masiva para insertar los datos en una tabla SQL.División de valores delimitados en una columna de SQL en varias filas

De hecho, en realidad, inserto a granel en una tabla temporal y luego de allí MEBO los datos en la tabla activa, esto es para problemas de análisis de prueba, ya que ciertos campos tienen comillas y valores similares.

Esto funciona bien, con la excepción del hecho de que la columna de la dirección del destinatario es un campo delimitado separado por a; personaje, y puede ser increíblemente largo a veces, ya que puede haber muchos destinatarios de correo electrónico.

Me gustaría tomar esta columna y dividir los valores en varias filas que luego se insertarán en otra tabla. El problema es que lo que estoy intentando es tomar demasiado tiempo o no funcionar de la manera que quiero.

Tome este ejemplo de datos:

message-id            recipient-address 
[email protected] [email protected] 
[email protected]  [email protected] 
[email protected]    [email protected];[email protected];[email protected] 

me gustaría que esto se formatea como utilizada en mi mesa de destinatarios:

message-id            recipient-address 
[email protected] [email protected] 
[email protected]  [email protected] 
[email protected]    [email protected] 
[email protected]    [email protected] 
[email protected]    [email protected] 

¿Alguien tiene alguna idea acerca de cómo puedo ir haciendo esto ?

Conozco bien a PowerShell, así que lo intenté, pero un ciclo foreach incluso en los 28K registros me llevó mucho tiempo procesar, necesito algo que se ejecute lo más rápido/eficientemente posible.

Gracias!

+0

Creo que debería ponerle tres resultados en una tabla usando una función dividida. Mire esto: http: // stackoverflow.com/questions/314824/t-sql-opposite-to-string-concatenation-how-to-split-string-into-multiple-reco Y luego de eso puedes administrar para unir tus datos divididos en tu otra tabla para obtener tu resultado – GregM

Respuesta

41

En primer lugar, crear una función de división:

CREATE FUNCTION dbo.SplitStrings 
(
    @List  NVARCHAR(MAX), 
    @Delimiter NVARCHAR(255) 
) 
RETURNS TABLE 
AS 
    RETURN (SELECT Number = ROW_NUMBER() OVER (ORDER BY Number), 
     Item FROM (SELECT Number, Item = LTRIM(RTRIM(SUBSTRING(@List, Number, 
     CHARINDEX(@Delimiter, @List + @Delimiter, Number) - Number))) 
    FROM (SELECT ROW_NUMBER() OVER (ORDER BY s1.[object_id]) 
     FROM sys.all_objects AS s1 CROSS APPLY sys.all_objects) AS n(Number) 
    WHERE Number <= CONVERT(INT, LEN(@List)) 
     AND SUBSTRING(@Delimiter + @List, Number, 1) = @Delimiter 
    ) AS y); 
GO 

Ahora se puede extrapolar simplemente por:

SELECT s.[message-id], f.Item 
    FROM dbo.SourceData AS s 
    CROSS APPLY dbo.SplitStrings(s.[recipient-address], ';'); 

También yo no sugeriría poner guiones en los nombres de columna. Significa que siempre debe ponerlos en [square brackets].

+2

Usted señor, merece una cookie de Internet :) Tuve que hacer un par de cambios, tuve que llamar al valor del campo Artículo en su lugar, ya que a PowerShell no le gustaba el nombre Artículo. También tuve que agregar 'AS f' después de aplicar CRUZ para alias esa sección como f, por lo que llamar a f.item/f.value funcionó. – HungryHippos

+0

También le escucho sobre los nombres de las columnas, esto se hizo para mantener la paridad con los nombres de las columnas del registro de seguimiento, soy consciente de la necesidad de corchetes y está bien, está bien. – HungryHippos

+0

muestra brillante. mi declaración se ve así: SELECCIONAR en el elemento, f.Artículo FROM dbconfig AS s CROSS APLICAR SplitStrings (s.setting, ';') AS f WHERE s.item = 'EXE_PATHS' –

0

SQL Server 2016 incluye una nueva función de tabla string_split(), similar a la solución anterior.

El único requisito es establecer el nivel de compatibilidad al 130 (SQL Server 2016)

0

Usted puede utilizar CROSS APPLY (disponible en SQL Server 2005 y superior) y STRING_SPLIT función (disponible en SQL Server 2016 y superior):

DECLARE @delimiter nvarchar(255) = ';'; 

-- create tables 
CREATE TABLE MessageRecipients (MessageId int, Recipients nvarchar(max)); 
CREATE TABLE MessageRecipient (MessageId int, Recipient nvarchar(max)); 

-- insert data 
INSERT INTO MessageRecipients VALUES (1, '[email protected]; [email protected]; [email protected]'); 
INSERT INTO MessageRecipients VALUES (2, '[email protected]; [email protected]'); 

-- insert into MessageRecipient 
INSERT INTO MessageRecipient 
SELECT MessageId, ltrim(rtrim(value)) 
FROM MessageRecipients 
CROSS APPLY STRING_SPLIT(Recipients, @delimiter) 

-- output results 
SELECT * FROM MessageRecipients; 
SELECT * FROM MessageRecipient; 

-- delete tables 
DROP TABLE MessageRecipients; 
DROP TABLE MessageRecipient; 

resultados:

MessageId Recipients 
----------- ---------------------------------------------------- 
1   [email protected]; [email protected]; [email protected] 
2   [email protected]; [email protected] 

y

MessageId Recipient 
----------- ---------------- 
1   [email protected] 
1   [email protected] 
1   [email protected] 
2   [email protected] 
2   [email protected] 
Cuestiones relacionadas