Используя SQL Server, как мне разбить строку, чтобы я мог получить доступ к элементу x?
Возьми строку «Привет, Джон Смит». Как я могу разбить строку по пробелам и получить доступ к элементу с индексом 1, который должен возвращать «Джон»?
sql
sql-server
tsql
split
GateKiller
источник
источник
Ответы:
Вы можете найти решение в пользовательской функции SQL для анализа строки с разделителями полезно (из проекта кода ).
Вы можете использовать эту простую логику:
источник
SET @p_SourceText = RTRIM( LTRIM( @p_SourceText)) SET @w_Length = DATALENGTH( RTRIM( LTRIM( @p_SourceText)))
и нетSET @p_SourceText = RTRIM( LTRIM( @p_SourceText)) SET @w_Length = DATALENGTH( @p_SourceText)
?STRING_SPLIT
которая будет разбивать строку и возвращать результат таблицы с одним столбцом, который можно использовать вSELECT
выражении или в другом месте.Я не верю, что в SQL Server есть встроенная функция разбиения, поэтому, кроме UDF, единственный другой ответ, который я знаю, - это захват функции PARSENAME:
PARSENAME берет строку и разбивает ее на символ точки. Он принимает число в качестве второго аргумента, и это число указывает, какой сегмент строки нужно вернуть (работает сзади).
Очевидная проблема - когда строка уже содержит точку. Я все еще думаю, что использование UDF - лучший способ ... какие-нибудь другие предложения?
источник
SPLIT()
Функция не входит в комплект , потому что она поощряет плохой дизайн базы данных, и база данных не будет оптимизирована для использования данных , сохраненных в этом формате. РСУБД не обязан помогают разработчикам делать глупости , что он был разработан не для ручки. Правильный ответ всегда будет: «Нормализуйте свою базу данных, как мы говорили вам 40 лет назад». Ни SQL, ни RDBMS не виноваты в плохом дизайне.Во-первых, создайте функцию (используя CTE, общее табличное выражение устраняет необходимость во временной таблице)
Затем используйте его как любую таблицу (или измените ее так, чтобы она соответствовала существующему хранимому процессу), например так.
Обновить
Предыдущая версия не будет работать для входной строки длиннее 4000 символов. Эта версия заботится об ограничении:
Использование остается прежним.
источник
100
(для предотвращения бесконечного цикла). Используйте MAXRECURSION намек , чтобы определить число уровней рекурсии (0
к32767
,0
«нет предела» - может раздавить сервер). Кстати, гораздо лучший ответ, чемPARSENAME
, потому что он универсален :-). +1maxrecursion
к этому решению помните этот вопрос и ответы на него. Как настроитьmaxrecursion
опцию для CTE внутри функции с табличным значением .s
больше не определяетсяБольшинство решений здесь используют циклы while или рекурсивные CTE. Я обещаю, что подход, основанный на множествах, будет лучше, если вы можете использовать разделитель, отличный от пробела:
Пример использования:
Результаты:
Вы также можете добавить
idx
желаемое в качестве аргумента функции, но я оставлю это в качестве упражнения для читателя.Это невозможно сделать только с помощью встроенной
STRING_SPLIT
функции, добавленной в SQL Server 2016, поскольку нет гарантии, что выходные данные будут отображаться в порядке исходного списка. Другими словами, если вы передадите3,6,1
результат, скорее всего, будет в таком порядке, но это может быть1,3,6
. Я попросил помощи сообщества в улучшении встроенной функции здесь:Имея достаточно качественную обратную связь, они могут рассмотреть некоторые из следующих улучшений:
Более подробно о функциях разделения, почему (и доказательство этого), когда циклы и рекурсивные CTE не масштабируются, и более эффективные альтернативы, если разделение строк происходит из уровня приложения:
На SQL Server 2016 или выше, однако, вы должны смотреть
STRING_SPLIT()
иSTRING_AGG()
:источник
select * from DBO.SplitString('Hello John smith', ' ');
и был получен результат: Значение Привет, привет, привет, Джон, Джон, Хан, Смит, Мит, й, чВы можете использовать таблицу чисел для анализа строк.
Создайте таблицу физических чисел:
Создать тестовую таблицу с 1000000 строками
Создать функцию
Использование (выводит 3 миллиона строк в 40 с на моем ноутбуке)
уборка
Производительность здесь не удивительна, но вызов функции из таблицы с миллионами строк - не лучшая идея. При выполнении разбивки строки на несколько строк я бы избегал этой функции.
источник
desc
будут удалены?REVERSE(PARSENAME(REPLACE(REVERSE('Hello John Smith'), ' ', '.'), 1))
из @NothingsImpossible завершился через 1,5 минуты. @hello_earth Как ваше решение будет сравниваться на более длинных строках с более чем 4 полями?Этот вопрос не о подходе разделения строк , а о том, как получить n-й элемент .
Все ответы здесь делают какое - то строка расщепления с помощью рекурсии,
CTE
с, множественныйCHARINDEX
,REVERSE
иPATINDEX
, придумав функции, вызов методов CLR, количество таблиц,CROSS APPLY
S ... Большинство ответов охватывают множество строк коды.Но - если вы действительно хотите не более чем подход к получению n-го элемента - это может быть сделано в виде реальной строки , без UDF, даже без дополнительного выбора ... И в качестве дополнительного преимущества: type safe
Получить часть 2, разделенную пробелом:
Конечно, вы можете использовать переменные для разделителя и позиции (используйте
sql:column
для получения позиции непосредственно из значения запроса):Если ваша строка может содержать запрещенные символы (особенно один из них
&><
), вы все равно можете сделать это следующим образом. Просто используйтеFOR XML PATH
сначала строку, чтобы неявно заменить все запрещенные символы подходящей escape-последовательностью.Это особый случай, если, кроме того, вашим разделителем является точка с запятой . В этом случае сначала я заменяю разделитель на «# DLMT #», и наконец заменяю его тегами XML:
ОБНОВЛЕНИЕ для SQL-Server 2016+
К сожалению, разработчики забыли вернуть индекс детали с помощью
STRING_SPLIT
. Но, используя SQL-Server 2016+, естьJSON_VALUE
иOPENJSON
.С помощью
JSON_VALUE
мы можем передать позицию в качестве индекса 'массив.Для документации четко сказано:
OPENJSON
Строка , как
1,2,3
нужно ничего более скобки:[1,2,3]
.Строка слов вроде
this is an example
должна быть["this","is","an","example"]
.Это очень простые строковые операции. Просто попробуйте:
- Смотрите это для безопасного разделения строк (начиная с нуля ):
В этом посте я протестировал различные подходы и обнаружил, что
OPENJSON
это действительно быстро. Даже намного быстрее, чем знаменитый метод delimitedSplit8k () ...ОБНОВЛЕНИЕ 2 - Получить значения типа безопасны
Мы можем использовать массив внутри массива просто используя doubled
[[]]
. Это позволяет ввестиWITH
-clause:источник
<x><![CDATA[x<&>x]]></x>
.CDATA
-разделы тоже могут с этим справиться ... Но после броска они пропали (поменялись наtext()
неявные). Я не люблю магию под капотом , поэтому я бы предпочел(SELECT 'Text with <&>' AS [*] FOR XML PATH(''))
- подход. Это выглядит чище для меня и происходит в любом случае ... (Еще немного о CDATA и XML ).Вот UDF, который сделает это. Он вернет таблицу значений с разделителями, не пробовал все сценарии, но ваш пример работает нормально.
Вы бы назвали это так:
Изменить: Обновленное решение для обработки разделителей с len> 1, как в:
источник
Здесь я публикую простой способ решения
Выполните функцию следующим образом
источник
По моему мнению, вы, ребята, делаете это слишком сложно. Просто создайте CLR UDF и покончите с этим.
источник
Как насчет использования
string
иvalues()
заявления?Результат достигнут.
источник
Я использую ответ Фредерика, но это не сработало в SQL Server 2005
Я изменил его, и я использую
select
с,union all
и это работаетИ набор результатов:
источник
EXEC
.EXEC
неявно вызывает хранимую процедуру, и вы не можете использовать хранимые процедуры в UDF.Этот шаблон работает нормально, и вы можете обобщить
обратите внимание ПОЛЕ , ИНДЕКС и ТИП .
Пусть некоторые таблицы с идентификаторами, как
Затем вы можете написать
раскол и отливка всех деталей.
источник
Если ваша база данных имеет уровень совместимости 130 или выше, вы можете использовать функцию STRING_SPLIT вместе с OFFSET FETCH чтобы получить конкретный элемент по индексу.
Чтобы получить элемент с индексом N (с нуля), вы можете использовать следующий код
Чтобы проверить уровень совместимости вашей базы данных , выполните этот код:
источник
xml
бы подход, основанный на -split, так как он позволяет извлекать значение, безопасное с точки зрения типов и не требует подзапроса, но это Неплохо. +1 с моей стороныSTRING_SPLIT
требования для v2016 +. В этом случае гораздо лучше использоватьOPENJSON
илиJSON_VALUE
. Вы можете проверить мой ответЯ искал решение в сети, и ниже работает для меня. ссылка .
И вы вызываете функцию так:
источник
Еще одна часть строки получает функцию delimeter:
и использование:
который возвращает:
источник
Попробуй это:
Проверьте это так:
источник
В следующем примере используется рекурсивный CTE
Обновление 18.09.2013
Демо на SQLFiddle
источник
источник
Вы можете разбить строку в SQL без необходимости использования функции:
Если вам нужно поддерживать произвольные строки (с помощью специальных символов xml)
источник
Я знаю, что это старый вопрос, но я думаю, что кто-то может извлечь выгоду из моего решения.
SQL FIDDLE
Преимущества:
Ограничения:
Примечание : решение может дать подстроку до N.
Чтобы преодолеть ограничение, мы можем использовать следующую ссылку .
Но опять же вышеупомянутое решение не может быть использовано в таблице (на самом деле я не смог его использовать).
Опять же, я надеюсь, что это решение может кому-то помочь.
Обновление: В случае записей> 50000 не рекомендуется использовать ,
LOOPS
поскольку это приведет к ухудшению производительностиисточник
Чистое множество на основе решения с использованием
TVF
рекурсивногоCTE
. Вы можетеJOIN
иAPPLY
эту функцию для любого набора данных.Применение:
Результат:
источник
Почти все другие ответы заменяют разделяемую строку, которая тратит циклы ЦП и выполняет ненужные выделения памяти.
Я расскажу о гораздо лучшем способе разделения строк здесь: http://www.digitalruby.com/split-string-sql-server/
Вот код:
источник
Рекурсивное решение CTE с серверной болью, протестируйте его
Настройка схемы MS SQL Server 2008 :
Запрос 1 :
Результаты :
источник
Несмотря на то, что аналогично ответу на основе xml от josejuan, я обнаружил, что обработка пути xml только один раз, а затем поворот был умеренно более эффективным:
побежал в 8:30
побежал в 9:20
источник
И ИСПОЛЬЗУЙТЕ ЕГО
источник
если кто-то хочет получить только одну часть разделенного текста, можно использовать это
выберите * fromSplitStringSep ('Word1 wordr2 word3', '')
источник
Я разработал это,
единственное внимание, которое вам следует уделить, это точка '.' этот конец @x всегда должен быть там.
источник
Основываясь на решении @NothingsImpossible или, точнее, прокомментировав ответ с наибольшим количеством голосов (чуть ниже принятого), я обнаружил, что следующее быстрое и грязное решение отвечает моим собственным потребностям - оно имеет преимущество, заключающееся в том, что оно находится исключительно в домене SQL.
учитывая строку «первый; второй; третий; четвертый; пятый», скажем, я хочу получить третий токен. это работает только в том случае, если мы знаем, сколько токенов будет иметь строка - в данном случае это 5. поэтому мой способ действия - отрубить последние два токена (внутренний запрос), а затем отобрать первые два токена ( внешний запрос)
я знаю, что это уродливо и покрывает определенные условия, в которых я был, но я публикую это на тот случай, если кто-то посчитает это полезным. ура
источник
источник
Начиная с SQL Server 2016 у нас есть string_split
источник
STRING_SPLIT
не гарантирует возврат того же заказа. НоOPENJSON
делает (см. Мой ответ (раздел обновления) )