Я хочу знать, как разделить символы Digits и специальные символы в Sql Server с помощью CTE?

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

db<>скрипка

Также обратите внимание на использование пробелов, чтобы вы могли четко видеть, где начинается один 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;
  

db<>скрипка

Комментарии:

1. @larnuThanks братан, это много значит для меня, и это также очень полезно для меня.

2. Если он отвечает на вопрос, пожалуйста, отметьте его как решение, чтобы будущие читатели знали, что это помогло, спасибо. Хотя я не твой «брат», мы не связаны. (Мой брат ничего не знает о SQL, он работает в сфере доставки).

3. @Kartheek с кратными 10 легко работать. Альтернативным подходом был бы rCTE, но они намного медленнее, чем подсчет , при работе с большими наборами данных, поэтому я использую их только в случае необходимости; это не один из тех случаев.

4. «потому что я должен решить эту проблему с помощью rcte» Вы заявили, что вам нужно использовать CTE, а не rCTE. Я бы придерживался подсчета, как я уже упоминал, они намного быстрее.

5. Извините, человек, которого я не видел, когда комментировал, не могли бы вы решить проблему с помощью rcte