#sql-server
#sql-server
Вопрос:
У меня есть строка, которая содержит символы, специальные символы и цифры в ней.
что мне нужно для этого, я должен разделить все символы в один столбец, а специальные символы — в другой столбец, а числа — в другой столбец, используя общее табличное выражение.мне было бы полезно, если бы кто-нибудь предоставил код, используя общее табличное выражение для получения требуемого результата.
Код, который я пробовал до сих пор:
DECLARE @search VARCHAR(200)
SET @search='123%#'
;with cte (Num,indexing) as (
SELECT
@search,0
UNION ALL
SELECT
indexing
num
from
cte
cross apply
(select indexing 1) C(NewLevel)
CROSS APPLY
(SELECT REPLACE(Num, NewLevel, '')) C2(NewInput)
WHERE
indexing<=LEN(NUM)
)
select Num
from cte
Мой ввод должен быть: abcd12345 $@##
мой ожидаемый результат:
Column 1 Column 2 Column 3
12345 $@### abcd
Комментарии:
1. К вашему сведению, хорошее использование пробелов является обязательным при написании читаемого SQL. Потратьте время на форматирование вашего кода, это значительно упростит чтение вашего кода как для вас, так и для других. Например, очень сложно (в приведенном выше) увидеть, где начинается и заканчивается этот CTE.
2. Кроме того, какая версия SQL Server?
3. @Larnu Ms Sql Server 2019
4. @Larnu Почему вы использовали эти многочисленные ЗНАЧЕНИЯ null (NULL),(NULL),(NULL), (NULL), (NULL),(NULL), (NULL),(NULL),(NULL),(NULL))N(N)) можем ли мы решить эту проблемугораздо более простым способом
5. @Larnu Если вы не возражаете, можете ли вы решить эту проблему с помощью rcte, потому что я должен решить эту проблему с помощью rcte
Ответ №1:
Я бы лично использовал Tally для разделения строки на отдельные символы, а затем использовал бы агрегацию условных строк для создания новых строк:
DECLARE @YourString varchar(200) = 'abcd12345$@##';
WITH N AS(
SELECT N
FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
SELECT TOP(LEN(@YourString))
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS I
FROM N N1, N N2, N N3, N N4),
Chars AS(
SELECT V.YourString,
SS.C,
T.I,
CASE WHEN SS.C LIKE '[A-z]' THEN 'Letter'
WHEN SS.C LIKE '[0-9]' THEN 'Number'
ELSE 'Special'
END AS CharType
FROM (VALUES(@YourString)) V(YourString)
CROSS JOIN Tally T
CROSS APPLY (VALUES(SUBSTRING(V.YourString,T.I,1)))SS(C))
SELECT STRING_AGG(CASE CharType WHEN 'Letter' THEN C END,'') WITHIN GROUP (ORDER BY I) AS Letters,
STRING_AGG(CASE CharType WHEN 'Number' THEN C END,'') WITHIN GROUP (ORDER BY I) AS Numbers,
STRING_AGG(CASE CharType WHEN 'Special' THEN C END,'') WITHIN GROUP (ORDER BY I) AS Special
FROM Chars
GROUP BY YourString;
Также обратите внимание на использование пробелов, чтобы вы могли четко видеть, где начинается один CTE и начинается другой.
Объяснение
Первый CTE ( N
) — это всего 10 NULL
значений. Я использую 10, поскольку с кратными 10 легко работать.
Затем следующая CTE ( Tally
) создает таблицу подсчета. Он пересекает N
сам себя 4 раза, создавая 10 ^ 4 строки или 10 000 строк, каждая с увеличивающимся числом, из-за ROW_NUMBER
. Однако нам не нужны все эти строки, поэтому я ограничиваю их длиной вашей переменной.
Затем мы переходим к Chars
; это разбивает строку на отдельные символы, по 1 строке на символ, нумерует их и определяет их тип: буква, цифра или специальный символ.
Затем мы, наконец, после CTE, объединяем значения, используя условное STRING_AGG
выражение, так что в столбце агрегируется только тот тип символов, который вы хотите.
Если вы «должны» использовать rCTE, вы можете сделать это таким образом, но, как я уже упоминал, rCTE является гораздо более медленным решением и страдает от ошибок максимальной рекурсии (если у вас более 100 символов, вам нужно будет изменить MAXRECURSION
значение в OPTION
предложении):
DECLARE @YourString varchar(200) = 'abcd12345$@##';
WITH Chars AS(
SELECT V.YourString,
1 AS I,
SS.C,
CASE WHEN SS.C LIKE '[A-z]' THEN 'Letter'
WHEN SS.C LIKE '[0-9]' THEN 'Number'
ELSE 'Special'
END AS CharType
FROM (VALUES(@YourString))V(YourString)
CROSS APPLY (VALUES(SUBSTRING(@YourString,1,1)))SS(C)
UNION ALL
SELECT C.YourString,
C.I 1 AS I,
SS.C,
CASE WHEN SS.C LIKE '[A-z]' THEN 'Letter'
WHEN SS.C LIKE '[0-9]' THEN 'Number'
ELSE 'Special'
END AS CharType
FROM Chars C
CROSS APPLY (VALUES(SUBSTRING(@YourString,C.I 1,1)))SS(C)
WHERE C.I 1 <= LEN(C.YourString))
SELECT STRING_AGG(CASE CharType WHEN 'Letter' THEN C END,'') WITHIN GROUP (ORDER BY I) AS Letters,
STRING_AGG(CASE CharType WHEN 'Number' THEN C END,'') WITHIN GROUP (ORDER BY I) AS Numbers,
STRING_AGG(CASE CharType WHEN 'Special' THEN C END,'') WITHIN GROUP (ORDER BY I) AS Special
FROM Chars
GROUP BY YourString;
Комментарии:
1. @larnuThanks братан, это много значит для меня, и это также очень полезно для меня.
2. Если он отвечает на вопрос, пожалуйста, отметьте его как решение, чтобы будущие читатели знали, что это помогло, спасибо. Хотя я не твой «брат», мы не связаны. (Мой брат ничего не знает о SQL, он работает в сфере доставки).
3. @Kartheek с кратными 10 легко работать. Альтернативным подходом был бы rCTE, но они намного медленнее, чем подсчет , при работе с большими наборами данных, поэтому я использую их только в случае необходимости; это не один из тех случаев.
4. «потому что я должен решить эту проблему с помощью rcte» Вы заявили, что вам нужно использовать CTE, а не rCTE. Я бы придерживался подсчета, как я уже упоминал, они намного быстрее.
5. Извините, человек, которого я не видел, когда комментировал, не могли бы вы решить проблему с помощью rcte