Jesper Schlütter Ответов: 5

Найдите последний код 2end в строке, разделенной запятыми.


В моем sql-операторе я хочу проверить только последний код 2end в строке, разделенной запятыми. суммы могут различаться.

В этом примере я только то, что нужно проверить "CX" против списка кодов.


когда instr('AX,BX,CX,DX', код) > 0

Что я уже пробовал:

я попытался найти решение в Google

5 Ответов

Рейтинг:
2

OriginalGriff

Во - первых, обработка строк SQL в лучшем случае плохая, поэтому любой дизайн, который хранит CSV-данные в Столбцах SQL, должен рассматриваться с крайним скептицизмом-он, вероятно, плохо спроектирован и должен использовать отдельную таблицу с внешним ключом обратно к оригиналу.

Нет никакого "хорошего" решения, но вы можете использовать это: Преобразование данных, разделенных запятыми в столбце, в строки для выбора[^] Как только у вас есть данные в виде временной таблицы, вы можете выбрать из нее любой необходимый вам элемент.

Но я бы серьезно подумал о том, чтобы перепроектировать БД, чтобы избавиться от CSV - данных-это только первая из многих неприятных проблем, которые она вызовет.


Jesper Schlütter

Спасибо за ваш ответ.

База данных-это не проблема, в таблице кода нет данных, разделенных запятыми.
Строка, разделенная запятыми, исходит из XML-сообщения (которое я не могу контролировать), где мне нужно проверить, существует ли 2-й последний код в строке в таблице кодов.

Рейтинг:
2

MadMyche

То, что вы собираетесь сделать, это использовать функцию разделения строк. Самый простой способ сделать это-использовать несколько запросов; первый-преобразовать строку в строки, а последний-получить конкретную строку.

SQL Server 2016 имеет встроенную эту функцию, называемую STRING_SPLIT
STRING_SPLIT (Transact-SQL) | Microsoft Docs[^]
В других версиях SQL могут быть установлены аналогичные функции, некоторые из них лучше, чем теперь родная функция. SQL Server Central имеет довольно много и документацию по их тестированию.

Это очень быстрая и уродливая процедура, в которой есть основы того, что вы хотите. Как только это будет понято, это должно быть переработано.

Я оставляю его неочищенным, чтобы вы могли видеть основы операций, которые необходимы, что усиливает OriginalGriffутверждение о том, что строковые функции просто не являются сильной стороной SQLs.
Вам было бы гораздо лучше работать на C# или любом другом языке и преобразовывать это в массив, а затем вы можете просто захватить любое значение по индексу

DECLARE @ElementCount INT =0
DECLARE @CSV NVARCHAR(1000) = 'AX,BX,CX,DX'
DECLARE @DesiredValue NVARCHAR(100)

DECLARE @SplitTable TABLE(idx INT IDENTITY(1,1) NOT NULL, Element NVARCHAR(100))

INSERT @SplitTable SELECT val FROM STRING_SPLIT(@CSV, ',')
SET @ElementCount = @@RowCount

SELECT @DesiredValue = val FROM @SplitTable WHERE idx = @ElementCount -1 

PRINT @DesiredValue


Рейтинг:
2

kirthiga S

Declare @code varchar(20)='AX,BX,CX,DX'
Declare @FirstRemCode varchar(20),@SecondRemCode varchar(20)
select @FirstRemCode=RIGHT(@code,LEN(@code)-charindex(',',@code))
select @SecondRemCode=RIGHT(@FirstRemCode,LEN(@FirstRemCode)-charindex(',',@FirstRemCode))
select LEFT(@SecondRemCode,charindex(',',@SecondRemCode)-1) Code


CHill60

ОП сказал:количество кодов варьируется.Если я выполню ваш код с помощью @code='AX,BX,CX,DX' затем он возвращается CX как и ожидалось, но если я запущу его с @code = 'AX,BX,CX,DX,XX' он по-прежнему возвращает CX вместо ДУПЛЕКСНЫЙ Другими словами, ваше решение не работает

Рейтинг:
1

kirthiga S

Я надеюсь, что это будет работать, даже размер кода меняется

Declare @code varchar(20) ='AX,BX,CX,DX,XX'
;with cte as (
select 1 SNO,LEFT(@code,charindex(',',@code)-1)Code,RIGHT(@code,LEN(@code)-charindex(',',@code))RemCode
union all
select SNO+1,LEFT(RemCode,charindex(',',RemCode)-1),RIGHT(RemCode,LEN(RemCode)-charindex(',',RemCode))from cte where @code is Not null and charindex(',',RemCode)>0
)select Code from cte where SNO=(select max(SNO) from cte)


CHill60

Знаете ли вы, что вы можете использовать ссылку "улучшить решение" для добавления информации к вашему исходному решению? Это лучше, чем публиковать другое решение, потому что это делает его более ясным, что вы переосмыслили сценарий и показываете свой мыслительный процесс - это менее запутанно для читателей.

Однако причина моего голосования-4. Это довольно элегантное решение, если вы углубитесь в него. Он работает для различного количества элементов >= 2 (в то время как мое решение фактически потерпит неудачу, если количество элементов = 2)

Лично я бы объяснил, что решение использует рекурсивное общее табличное выражение для генерации последовательности или списка большинства составных частей в исходной строке (последняя опущена из-за проверки and charindex(',',RemCode)>0 Каждому элементу присваивается номер в том CTE, который представляет его позицию в строке. Затем вы просто выбираете последний элемент в последовательности, чтобы получить желаемый результат.

Другими словами - вы добавляете больше ценности, если объясняете, Как добраться до решения, а не просто сбрасываете код

Рейтинг:
1

CHill60

Какое решение 3 пытался сделать и вариант, если у вас есть более ранняя версия SQL, чем 2016 (но 2008 или выше). В основном переверните строку и удалите (теперь) первый элемент, вернув новый первый элемент обратно (назад, как это было)...

Declare @code varchar(20)='AX,BX,CX,DX,XX'
Declare @revCode varchar(20) = REVERSE(@code)
set @revCode  = SUBSTRING(@revCode, CHARINDEX(',',@revCode) + 1, LEN(@revCode))
set @revCode = REVERSE(LEFT(@revCode, CHARINDEX(',', @revCode) - 1))
select @revCode -- DX
Но я с другими, которые предложили сделать это в вызывающем слое, а не в SQL, если это вообще возможно.