Вывести значения динамических параметров - PullRequest
3 голосов
/ 06 мая 2011

Я использовал динамический SQL для многих задач и постоянно сталкиваюсь с одной и той же проблемой: печать значений переменных, используемых внутри оператора Dynamic T-SQL.

EG:

Declare @SQL nvarchar(max), @Params nvarchar(max), @DebugMode bit, @Foobar int
select @DebugMode=1,@Foobar=364556423

set @SQL='Select @Foobar'
set @Params=N'@Foobar int'

if @DebugMode=1 print @SQL
exec sp_executeSQL @SQL,@Params
    ,@Foobar=@Foobar

Результаты печати приведенного выше кода просто "Выберите @Foobar". Есть ли способ динамически печатать значения и имена переменных выполняемого SQL? Или при выполнении печати замените параметры их фактическими значениями, чтобы SQL можно было повторно запускать?

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

Ответы [ 2 ]

3 голосов
/ 06 мая 2011

Я не верю, что оцененный оператор доступен, что означает, что ваш пример запроса 'Select @FooBar' никогда не сохраняется нигде, как 'Select 364556243'

Даже в трассировке профилировщика вы увидите, что оператор попадет в кеш как '(@Foobar int) select @ foobar'

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

обновлено: Вот шаг в правильном направлении :

Все это можно было бы очистить и обернуть в красивую функцию с входными данными (@Statement, @ParamDef, @ParamVal) и возвращать «подготовленный» оператор. Я оставлю это как упражнение для вас, но, пожалуйста, отправляйте сообщения, когда вы улучшите его!

Здесь используется функция разделения ссылка

set nocount on;

declare @Statement  varchar(100),   -- the raw sql statement
        @ParamDef   varchar(100),   -- the raw param definition
        @ParamVal   xml             -- the ParamName -to- ParamValue mapping as xml


-- the internal params:
declare @YakId int,
        @Date datetime
select  @YakId = 99,
        @Date = getdate();


select  @Statement = 'Select * from dbo.Yak where YakId = @YakId and CreatedOn > @Date;',
        @ParamDef = '@YakId int, @Date datetime';

-- you need to construct this xml manually... maybe use a table var to clean this up
set @ParamVal = (   select *
                    from    (   select '@YakId', cast(@YakId as varchar(max)) union all
                                select '@Date', cast(@Date as varchar(max))
                            ) d (Name, Val)
                    for xml path('Parameter'), root('root')
                )

-- do the work
declare @pStage table (pName varchar(100), pType varchar(25), pVal varchar(100));
;with 
    c_p (p)
    as  (   select  replace(ltrim(rtrim(s)), ' ', '.')
            from    dbo.Split(',', @ParamDef)d
        ),
    c_s (pName, pType)
    as  (   select  parsename(p, 2), parsename(p, 1)
            from    c_p
        ),
    c_v (pName, pVal)
    as  (   select  p.n.value('Name[1]', 'varchar(100)'),
                    p.n.value('Val[1]', 'varchar(100)')
            from    @ParamVal.nodes('root/Parameter')p(n)
        )
insert into @pStage
    select  s.pName, s.pType, case when s.pType = 'datetime' then quotename(v.pVal, '''') else v.pVal end -- expand this case to deal with other types
    from    c_s s
    join    c_v v on
            s.pName = v.pName

-- replace pName with pValue in statement
select  @Statement = replace(@Statement, pName, isnull(pVal, 'null'))                       
from    @pStage
where   charindex(pName, @Statement) > 0;

print @Statement;
2 голосов
/ 06 мая 2011

Что касается того, как большинство людей делают это, я буду говорить только о том, что я делаю:

  • Создайте тестовый сценарий, который будет запускать процедуру с использованием широкого диапазона допустимых и недействительных входных данных.Если параметр является целым числом, я отправлю ему '4' (вместо 4), но я попытаюсь использовать только одно строковое значение, например 'agd'.
  • Запустить значения для набора данных представителяразмер и распределение значений данных для того, что я делаю.Используйте свой любимый инструмент генерации данных (есть несколько хороших на рынке), чтобы ускорить это.
  • Я обычно отлаживаю, как это, на более специальной основе, поэтому собираю результаты из окна результатов SSMSнасколько мне нужно, чтобы взять его.

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

Однако это не так.не все персики и сливки.

Это подходит только для среды разработки, возможно QA, в зависимости от жесткости вашего магазина.

Если запрос занимаетВ течение длительного времени вы можете уменьшить это, добавив «TOP 1», «WHERE 1 = 2» или аналогичное ограничивающее предложение в строку запроса, если @DebugMode = 1. В противном случае, вы можете некоторое время ждать, пока онзаканчивай каждый раз.

Для длинных запросов, когда вы не можете добавить что-либо в строку запроса только для режима отладки, вы можете зафиксировать текст команды в событии StmtStarted, а затем отменить запрос, как только вы получите команду.

Если запрос представляет собой INSERT / UPDATE / DELETE, вам нужно будет выполнить откат, если @DebugMode = 1, и вы не хотите, чтобы изменение происходило.Если вы в данный момент не используете явную транзакцию, это потребует дополнительных затрат.

Если вы пойдете по этому пути, вы сможете добиться некоторой автоматизации, чтобы упростить жизнь.Вы можете создать шаблон для создания трассировки и запуска / остановки действий.Вы можете записать результаты в файл или таблицу и обработать текст команды оттуда программно.

...