Рейтинг:
6
CHill60
Альтернатива решению 1, но вы, возможно, не сможете его реализовать.
Я также был в положении, когда я унаследовал" постоянную " таблицу данных, где столбцы использовались таким образом. К счастью, я был в состоянии сменить стол, так как он использовался только в одном месте.
Если вам тоже так повезло, могу ли я предложить изменить таблицу SYSPAR_NML11 с таблицы с 12 столбцами и 1 строкой на таблицу с 2 столбцами и 12 строками ...
create table SYSPAR_NML11_Replacement
(
period int,
period_descr varchar(16)
)
Который вы можете заполнить из оригинала
INSERT INTO SYSPAR_NML11_REPLACEMENT
SELECT 1 as O, period_descr_1 as period_descr FROM SYSPAR_NML11_Original UNION SELECT 2, period_descr_2 FROM SYSPAR_NML11_Original UNION
SELECT 3, period_descr_3 FROM SYSPAR_NML11_Original UNION SELECT 4, period_descr_4 FROM SYSPAR_NML11_Original UNION
SELECT 5, period_descr_5 FROM SYSPAR_NML11_Original UNION SELECT 6, period_descr_6 FROM SYSPAR_NML11_Original UNION
SELECT 7, period_descr_7 FROM SYSPAR_NML11_Original UNION SELECT 8, period_descr_8 FROM SYSPAR_NML11_Original UNION
SELECT 9, period_descr_9 FROM SYSPAR_NML11_Original UNION SELECT 10, period_descr_10 FROM SYSPAR_NML11_Original UNION
SELECT 11, period_descr_11 FROM SYSPAR_NML11_Original UNION SELECT 12, period_descr_12 FROM SYSPAR_NML11_Original
ORDER BY 1
Тогда весь выбор становится очень простым:
declare @period int = 10
declare @RetVal varchar(16)
SELECT @RetVal = period_descr from SYSPAR_NML11_REPLACEMENT WHERE period = @period
select ISNULL(@RetVal, 'Out of range')
На самом деле вы, вероятно, вообще обойдетесь без этой функции.
Вы, вероятно, найдете другие таблицы параметров, которые делают подобные вещи - опять же, если вы можете повлиять на схему, поощряйте их изменение с многоколоночных мерзостей на что-то вроде:
create table SYS_PARMS
(
id int identity(1,1),
parm_descr nvarchar(125),
parm_value nvarchar(125),
parm_comment nvarchar(125)
)
и т. д. и т. д.
[РЕДАКТИРОВАТЬ]
OP, к сожалению, подтвердил, что они не могут настроить схему таблицы.
Однако, используя
UNPIVOT
мы можем создать временную таблицу в нужном нам формате:
IF OBJECT_ID('tempdb..#temp') IS NOT NULL
DROP TABLE #temp
create table #temp (period int identity(0,1), Descrip nvarchar(16))
insert into #temp
select u.period
from SYSPAR_NML11 s
unpivot
(
period for Descrip in (period_descr_0,period_descr_1,period_descr_2,
period_descr_3,period_descr_4,period_descr_5,
period_descr_6,period_descr_7,period_descr_8,
period_descr_9,period_descr_10,period_descr_11,
period_descr_12)
) u;
declare @RetVal varchar(16)
SELECT @RetVal = Descrip from #temp WHERE period = @period
select ISNULL(@RetVal, 'Out of range')
Kornfeld Eliyahu Peter
Для меня смена схемы всегда была мечтой, даже она оказалась лучшим решением для всех...: thumbsup:
CHill60
"всегда мечта"... Так что правда, как правило! Пытаясь убедить менеджера, который ничего не знает о реляционных базах данных, что схема просто ужасна, но когда она была разработана их любимым "экспертом" (читай ... парень с которым они играют в гольф)
pkfox
К сожалению я не могу изменить схему но спасибо за ваш ответ
CHill60
Это позор. Однако я разработал альтернативу - см. мое пересмотренное решение после "[EDIT]"
pkfox
Где вы объявляете #temp ? кроме того, в таблице нет столбца периода, только period_desc_0 ... и т. д
CHill60
#temp генерируется запросом. Как временная таблица, созданная select...into
его не нужно ни объявлять, ни создавать заранее.
В столбце период #темп генерируется от отмены свертывания.
Попробуйте сделать это вне функции и просто запросите таблицу#temp, чтобы увидеть, что произойдет.
Это можно расширить, если эта таблица данных получает дополнительные столбцы, вам нужно только добавить имя столбца в unpivot
pkfox
Хорошо спасибо за разъяснение
pkfox
Привет я попробовал ваш код и получил эту ошибку
(13 строк) затронуты)
Msg 245, Уровень 16, Состояние 1, Строка 17
Ошибка преобразования в тип varchar значение 'описание 0' в тип данных int.
IF OBJECT_ID ('tempdb..#temp') НЕ ЯВЛЯЕТСЯ НУЛЕВЫМ
DROP TABLE #temp
выберите u. Descrip, u. period
В #temp
из описания
оператор UNPIVOT
(
период для описания в (period_descr_0, period_descr_1,period_descr_2,
period_descr_3, period_descr_4,period_descr_5,
period_descr_6, period_descr_7,period_descr_8,
period_descr_9, period_descr_10,period_descr_11,period_descr_12)
) у;
объявить @period int = 1
объявить @RetVal varchar(16)
Выберите @RetVal = Descrip из #temp, где period = @period
выберите ISNULL(@RetVal, 'Out of range')
CHill60
Мои извинения, у меня были цифры в поле описания, и код сделал неявное преобразование, которое я полностью пропустил.
Я обновил ответ, чтобы исправить ошибку.
pkfox
вот к чему я пришел, основываясь на вашем предложении
Создайте функцию [dbo].[GetDescription] (@Period int)
Возвращает varchar(16)
АС
НАЧАТЬ
Объявить @RetVal varchar(110);
DECLARE @tempTable table (period int identity(0,1), period_descr varchar(16))
вставить в @tempTable
выберите u. период
из описания с
оператор UNPIVOT
(
период для описания в (period_descr_0, period_descr_1,period_descr_2,
period_descr_3, period_descr_4,period_descr_5,
period_descr_6, period_descr_7,period_descr_8,
period_descr_9, period_descr_10,period_descr_11,
period_descr_12)
) у;
Выберите @код = period_descr от @поддающийся соблазну где период = @период
возвращение @RetVal
КОНЕЦ
Большое спасибо за вашу помощь, я даже не слышал о unpivot ! очень полезная информация, в качестве примечания вы не можете использовать временные таблицы #temp в функции
CHill60
*хлопает по голове* - еще раз извини! Без временных таблиц в функции ловит меня каждый раз. Однако вы нашли переменную workaround - table.
Я слышал о unpivot довольно давно, но это первый раз, когда я использовал его для реальной проблемы...думаю, это показывает! ;-)
Рейтинг:
12
Kornfeld Eliyahu Peter
Я бы сказал, что динамический SQL может помочь вам здесь...
DECLARE @PERIOD INT = 1
DECLARE @SQL AS NVARCHAR(MAX)
DECLARE @RETVAL VARCHAR(16)
SET @SQL = 'SELECT @RV = PERIOD_DESCR_' + CAST(@PERIOD AS NVARCHAR) + ' FROM SYSPAR_NML11'
EXECUTE sp_executesql @SQL, N'@RV VARCHAR(16) OUT', @RV = @RETVAL OUT
SELECT @RETVAL
sp_executesql (Transact-SQL) | Microsoft Docs[
^]
pkfox
Привет, Питер, к сожалению, вы не можете использовать sp_executesql в функции-спасибо за ваш ответ
Kornfeld Eliyahu Peter
Я бы не сказал, что это намного элегантнее, но вы можете создать такой вид:
SELECT 0, (SELECT TOP 1 PERIOD_DESCR_0 FROM SYSPAR_NML11) UNION
SELECT 1, (SELECT TOP 1 PERIOD_DESCR_1 FROM SYSPAR_NML11) UNION
ВЫБЕРИТЕ 2, (ВЫБРАТЬ ПЕРВЫЕ 1 PERIOD_DESCR_2 ОТ SYSPAR_NML11) СОЮЗ
SELECT 3, (SELECT TOP 1 PERIOD_DESCR_3 FROM SYSPAR_NML11) UNION
ВЫБЕРИТЕ 4, (ВЫБРАТЬ ПЕРВЫЕ 1 PERIOD_DESCR_4 ОТ SYSPAR_NML11) ...
И идите с раствором из CHill60 оттуда...
CHill60
Я обновил его - использовал UNPIVOT, чтобы сделать что-то подобное. Первый раз я использовал UNPIVOT в гневе! :-)
Kornfeld Eliyahu Peter
Спасибо...