Мне нужно удалить определенные данные из столбца SQL вместе с данными, я не могу найти правильный подход. Пожалуйста, помогите мне.
Пример ввода:
<div></div><div><div><div><div><p>12345</p></div></div></div></div>
<div><div><span>45678<span></span></span></div></div>
<div><div>Test No.</div></div><div><div><div><div><p>4466</p></div></div></div></div>
<div>6789</div>
<p></p><p><i>As per the attachment, no provided because we were supposed to be onboarded.</i></p>
Желаемый результат
12345
45678
Test No.4466
6789
As per the attachment, no provided because we were supposed to be onboarded.
Тип данных столбца — varchar NULL, и я попробовал приведенное ниже, но не работает.
Select Col, REPLACE(col, SUBSTRING(col, CHARINDEX('<', col), LEN(col) - CHARINDEX('>', REVERSE(col)) - CHARINDEX('<', col) + 2), '')
from table
Просто интересно, разве у нас нет прямого кода в SQL Server, чтобы удалить угловые скобки <></>
и их значение, а остальное сохранить?
Это XML в столбце типа XML
в таблице SQL Server? Также, пожалуйста, покажите нам, что вы пробовали...
Извините, приведенные выше значения загружаются на сервер Sql в столбце.
Да, и это столбец xml
, @MrD?
Тип данных столбца: [varchar](3000) NULL, и я попробовал приведенное ниже, но не работает. Выберите Col, REPLACE(col, SUBSTRING(col, CHARINDEX('<', col), LEN(col) - CHARINDEX('>' , REVERSE(col)) - CHARINDEX('<', col) + 2), '') из таблицы
Пожалуйста, опубликуйте то, что вы пробовали в исходном вопросе, в правильном формате и все такое! Не пишите это в комментариях!
Реальный вопрос: как удалить все теги из фрагмента HTML? Вы не можете сделать это с помощью SQL и не можете использовать функции XML, потому что это недопустимый XML. Если только полный документ не будет правильно сформирован. SQL — это язык запросов, а не анализатор HTML. В T-SQL даже нет регулярных выражений, поэтому вы не сможете удалить все HTML-теги.
Какие-либо значения в вашем столбце varchar
недействительны xml
, @MrD ? Возвращает ли SELECT YourStringColumn FROM dbo.YourTable WHERE TRY_CONVERT(xml,YourStringColumn) IS NULL AND YourStringColumn IS NOT NULL;
какие-либо строки? Если ответ «да», то ответом на ваш вопрос будет «не использовать T-SQL». (И даже если это «нет», я все равно считаю, что это и есть ответ.)
Гораздо проще и быстрее удалять теги на клиентском языке, таком как C# или Python. Зачем это делать в SQL?
Чтобы внести ясность. HTML — это не XML.
Устав от извлечения строк между двумя разными разделителями, я некоторое время назад создал эту функцию. Возможно это поможет или dbFiddle
Если в таблице
Declare @YourTable Table ([SomeCol] varchar(max)) Insert Into @YourTable Values
('<div/divdivdivdivdivp>12345</p/div/div/div/divdivdivspan>45678<span/span/span/div/divdivdiv>Test No.</div/divdivdivdivdivp>4466</p/div/div/div/divdiv>6789</divp/ppi>As per the attachment, no provided because we were supposed to be onboarded.</i/p>')
Select B.*
From @YourTable A
Cross Apply [dbo].[tvf-Str-Extract](SomeCol,'>','</') B
Если передать строку
Declare @S varchar(max) = '<div/divdivdivdivdivp>12345</p/div/div/div/divdivdivspan>45678<span/span/span/div/divdivdiv>Test No.</div/divdivdivdivdivp>4466</p/div/div/div/divdiv>6789</divp/ppi>As per the attachment, no provided because we were supposed to be onboarded.</i/p>'
Select * from [dbo].[tvf-Str-Extract](@S,'>','</') B
Полученные результаты
RetSeq RetVal
1 12345
2 Test No.
3 4466
4 6789
5 As per the attachment, no provided because we were supposed to be onboarded.
TVF, если интересно
CREATE FUNCTION [dbo].[tvf-Str-Extract] (@String varchar(max),@Delim1 varchar(100),@Delim2 varchar(100))
Returns Table
As
Return (
Select RetSeq = row_number() over (order by RetSeq)
,RetVal = left(RetVal,charindex(@Delim2,RetVal)-1)
From (
Select RetSeq = row_number() over (order by 1/0)
,RetVal = ltrim(rtrim(B.i.value('(./text())[1]', 'varchar(max)')))
From ( values (convert(xml,'<x>' + replace((Select replace(@String,@Delim1,'§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>').query('.'))) as A(XMLData)
Cross Apply XMLData.nodes('x') AS B(i)
) C1
Where charindex(@Delim2,RetVal)>1
)
Если ваш HTML также действителен xml
, вы можете рассматривать его как XML. Одним из методов было бы использование рекурсивного общего табличного выражения (rCTE), чтобы просто перебирать дочерние узлы и затем возвращать значения, где значение не равно NULL
. Могут быть другие методы, использующие XQuery, чтобы сделать это без рекурсии.
DECLARE @XML varchar(3000) = '<div></div><div><div><div><div><p>12345</p></div></div></div></div>
<div><div><span>45678<span></span></span></div></div>
<div><div>Test No.</div></div><div><div><div><div><p>4466</p></div></div></div></div>
<div>6789</div>
<p></p><p><i>As per the attachment, no provided because we were supposed to be onboarded.</i></p>';
SELECT @XML AS XMLString
INTO #YourTable;
WITH rCTE AS(
SELECT X.N.value('(./text())[1]','nvarchar(50)') AS NodeValue, --Choose an appropriate length, I just went with 50 as an arbitrary value
X.N.query('*') AS NodeQuery
FROM #YourTable YT
CROSS APPLY(VALUES(TRY_CONVERT(xml,YT.XMLString)))V(XML)
CROSS APPLY V.XML.nodes('/*') X(N)
UNION ALL
SELECT C.N.value('(./text())[1]','nvarchar(50)') AS NodeValue, --Choose an appropriate length, I just went with 50 as an arbitrary value
C.N.query('*') AS NodeQuery
FROM rCTE r
CROSS APPLY r.NodeQuery.nodes('./child::node()') C(N))
SELECT r.NodeValue
FROM rCTE r
WHERE r.NodeValue IS NOT NULL;
Если ваш HTML недействителен xml
, то, по моему мнению, T-SQL просто неподходящее место для этого.
Слишком сложно, вы можете просто использовать ось ` // ` всех потомков
Почему я заявил: «Могут быть другие методы, использующие XQuery, чтобы сделать это без рекурсии». Это именно то направление, в котором я пошел, @Charlieface, я не говорил, что оно правильное.
Предполагая, что ваш HTML также является допустимым XML, вы можете просто использовать следующий код, чтобы получить все текстовые узлы и объединить их вместе.
SELECT
t.id,
t.xhtml,
t.xhtml.query('//text()').value('text()[1]', 'nvarchar(max)') AS value
FROM t;
.query('//text()')
получает все текстовые узлы, вы можете использовать любой фильтр XQuery, чтобы получить любые узлы, которые вы хотите. Затем .value('text()[1]', 'nvarchar(max)')
объединяет их все вместе.
Это становится «шатким», если значение, которое дал нам ОП, представляет собой одно xml
значение: db<>fiddle
@ThomA Что в этом плохого? ОП, кажется, хочет объединить все это воедино. Если им нужно пространство, вы можете просто сделать это for $t in //text() return concat($t, " ")
Обратите внимание, как пример OP Test No.4466
соединился без пробела.
ВЫБЕРИТЕ t.id, t.xhtml, t.xhtml.query('//text()').value('text()[1]', 'nvarchar(max)') AS значение FROM t; Этот код мне помог, спасибо Charlieface
Вот еще один вариант.
Примечательные моменты:
CROSS APPLY
преобразует столбец VARCHAR(3000) в тип данных XML.data()
получает все текстовые значения и автоматически добавляет пробел в качестве разделителя.SQL
-- DDL and sample data population, start
DECLARE @tbl TABLE (id INT PRIMARY KEY IDENTITY, fragment VARCHAR(3000));
INSERT @tbl (fragment) VALUES
('<div></div><div><div><div><div><p>12345</p></div></div></div></div>'),
('<div><div><span>45678<span></span></span></div></div>'),
('<div><div>Test No.</div></div><div><div><div><div><p>4466</p></div></div></div></div>'),
('<div>6789</div>'),
('<p></p><p><i>As per the attachment, no provided because we were supposed to be onboarded.</i></p>');
-- DDL and sample data population, end
SELECT t.*
, TRIM(c.query('data(/*)').value('text()[1]', 'VARCHAR(MAX)')) AS value
FROM @tbl AS t
CROSS APPLY (SELECT TRY_CAST(fragment AS XML)) AS t1(c);
Выход
Зачем вам отменять это редактирование...?