2009-03-10 7 views
3

J'ai un resultset composé de 1 colonne et dans ce cas 2 lignes la seule colonne [ProductDescription] est un champ varchar qui contient 3 informations (je ne l'ai pas conçu) i besoin d'obtenir ces trois éléments d'information sur dans 3 champs supplémentaires à l'aide d'une requêteMSSQL - Diviser un champ en 3 champs

avant

 
/------------------------------\ 
|ProductDescription   | 
|------------------------------| 
|DB1 - DB2 - DB3    | 
|DataBit1 - DataBit2 - DataBit3| 
\------------------------------/ 

Après

 
/---------------------------------------------------------\ 
|Field1 |Field2 |Field3 |ProductDescription   | 
|---------------------------------------------------------| 
|DB1  |DB2  |DB3  |DB1 - DB2 - DB3    | 
|DataBit1|DataBit2|DataBit3|DataBit1 - DataBit2 - DataBit3| 
\---------------------------------------------------------/ 

J'ai essayé d'utiliser des combinaisons de Substr ing et charindex mais n'ont pas été en mesure de l'obtenir tout à fait raison, chaque partie du champ pourrait être de n'importe quelle longueur, donc l'utilisation de décalages codés en dur ne fonctionne pas.

+0

Existe-t-il littéralement un tiret et un espace entre chaque composant? – cmsjr

Répondre

4

Ce n'est pas joli, mais cela fonctionne et il vous donne ce que vous cherchez, pour votre cas particulier ... Si vous aviez un nombre variable de jetons dans votre ProductDescription, vous auriez probablement besoin de créer un proc stocké pour gérer votre état tout en analysant la chaîne, car cela deviendrait rapidement ingérable.

create table #table(productdescription varchar(255)) 
go 
/* Demonstrate it working in a 'pretty' case */ 
INSERT INTO #TABLE (ProductDescription) values ('abc - def - ghi') 
go 

/* Demonstrate it working in a 'ugly' case */ 
insert into #table (ProductDescription) values ('jklsaf -mnoa-psdfaqr') 
go 

SELECT RTRIM(LTRIM(SUBSTRING(ProductDescription, 0, CHARINDEX('-', ProductDescription)-1))) as Field1, 

RTRIM(LTRIM(SUBSTRING(ProductDescription, CHARINDEX('-', ProductDescription)+1, (CHARINDEX('-', ProductDescription, CHARINDEX('-', ProductDescription)+1)) - (CHARINDEX('-', ProductDescription)+1)))) as Field2, 

RTRIM(LTRIM(SUBSTRING(ProductDescription, CHARINDEX('-', ProductDescription, CHARINDEX('-', ProductDescription)+1)+1, LEN(ProductDescription)))) as Field3 
FROM #table 
go 

J'espère que cela aide!

+0

Il y a un petit bogue: retourne "DB2-DB3", "DataBit2-DataBit3", "def-ghi", "mnoa-psdfaqr" etc dans la colonne Field2. – LukeH

+0

Fixé. J'ai oublié de soustraire mes paramètres Charindex pour obtenir une LONGUEUR dans le cas FIELD2. – Doug

+0

Et j'ai eu un bug très similaire dans ma réponse aussi :) – LukeH

2

Si l'on suppose qu'il ya toujours trois éléments d'information dans votre colonne ProductDescription et que le séparateur est toujours « - » alors ce qui suit devrait faire l'affaire:

SELECT 
    SUBSTRING(ProductDescription, 1, 
     CHARINDEX(' - ', ProductDescription) - 1 
    ) AS Field1, 
    SUBSTRING(ProductDescription, 
     CHARINDEX(' - ', ProductDescription) + 3, 
     CHARINDEX(' - ', ProductDescription, 
      CHARINDEX(' - ', ProductDescription) + 3 
     ) - (CHARINDEX(' - ', ProductDescription) + 3) 
    ) AS Field2, 
    SUBSTRING(ProductDescription, 
     CHARINDEX(' - ', ProductDescription, 
      CHARINDEX(' - ', ProductDescription) + 3) + 3, 
     LEN(ProductDescription) 
    ) AS Field3, 
    ProductDescription 
FROM your_table 
0

Merci luke, qui est proche mais pas exacte .

 
/----------------------------------------------------------------------------\ 
|DB1  |DB2  |DB3   |ProductDescription     | 
|----------------------------------------------------------------------------| 
|Loading |Trailer |Albert Moving |Loading - Trailer - Albert Moving | 
|Unloading |Trailer - |Moving Staffers|Unloading - Trailer - Moving Staffers| 
\----------------------------------------------------------------------------/ 
+0

Oups, j'ai mis à jour ma réponse pour y remédier. – LukeH

2

Que diriez-vous d'une fonction en ligne qui prend une chaîne, un séparateur, et quelle partie vous voulez revenir

Create Function dbo.GetPart(@InString as varchar(1000) 
    , @Part as int 
    , @Delim as varchar(10)) 
    Returns varchar(1000) as 
    Begin 
     Declare @CurrentPart int 
     Declare @i int 
     Declare @j int 
     Declare @Ret varchar(1000) 
     Set @Ret = '' 
     Set @i = 0 
     Set @InString = Replace(@InString, ' ', '') 

     Set @CurrentPart = 1 
     while (@CurrentPart <= @Part) 
     Begin 
      Set @j = charindex(@Delim, @InString, @i + 1) 
      if @j = 0 set @j = len(@InString) + 1 
      if ((@j - @i) > 0 and @CurrentPart = @Part) 
      Begin 
       Set @Ret = Substring(@InString, @i , @j - @i) 
       If @Ret = '' set @ret = 'Weird' 
       break 
      End 
      Set @i = charindex(@Delim, @InString, @i) + len(@delim) 
      Set @CurrentPart = @CurrentPart + 1 
     End 
     if @Ret = '' Set @Ret = 'inconveivable' 
     Return @Ret 
    End 
    GO 
    Select dbo.GetPart('DB1 - DB2 - DB3',1, '-') as Field1 
    ,dbo.GetPart('DB1 - DB2 - DB3',2, '-') as Field2 
    , dbo.GetPart('DB1 - DB2 - DB3',3, '-') as Field3 

    Select dbo.GetPart('DataBit1 - DataBit2 - DataBit3',1, '-') as Field1 
    ,dbo.GetPart('DataBit1 - DataBit2 - DataBit3',2, '-') as Field2 
    , dbo.GetPart('DataBit1 - DataBit2 - DataBit3',3, '-') as Field3 
+0

Cette fonction supprime les espaces au début, vous ne devez donc pas utiliser de caractères espaces dans le délimiteur tel qu'il est actuellement écrit. – cmsjr

0

Voici une autre solution. Suppose qu'il n'y a pas de période dans la description du produit (.):

SELECT 
    LTRIM(PARSENAME(REPLACE(ProductDescription,'-','.'),3)) DB1, 
    LTRIM(PARSENAME(REPLACE(ProductDescription,'-','.'),2)) DB2, 
    LTRIM(PARSENAME(REPLACE(ProductDescription,'-','.'),1)) DB3, 
    ProductDescription 
FROM #TABLE T 
0

Personall Je vérifierais pour « - » et l'utiliser comme mon delimiter au lieu de simplement le « - » pour la simple raison que de nombreuses entrées peuvent être coupé. Remplacez la combinaison de 3 caractères par une virgule et générez essentiellement une chaîne CSV (étape 1) et l'analyse des chaînes CSV dans votre table.

Il n'y a rien de mal à diviser de façon disproportionnée votre processus en deux opérations spécifiques au résultat pour atteindre ce dont vous avez besoin.

Mac

Questions connexes