Prashanth Mundath Ответов: 2

Извлеките числовое значение месяца/года/Недели/дня из строки


У меня есть выпадающий список для выбора года/месяца/недели/дня, и выбранные значения будут назначены полю в виде строки . Из сгенерированной строки Мне нужно извлечь каждое значение.Позвольте мне объяснить на примере ниже
@string='30 лет 3 месяца 2 недели 2 дня'.
Требуемая производительность: @лет=30,@месяцев=3,@недель=2,@дней=2

Строка может иметь входные данные в любых комбинациях,
несколько случаев, как показано ниже
@String='3 Месяца 20 Дней' Или @String='3 Года 2 Недели' Или @String='10 Дней'

Поэтому из доступных форматов мне нужно извлечь @years,@months,@weeks,@days

Что я уже пробовал:

Прямо сейчас у меня нет решений

F-ES Sitecore

Вы должны хранить вещи в соответствующем формате, и вы не столкнетесь с этими проблемами. Имейте числовое поле в вашей таблице на годы, одно на месяцы и так далее и храните числа в соответствующем поле. Таким образом, вам вообще не нужно делать никакого синтаксического анализа строк.

2 Ответов

Рейтинг:
1

CHill60

Во-первых, смотрите (более чем корректный) комментарий от F-ES Sitecore.

Однако если вы действительно должны разобрать эту строку, то есть несколько способов сделать это.

Вы можете подумать об использовании цикла и использовании Функция patindex[^] чтобы найти числовые биты, например PATINDEX('%[0-9]%',@String) и/или нечисловые биты PATINDEX('%^[0-9]%',@String) Я бы не рекомендовал такой подход.

Мой предпочтительный подход...

Вы можете разделить строку на ее составные части, используя STRING_SPLIT [^] (из SQL 2016, Google для альтернативного решения, если у вас есть более ранняя версия), так что в итоге вы получите такую таблицу:

1	30
2	Years
3	3
4	Month
5	2
6	Weeks
7	2
8	day
Тогда вы можете сделать что-то вроде этого
;with CTE AS
(
	select ID, part, LEAD(part) OVER (ORDER BY id) AS descriptor
	from @split
)
SELECT '@' + descriptor + '=' + part
FROM CTE
WHERE ID % 2 = 1
что дает вам
@Years=30
@Month=3
@Weeks=2
@day=2
Но это не согласуется с дескрипторами, поэтому я бы сделал еще один шаг вперед и сделал что-то вроде
declare @descriptors table (part varchar(30), descriptor varchar(30))
insert into @descriptors (part, descriptor) values
('day','@days='),
('days','@days='),
('week','@weeks='),
('weeks','@weeks='),
('month','@month='),
('months','@months='),
('year','@years='),
('years','@years=')

;with CTE2 AS
(
	select ID, part, LEAD(part) OVER (ORDER BY id) AS descrip
	from @split
)
SELECT descriptor + a.part
FROM CTE2 A
INNER JOIN @descriptors B ON A.descrip = B.part
WHERE ID % 2 = 1
что дает
@years=30
@month=3
@weeks=2
@days=2
Затем вы захотите создать список, разделенный запятыми, из этих значений- есть множество предложения[^] на этом.

что возвращает меня прямо к комментарию F-ES Sitecore ... ваш дизайн не является правильным способом сделать это


Prashanth Mundath

Но, как я уже упоминал в описании, у меня всегда не будет всех входных данных, это может быть только одно значение, например "10 недель" или "2 месяца 3 дня"

CHill60

Техника работает и с этим - я использовал только один пример, так как решение было достаточно длинным. Вы, очевидно, не пробовали его.

Рейтинг:
0

Member 7870345

Вот функция, которая помогает в вашей задаче:

CREATE FUNCTION  number_that_preceeds 
(
	@input varchar(max),
	@search varchar(max)
)
RETURNS INT
AS
BEGIN
	DECLARE @inputReverse varchar(max)
	DECLARE @searchReverse varchar(max)
	DECLARE @resultStringReverse varchar(max)
	DECLARE @resultString varchar(max)
	DECLARE @string1 varchar(max)
	DECLARE @string2 varchar(max)
	DECLARE @i INT
	DECLARE @oneCharacter CHAR(1)
	DECLARE @result	BIGINT
	DECLARE @position BIGINT

	SET @resultStringReverse=''
	SET @result=0
	SET @inputReverse=REVERSE(UPPER(LTRIM(RTRIM(@input))))
	SET @searchReverse=REVERSE(UPPER(LTRIM(RTRIM(@search))))
	SET @position=CHARINDEX(@searchReverse,@inputReverse)
	IF @position>0
			BEGIN
			/* we need to find the number that comes BEFORE the @search parameter */
			/* so: we reverse both the input string and the search parameter */
			SET @string1=SUBSTRING(@inputReverse,@position+LEN(@searchReverse),LEN(@inputReverse)-@position+1-LEN(@searchReverse))
			/* now in @string1 we have just the reverse of the substring that preceeds @search */
			SET @string2=LTRIM(RTRIM(@string1))
			/* in resultStringReverse we concat just the numeric part of string2*/
			SET @resultStringReverse=''
			SET @i=1
			WHILE @i<=LEN(@string2)
				BEGIN
				SET @oneCharacter=SUBSTRING(@string2,@i,1)
				IF CHARINDEX(@oneCharacter,'0123456789')=0
					SET @i=LEN(@string2)+9999
				ELSE
					BEGIN
					SET @resultStringReverse=@resultStringReverse+@onecharacter
					SET @i=@i+1
					END
				END
			END

	
	SET @resultString=REVERSE(@resultStringReverse)
	/* with another reverse we have in resultString the just the string that contains the number that preceeds @searech*/
	IF @resultString=''
		SET @result='0'
	SET @result=CONVERT(int,@resultString)
	--SET @resultString=@resultStringReverse+'<'+STR(@result)+'>'
	RETURN @result

END
GO


и тогда вы можете использовать:
SELECT DBO.number_that_preceeds('3 YEAR 5 DAYS','DAY')

в obtein
5
или
SELECT DBO.number_that_preceeds('3 YEAR 5 DAYS','Month')

в obtein
0