2010-12-15 29 views
1

j'ai un champ de base de données avec des données comme les exemples ci-dessous:Parsing Out données en différentes longueurs pour être utilisé dans une procédure stockée pour calculer un champ

FEE 200 A 16 YN NYFIRE 32,8 C M0008 YN
INF 150 A 05 AA PFE 35 A 05 AA
NYFEE 200 A 16 YN

Je dois analyser toutes les valeurs avec un A devant eux, ou toutes les valeurs qui sont précédés d'un INF. Si elles sont précédées d'un INF j'ai besoin d'utiliser ces valeurs pour les déduire d'une formule en SQL. Si les valeurs ne sont pas précédées d'un INF, mais sont suivies d'un A, j'ai besoin d'ajouter ces valeurs dans une formule dans une procédure stockée. IMPORTANT, ce qui ressemble à des espaces dans les exemples sont des caractères CHAR (9). Il pourrait y avoir jusqu'à 9 séries de nombres qui ont un A avant eux ... les exemples ci-dessus montrent seulement 1 ou 2. Je peux extraire le premier en utilisant un charindex, mais je ne sais pas comment obtenir les A suivants . Je ne peux pas obtenir un patindex pour travailler avec '% [' + CHAR (9) + 'INF' + CHAR (9) + ']%', mais si je fais patindex sur 'INF' alors je ne peux pas obtenir juste la valeur suivante avec le 'INF' dans le cadre de la chaîne, je ne veux pas la partie 'INF'. Je ne sais pas comment analyser les valeurs dans une procédure stockée, ou pas du tout (j'ai essayé un certain nombre de choses comme mentionné ci-dessus), et n'ai pas été capable de trouver quoi que ce soit sauf comment analyser données sur des modèles spécifiques. Il n'y a pas toujours le même nombre d'espaces pour la valeur précédant le A, il pourrait y avoir 2 ou 3 caractères.

+1

est ce SQL Server? Regardez les CTE récursifs. En outre, c'est un parfait exemple de pourquoi vous ne devriez stocker qu'une seule valeur dans une ligne/colonne. –

Répondre

0

Ceci va analyser les valeurs. Dans SQL 2005/2008 vous pouvez faire

DECLARE @Test table 
(id int identity, field varchar(max)) 

INSERT INTO @Test (field) 
Values('FEE 200 A 16 Y N NYFIRE 32.8 C M0008 Y N') 

INSERT INTO @Test (field) 
Values('INF 150 A 05 Y Y PFE 35 A 05 Y Y') 

INSERT INTO @Test (field) 
Values('NYFEE 200 A 16 Y N') 
Update @Test set Field = REPLACE(Field,' ', CHAR(9)) 


;with cte 
as 
(

SELECT 
     id, 
     cast(0 as bigint) ind, 
     cast('' as varchar(max)) foo, 
     1 anchor 
FROM 
     @Test 
UNION ALL SELECT 
     n.id, CHARINDEX(Char(9), 
     n.field, 
     cte.ind+1) ind , 
     SUBSTRING(field,cte.ind,CHARINDEX(Char(9),n.field, cte.ind+1) - cte.ind) Foo, 
     0 anchor 
FROM 
     @Test n 
     INNER JOIN cte ON n.id = cte.id 
WHERE 
     CHARINDEX(Char(9),n.field, cte.ind+1) <> 0 
) 

select * 
from cte 
where 
    anchor = 0 


order by id, ind 

Vous pouvez soit mettre en place une boucle (que je ne recommande pas) ou vous pouvez faire l'auto-jointures pour comprendre ce qui a un droit et ce qui a une INF et quelles sont les valeurs que vous voulez

select Fees.id, value.* 

from cte Fees 
INNER JOIN Cte a 
ON Fees.id = a.id and a.foo like '%A%' 
    INNER JOIN Cte value 
ON a.id = value.id and a.ind < value.ind 

where 
fees.anchor = 0 
and fees.foo like '%FEE' 

order by fees.id, fees.ind 

Si vous utilisez 2000, vous aurez besoin de mettre en place une fonction split et boucle à travers vos données et l'appeler

SET QUOTED_IDENTIFIER ON 
GO 


CREATE FUNCTION [dbo].[Split] 
( 
    @RowData VARCHAR(8000), 
    @Delimeter NVARCHAR(2000) 
) 
RETURNS @RtnValue TABLE 
(
    ID INT IDENTITY(1,1), 
    Data VARCHAR(8000) 
) 
AS 
BEGIN 
    DECLARE @Iterator INT 
    SET @Iterator = 1 

    DECLARE @FoundIndex INT 
    SET @FoundIndex = CHARINDEX(@Delimeter,@RowData) 

    WHILE (@FoundIndex>0) 
    BEGIN 
     INSERT INTO @RtnValue (data) 
     SELECT 
      Data = LTRIM(RTRIM(SUBSTRING(@RowData, 1, @FoundIndex - 1))) 

     SET @RowData = SUBSTRING(@RowData, 
       @FoundIndex + DATALENGTH(@Delimeter)/2, 
       LEN(@RowData)) 

     SET @Iterator = @Iterator + 1 
     SET @FoundIndex = CHARINDEX(@Delimeter, @RowData) 
    END 

    INSERT INTO @RtnValue (Data) 
    SELECT Data = LTRIM(RTRIM(@RowData)) 

     RETURN 
    END 
Go 

La fonction split est une version modifiée pour 2000 version de ce qui est found here par Itai Goldstein

DECLARE @Test table 
(id int identity, fieldValue varchar(2000)) 

INSERT INTO @Test (fieldValue) 
Values('FEE 200 A 16 Y N NYFIRE 32.8 C M0008 Y N') 

INSERT INTO @Test (fieldValue) 
Values('INF 150 A 05 Y Y PFE 35 A 05 Y Y') 

INSERT INTO @Test (fieldValue) 
Values('NYFEE 200 A 16 Y N') 
Update @Test set fieldValue = REPLACE(fieldValue,' ', CHAR(9)) 

DECLARE @fieldValue varchar(2000) 
DECLARE @CurrentID int 

    SELECT @CurrentID = MIN(id) 
    FROM 
     @test 



DECLARE @OUTPUT table 
(id int , theOrder int, fieldValue varchar(2000)) 
DECLARE @rowData varchar(8000) 

DECLARE @delimiter varchar(1) 
SET @delimiter = char(9) 

WHILE not @CurrentID IS NULL 
BEGIN 


    SELECT @rowData = FieldValue FROM @Test Where id = @currentID 

    INSERT INTO @OUTPUT 
    SELECT 
     @currentID, 
     s.ID, 
     s.data 
    FROM 
     dbo.split(@rowdata, @delimiter) s 


    SELECT @CurrentID = MIN(id) 
    FROM 
     @test 
    WHERE 
     id > @CurrentID 



END 

SELECT * FROM @OUTPUT 
+0

Cela utilise SQL Server 2005. Malheureusement, nous sommes à la merci d'un fournisseur tiers concernant la base de données. Nous ne sommes pas friands de leur choix d'entrer plusieurs valeurs dans un domaine, mais doivent travailler avec ce que nous avons ... – dazacher

+0

@dazacher J'ai testé cela avec SQL 2008, mais il devrait fonctionner correctement avec 05 –

+0

Je reçois le message d'erreur suivant : Syntaxe incorrecte près du mot clé "avec" lorsque j'essaie de l'exécuter ..... des suggestions? – dazacher