chints786 Ответов: 3

Как извлечь конкретное значение из существующего значения


У меня есть таблица, в которой есть столбец, состоящий из различных шаблонов значений.

Мне нужно извлечь определенные ценности из этого отца.


вход
8.92 mm (0.3510)			
31.00 mm (1.2210)			
0.3583
1-1/32" (1.0312)
#77 (0.0180 in)			
J (0.2770)				
11/64" (0.1719)
21/32 in (0.6562 in)


выход
0.3510
1.2210
0.3583
1.0312
0.0180
0.2770
0.1719
0.6562


Пожалуйста, помогите!!

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

Charindex и substring но не смогли добиться успеха

CHill60

Раздел "Что я пробовал" предназначен для того, чтобы вы поместили код, который вы пробовали
Edit - кроме того, какую версию SQL вы используете?

3 Ответов

Рейтинг:
2

CHill60

Решение 1-это лучший совет, который вы получите, но в этом решении я буду предполагать, что у вас уже есть эти данные и вы хотите преобразовать их в более разумный формат, предложенный в решении 1.

Сначала изучите данные - на первый взгляд кажется, что существует 7 или более различных форматов, но числа, которые вас интересуют, находятся только в двух разных форматах ... больше ничего нет в столбце, например, ваша строка 3 0.3583, Или они окружены скобками (...).
Если вы окружены скобками, то у вас есть только две версии этого - только цифры, например, ваша строка 1 8.92 mm (0.3510) или за ним следует "в", Например, ваша строка 5 #77 (0.0180 in)
Все остальное в данных игнорируется, поэтому то, что вы пытаетесь сделать, это
1. Удалите все, что не связано с требуемым номером
2. Удалите в скобках все, что не является числом
3. Снимите скобки

Когда вы подходите к проблемам такого рода, очень важно сделать этот предварительный анализ, чтобы вы могли быть уверены, что вы охватываете все возможные варианты.

Вы можете сделать шаг 1 с sql следующим образом

select id, s.[value]
FROM @test
CROSS APPLY string_split (dat, '(') s
WHERE s.value LIKE '%)%'
	
UNION 
	
select id, dat
FROM @test
WHERE dat NOT LIKE '%(%'
Моменты, которые следует отметить:
а) если вы используете версию SQL до 2016 года, вам придется написать свой собственный UDF, чтобы выполнить разделение строк. Есть сотни примеров, доступных через вашу любимую поисковую систему.
б) обратите внимание, что в первом запросе я просто ищу цифры в скобках. Я игнорирую все, что не было заключено в скобки, проверяя наличие закрывающей скобки
в) второй запрос ищет шаблон, где столбец содержит только наше правило чисел.
Пока что мы получаем такие результаты:
id	[value]
1	0.3510)
2	1.2210)
3	0.3583
4	1.0312)
5	0.0180 in)
6	0.2770)
7	0.1719)
8	0.6562 in)
Таким образом, нам все еще нужно избавиться от закрывающей скобки и "in", что мы можем сделать следующим образом
;with cte as 
(
	select id, REPLACE(REPLACE(s.value, ')',''), ' in','')  AS [value]
	FROM @test
	CROSS APPLY string_split (dat, '(') s
	WHERE s.value LIKE '%)%'
	
	UNION 
	
	select id, dat
	FROM @test
	WHERE dat NOT LIKE '%(%'
)
SELECT id, [value]
from cte
Здесь очень важно отметить, что эти значения являются строками - возможно, вам придется преобразовать их в числа, прежде чем они будут использованы.

Теперь я собираюсь вернуться к решению 1, где @OriginalGriff указывает
Цитата:
вы найдете входные данные, которые не соответствуют ни одному из приведенных примеров, поэтому вам придется часто менять сложный SQL-код для обнаружения и добавления новых случаев.
К счастью, вы последуете его совету, так что это будет одноразовое упражнение, а не частое явление. Однако вам нужно будет изучить ваши преобразованные данные, чтобы убедиться, что вы захватили все.

РЕДАКТИРОВАТЬ: Я просто изменил свои тестовые данные, чтобы проверить наличие других проблем - обратите внимание на новый формат в последнем значении
declare @test table (id int identity(1,1), dat nvarchar(50))
insert into @test (dat) values
('8.92 mm (0.3510)' ),
('31.00 mm (1.2210)'), 
('0.3583'),
('1-1/32" (1.0312)'),
('#77 (0.0180 in)' ),
('J (0.2770)'),
('11/64" (0.1719)'),
('21/32 in (0.6562 in)')
,('0.3583 in')
Это привело к тому, что мой код выше выдал ошибку
Msg 8114, Уровень 16, Состояние 5, Строка 28
Ошибка преобразования типа данных nvarchar в числовой.
Этого можно избежать (в данном случае), выполнив замену вне cte, т. е.
;with cte as 
(
	select id, s.[value]
	FROM @test
	CROSS APPLY string_split (dat, '(') s
	WHERE s.value LIKE '%)%'
	
	UNION 
	
	select id, dat
	FROM @test
	WHERE dat NOT LIKE '%(%'
)
SELECT id, REPLACE(REPLACE([value], ')',''), ' in','')  
from cte
Но это действительно делает точку зрения, которую сделал @OriginalGriff и которую я процитировал выше!


Maciej Los

5ed!

Рейтинг:
2

OriginalGriff

В принципе, не храните его так вообще: обработка строк SQL-это ... МММ ... плохо, в лучшем случае - и вы должны выбрать тип хранения (метрическое или имперское) и преобразовать входные данные в вашем программном обеспечении для презентаций в это, а затем сохранить их в виде последовательного числа в столбце с плавающей запятой.
Хранение числовых значений в виде строк - это просто рецепт для чрезвычайно болезненной обработки позже, особенно когда "числовое значение" имеет свободную форму и не находится в определенной системе измерений.

Оставить хранилище таким, как оно есть на данный момент, - это кошмар: вы найдете входные данные, которые не соответствуют ни одному из показанных вами примеров, поэтому вам придется часто менять сложный SQL-код для обнаружения и добавления новых случаев.
Объединяйте и проверяйте входные данные; храните данные в числовых полях; будьте последовательны. В будущем ваша жизнь станет намного легче!


Рейтинг:
1

Santosh kumar Pithani

DECLARE @table TABLE(INputval NVARCHAR(100)); 

INSERT INTO @table(INputval)

VALUES
 ('8.92 mm (0.3510)')	
,('31.00 mm (1.2210)')
,('0.3583')
,('1-1/32" (1.0312)')
,('#77 (0.0180 in)')	
,('J (0.2770)')	
,('11/64" (0.1719)')
,('21/32 in (0.6562 in)')


SELECT SUBSTRING(REPLACE(REPLACE(INputval,'in','  '),')',' '),CHARINDEX('(',INputval)+1,LEN(INputval)) AS INputval  FROM @table


chints786

Спасибо, Сантош!! Не могли бы вы дать мне знать что если у меня есть данные в дроби скажем

На col1
1/2
2/3
4/5
0.123
0.345
0.222

Мне нужна только дробная часть, то есть

На col1
1/2
2/3
4/5

На col1
1/2
2/3
4/5

CHill60

В этом случае применяется решение 1

Santosh kumar Pithani

Если вам нужно отфильтровать только дробные значения ('/'), то используйте charindex ('/', columnName)<>0