PeejayAdams Ответов: 1

Казалось бы, простая замена регулярных выражений SQL - как мне сделать это наиболее читабельным способом?


У меня есть SQL-запрос, который в некоторых случаях извлекает код из описания, например:

SELECT 
    .
    .
    , CASE
	   WHEN taskCodes.task_code IS NOT NULL
		  THEN taskCodes.task_code
		  ELSE
			 CASE 
				WHEN PATINDEX ('%(J[A-Z][0-9]0)%', act.description) > 0 
				    THEN REPLACE (REPLACE (SUBSTRING (act.description, PATINDEX ('%J[A-Z][0-9]0%', act.description), 1000), '(', ''), ')', '')  
			 END 
		  END AS 'Budget Task Code'


Это прекрасно и денди, и это работает.

Теперь в следующем поле инструкции SELECT я хочу преобразовать эти коды вдоль довольно простых строк в другое значение. Если мой код задачи совпадает с JA[1-9]0, Я хочу видеть JA00 как фазовый код, если JB[1-9]0, то JB00 и т. д., Так что это просто случай обнуления того, что будет единственной ненулевой цифрой. Так что все, что мне нужно, это что-то вроде:

, CASE 
	   WHEN taskCodes.phase_code IS NOT NULL 
		  THEN taskCodes.phase_code 
		  ELSE 
			 CASE 
				WHEN PATINDEX ('%(J[A-Z][0-9]0)%', act.description) > 0 
				    THEN
					   --Something to convert the above task code to a phase code	  
				    END 
		  END AS 'Phase Code'


Это звучит так, как будто это должна быть действительно тривиальная задача, но чем больше я смотрю на нее, тем больше я вхожу в эту мерзкую вещь SQL-упаковки -

REPLACE(REPLACE(REPLACE(SUBSTRING(PATINDEX(YADDA,YADDA,YADDA ...))))


.. и код быстро становится нечитаемым до такой степени, что я даже не могу его написать!

Так что то, что должно быть довольно простым преобразованием, превращается в серьезную головную боль (этот код также должен быть повторен в предложении GROUP BY просто для того, чтобы сделать вещи еще более запутанными).

Этот конкретный оператор SELECT является одним из нескольких в довольно длинном объединении (это сценарий миграции данных - производительность не является проблемой, но я бы очень хотел, чтобы он был как можно более читабельным).

Я подозреваю, что самым простым методом было бы бросить начальные результаты во временную таблицу и выполнить преобразование через обновление, но это кажется довольно наивным - это очень простое преобразование, и мне кажется, что я должен быть в состоянии сделать это в запросе.

Может ли кто-нибудь указать мне на оптимальный подход здесь, пожалуйста?

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

Это скорее вопрос о том, как лучше всего подойти к чему-то, чем о том, как это сделать.

1 Ответов

Рейтинг:
2

Richard Deeming

Как насчет чего-то вроде этого:

CASE 
    WHEN taskCodes.phase_code IS NOT NULL THEN taskCodes.phase_code 
    WHEN PATINDEX('%(J[A-Z][0-9]0)%', act.description) > 0 THEN
        STUFF(act.description, PATINDEX('%(J[A-Z][0-9]0)%', act.description) + 3, 1, '0')
END As 'Phase Code'

STUFF (Transact-SQL) | Microsoft Docs[^]

(Если вы действительно хотите, вы можете использование регулярных выражений в SQL через SQLCLR[^]; но это не будет особенно быстро.)


PeejayAdams

- Спасибо, Ричард. Я, конечно, ни о чем таком не думал. В этом случае мне все еще нужно подстроить поле описания вниз к фактическому коду, но это, безусловно, снимает некоторую сложность из уравнения. В конце концов, я использовал CTE и применил последующий перенос на окончательный выбор:

ДЕЛО
Когда PATINDEX ('%J[A-Z][0-9]0%', [код фазы]) > 0
ЗАТЕМ
REPLACE ([Phase Code], SUBSTRING ([Phase Code], PATINDEX('%[1-9]%', [фазовый код]), 1), '0')
ЕЩЕ
[Фазовый Код]
КОНЕЦ
Как [фазовый код]

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