Разбор данных в различных длинах для использования в хранимой процедуре для вычисления поля
У меня есть поле базы данных с данными, как примеры ниже:
FEE 200 A 16 YN NYFIRE 32,8 C M0008 YN
INF 150 A 05 YY PFE 35 A 05 YY
NYFEE 200 A 16 YN
Мне нужно разобрать все значения с A перед ними, или любые значения, которые начинаются с INF. Если им предшествует INF, мне нужно использовать эти значения, чтобы вычесть их из формулы в SQL. Если значения не предшествуют INF, но сопровождаются AI, необходимо добавить эти значения в формулу в хранимой процедуре. ВАЖНО, то, что в примерах выглядит как пробелы, это символы CHAR(9). Может быть до 9 серий чисел, перед которыми стоит буква A... в приведенных выше примерах показано только 1 или 2. Я могу извлечь первое с помощью charindex, но не знаю, как получить последующие буквы A, Я не могу заставить patindex работать с '%[' + CHAR(9) + 'INF' + CHAR(9) + ']%', но если я делаю patindex только с INF, то я не могу получить только следующее значение с INF в качестве части строки, я не хочу, чтобы часть INF.
Я не знаю, как анализировать значения в хранимой процедуре или вообще (я пробовал несколько вещей, как упомянуто выше), и не смог найти ничего, кроме как проанализировать данные по определенным шаблонам, Не всегда одинаковое количество пробелов для значения, предшествующего A, это может быть 2 или 3 символа.
1 ответ
Это будет анализировать значения. В SQL 2005/2008 вы можете сделать
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
Вы можете либо настроить цикл (который я не рекомендую), либо вы можете сделать самостоятельные объединения, чтобы выяснить, что имеет FEE, а что INF и какие значения вы хотите
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
Если вы используете 2000, вам нужно настроить функцию разделения, перебрать данные и вызвать их
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
Функция расщепления является модифицированной для 2000 версии того, что находится здесь у 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