Удалить определенные данные вместе с угловыми скобками в SQL

Мне нужно удалить определенные данные из столбца 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, чтобы удалить угловые скобки <></> и их значение, а остальное сохранить?

Зачем вам отменять это редактирование...?

Thom A 07.06.2024 15:13

Это XML в столбце типа XML в таблице SQL Server? Также, пожалуйста, покажите нам, что вы пробовали...

marc_s 07.06.2024 15:14

Извините, приведенные выше значения загружаются на сервер Sql в столбце.

Mr D 07.06.2024 15:16

Да, и это столбец xml, @MrD?

Thom A 07.06.2024 15:17

Тип данных столбца: [varchar](3000) NULL, и я попробовал приведенное ниже, но не работает. Выберите Col, REPLACE(col, SUBSTRING(col, CHARINDEX('<', col), LEN(col) - CHARINDEX('>' , REVERSE(col)) - CHARINDEX('<', col) + 2), '') из таблицы

Mr D 07.06.2024 15:19

Пожалуйста, опубликуйте то, что вы пробовали в исходном вопросе, в правильном формате и все такое! Не пишите это в комментариях!

marc_s 07.06.2024 15:20

Реальный вопрос: как удалить все теги из фрагмента HTML? Вы не можете сделать это с помощью SQL и не можете использовать функции XML, потому что это недопустимый XML. Если только полный документ не будет правильно сформирован. SQL — это язык запросов, а не анализатор HTML. В T-SQL даже нет регулярных выражений, поэтому вы не сможете удалить все HTML-теги.

Panagiotis Kanavos 07.06.2024 15:21

Какие-либо значения в вашем столбце varchar недействительны xml, @MrD ? Возвращает ли SELECT YourStringColumn FROM dbo.YourTable WHERE TRY_CONVERT(xml,YourStringColumn) IS NULL AND YourStringColumn IS NOT NULL; какие-либо строки? Если ответ «да», то ответом на ваш вопрос будет «не использовать T-SQL». (И даже если это «нет», я все равно считаю, что это и есть ответ.)

Thom A 07.06.2024 15:22

Гораздо проще и быстрее удалять теги на клиентском языке, таком как C# или Python. Зачем это делать в SQL?

Panagiotis Kanavos 07.06.2024 15:23
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
1
9
67
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Чтобы внести ясность. 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 просто неподходящее место для этого.

Слишком сложно, вы можете просто использовать ось ` // ` всех потомков

Charlieface 07.06.2024 16:22

Почему я заявил: «Могут быть другие методы, использующие XQuery, чтобы сделать это без рекурсии». Это именно то направление, в котором я пошел, @Charlieface, я не говорил, что оно правильное.

Thom A 07.06.2024 16:29
Ответ принят как подходящий

Предполагая, что ваш 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)') объединяет их все вместе.

db<>рабочий пример

Это становится «шатким», если значение, которое дал нам ОП, представляет собой одно xml значение: db<>fiddle

Thom A 07.06.2024 16:31

@ThomA Что в этом плохого? ОП, кажется, хочет объединить все это воедино. Если им нужно пространство, вы можете просто сделать это for $t in //text() return concat($t, " ") Обратите внимание, как пример OP Test No.4466 соединился без пробела.

Charlieface 07.06.2024 16:33

ВЫБЕРИТЕ t.id, t.xhtml, t.xhtml.query('//text()').value('text()[1]', 'nvarchar(max)') AS значение FROM t; Этот код мне помог, спасибо Charlieface

Mr D 12.06.2024 12:48

Вот еще один вариант.

Примечательные моменты:

  • CROSS APPLY преобразует столбец VARCHAR(3000) в тип данных XML.
  • Функция XQuery data() получает все текстовые значения и автоматически добавляет пробел в качестве разделителя.
  • Нет необходимости использовать рекурсивное выражение XPath «//...» по соображениям производительности.

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);

Выход

идентификатор ценить 1 12345 2 45678 3 Тест № 4466 4 6789 5 Согласно вложению, нет, потому что мы должны были быть на борту.

Другие вопросы по теме