#sql #sql-server #tsql #split #case
Вопрос:
Но учитывая требования:
a~b~c~d~e~f
и O / p, как:
a b
c d
e f
Здесь a, e — нечетное значение, а c — четное значение. Поэтому я попытался использовать этот запрос, используя string_split()
для разделения этого символа ‘~’. Кто-нибудь может помочь?
В этом запросе я не получаю нечетный четный вывод отдельного столбца:
select
C.CID, c.nunique,
Row Number() OVER (ORDER BY C.CID) as RowNum,
CASE
WHEN (ROW Number () OVER(ORDER BY c.CID)) % 2 = 0 THEN s.value
WHEN (Row Number() OVER (ORDER BY c.CID)) % 2 = 1 THEN s.value
ELSE " invalid"
END
from Candidate c
cross apply STRING SPLIT(applist,~) s
Комментарии:
1. Я не могу понять, чего вы хотите. Не могли бы вы вставить пример с входными данными и результатом, пожалуйста?
2. К сожалению
STRING_SPLIT
, может возвращать вложенные строки в любом порядке. Лучший выбор — рекурсивный cte.
Ответ №1:
Ответ:
Вам нужно разделить сохраненную последовательность, используя разделитель, чтобы получить подстроки и порядок подстрок. Здесь может помочь подход, основанный на JSON — просто преобразуйте текст в допустимый массив JSON ( a~b~c~d~e~f
into ["a","b","c","d","e","f"]'
) и проанализируйте массив с OPENJSON()
помощью . Результатом OPENJSON()
вызова является таблица со столбцами key
, value
type
а в случае массива JSON key
столбец содержит индекс каждого элемента в массиве на основе 0:
SELECT c.cid, j.odd, j.even
FROM (VALUES (1, 'a~b~c~d~e~f')) c (cid, applist)
CROSS APPLY (
SELECT
MIN(CASE WHEN CONVERT(int, [key]) % 2 = 0 THEN [value] END) AS [odd],
MIN(CASE WHEN CONVERT(int, [key]) % 2 = 1 THEN [value] END) AS [even]
FROM OPENJSON(CONCAT('["', REPLACE(c.applist, '~', '","'), '"]'))
GROUP BY CONVERT(int, [key]) / 2
) j
Результат:
cid odd even
1 a b
1 c d
1 e f
Обновить:
Если подход, основанный на JSON, не подходит, может помочь рекурсивный CTE:
CREATE TABLE Candidate (cid int, applist varchar(max))
INSERT INTO Candidate (cid, applist)
VALUES (1, 'a~b~c~d~e~f'), (2, 'g~h~i~i')
;WITH rCTE AS (
SELECT
c.cid,
LEFT(CONCAT(c.applist, '~'), CHARINDEX('~', CONCAT(c.applist, '~')) - 1) AS substring,
STUFF(CONCAT(c.applist, '~'), 1, CHARINDEX('~', CONCAT(c.applist, '~')), '') AS remaining,
0 AS position
FROM Candidate c
UNION ALL
SELECT
r.cid,
LEFT(r.remaining, CHARINDEX('~', r.remaining) - 1),
STUFF(r.remaining, 1, CHARINDEX('~', r.remaining), ''),
r.position 1
FROM rCTE r
WHERE LEN(r.remaining) > 0
)
SELECT
cid,
MIN(CASE WHEN position % 2 = 0 THEN [substring] END) AS [odd],
MIN(CASE WHEN position % 2 = 1 THEN [substring] END) AS [even]
FROM rCTE
GROUP BY cid, position / 2
OPTION (MAXRECURSION 0);
Использование STRING_SPLIT()
:
Обратите внимание, что, хотя STRING_SPLIT()
это и опция, используйте эту функцию осторожно, потому что, как указано в документации, выходные строки могут располагаться в любом порядке, и порядок не гарантируется, чтобы соответствовать порядку подстрок во входной строке.
SELECT
c.cid,
MIN(CASE WHEN rn % 2 = 0 THEN [value] END) AS [odd],
MIN(CASE WHEN rn % 2 = 1 THEN [value] END) AS [even]
FROM (VALUES
(1, 'a~b~c~d~e~f'),
(2, 'g~h~i~i')
) c (cid, applist)
CROSS APPLY (
SELECT [value], ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1 rn
FROM STRING_SPLIT(c.applist, '~')
) s
GROUP BY c.cid, s.rn / 2
Комментарии:
1. Спасибо за ответ! это действительно полезно, и результат, который вы показали, идеален.. но мое требование — решить без использования OpenJson ()
2. Большое спасибо за объяснение этих 3 разных методов решения моего вопроса… Метод CTE помог мне набрать больше баллов.