Move data between job steps

انتقال داده ها میان Stepهای SQL Server Agent Job

گاهی اوقات، ممکن است یک الزام تجاری وجود داشته باشد که در یک SQL Server Agent Job، بخواهیم یک مقدار پارامتر یا چندین مقدار را از Step 1 به Step 2 منتقل کنیم. به عنوان مثال، در Step 1 یک Job، من یک رکورد را به جدولی با یک ستون  identity وارد می کنم و من می‌خواهم مقدار identitty که به تازگی درج شده است، یعنی ()scope_identity را به Step بعدی آن Job منتقل کنم.

انواع مختلفی از Stepهای SQL Server Agent Job وجود دارد، مانند ActiveX Script، PowerShell script، پکیج های SSIS، اسکریپت T-SQL و غیره، از بین این Job Stepها، احتمالاً سخت ترین آنها نوع T-SQL Script است. T-SQL معمولاً راه آسانی برای نوشتن اطلاعات خارج از محدوده برای Step های بعدی ندارد، در حالی که ActiveX Script، PowerShell وپکیج SSIS می توانند به راحتی یک فایل خارجی یا حتی دسترسی به متغیرهای محیط سیستم عامل برای اهداف تبادل داده ایجاد کنند. .

بنابراین چه راه حلی برای رسیدگی به این مشکل تبادل داده برای استپ های جاب از نوع T-SQL داریم؟

در واقع، یک راه معمول برای انجام این کار وجود دارد، یعنی ایجاد یک جدول دائمی و سپس استفاده از این جدول به عنوان “رابط” یا “پیام‌رسان” برای تبادل داده بین استپ های جاب. این رویکرد اشکالی ندارد، با این حال، ممکن است راه‌های دیگری نیز وجود داشته باشد که انعطاف‌پذیرتر و قوی‌تر با کار کمتر یا همسویی بهتر با الزامات تجاری باشد.

ما این راه حل های بالقوه را به جز استفاده از جدول دائمی بررسی خواهیم کرد.

ما فرض می کنیم که می خواهیم دو پارامتر را ارسال کنیم، یکی پارامتر عدد صحیح، parmInt@ و دیگری یک پارامتر رشته، parmStr@.

برای اهداف آزمایشی، فرض می کنیم که یک Job با دو Step داریم و مقادیر را از Step 1 به Step 2 منتقل می کنیم.

روش 1: انتقال داده ها  از طریق یک Extended Proeprty بین استپهای جاب Agent SQL Server 

یک Etended Proeprty مکان خوبی برای ذخیره مقادیر موقتی است زیرا هدف اولیه آن برای “مستندسازی” اشیاء پایگاه داده است.

برای ساده‌تر کردن کارها، Etended Proeprtyها را به TempDB اضافه می‌کنیم تا داده‌ها را بین استپ ها ارسال کنیم.

بنابراین، در Step 1 جاب، این اسکریپت را داریم:

if exists (select * from tempdb.sys.extended_properties where class=0 and name=’parmInt’)

   ‘exec tempdb.sys.sp_dropextendedproperty @name=’parmInt

if exists (select * from tempdb.sys.extended_properties where class=0 and name=’parmStr’)

   ‘exec tempdb.sys.sp_dropextendedproperty @name=’parmStr

EXEC tempdb.sys.sp_addextendedproperty  

@ ,’name = N’parmStr@  

value = ‘HelloWorld’; —  assuming ‘HelloWorld’ is what we want to pass

EXEC tempdb.sys.sp_addextendedproperty  

@ ,’name = N’parmInt@  

value = ‘123’; — assuming ‘123’ is what we want to pass

در استپ 2 job، می توانیم از اسکریپت زیر برای بازیابی مقادیر استفاده کنیم:

declare @parmInt int, @parmStr varchar(128) 

select @parmInt = cast([value] as int) from tempdb.sys.fn_listextendedproperty(‘parmInt’, null, null, null, null, null, null) 

select @parmStr = cast([value] as varchar(128)) from tempdb.sys.fn_listextendedproperty(‘parmStr’, null, null, null, null, null, null)

*/

 other regular business processing with @parmInt and @parmStr

 you can even drop these Eps after the work is done using sp_dropextendedproperty

/*

روش 2: ارسال مقادیر از طریق Error Log بین استپهای جاب Agent SQL Server

در این روش مقدار پارامتر را در Error log می نویسیم و سپس در استپ بعدی جاب از Log error SQL Server آنرا می خوانیم.

بنابراین در استپ 1، با استفاده از raiserror..with Log  در لاگ می نویسیم. “with log” پیام را در error Log SQL Server خواهد نوشت.

برای عبارت raiserror، اگر level severity را 0 (یا 10) قرار دهیم، step job شکست نمی خورد و در چنین مواردی، raiserror خودش فقط برای نوشتن اطلاعاتی در error log است.

بنابراین، در استپ 1، کد زیر را داریم:

*/

other business logic block

now we want to pass values to next step

/*

‘declare @parmInt int = 1234, @parmStr varchar(128) = ‘hello world

raiserror (‘@parmInt = %d;; @parmStr = %s’, 10, 1, @parmInt, @parmStr) with log

و در error Log SQL Server ما مشاهده میکنیم:

using error log to store parameter values

در استپ بعد می توانیم کد زیر را برای بازیابی داده ها بر اساس فرمت داده از استپ 1 اجرا کنیم:

;set nocount on

declare @t table (LogDate datetime, ProcessInfo varchar(100), [text] varchar(300))

 insert into @t (LogDate, ProcessInfo, [Text])

‘exec master.sys.sp_readerrorlog 0, 1, ‘parmInt 

;declare @parmInt int, @parmStr varchar(128) 

select top 1 @parmInt = cast(substring([text], len(‘@parmInt = ‘)+1, charindex(‘;;’, [text])-len(‘@parmInt = ‘)-1) as int), @parmStr = substring([text], charindex(‘@parmstr = ‘, [text])+len(‘@parmStr = ‘)+1, 128)

from @t

order by LogDate desc; — find the most recent data

raiserror(‘@parmInt = %d’, 0, 1, @parmInt) with nowait; — for debug purpose

raiserror(‘@parmStr = %s’, 0, 1, @parmStr) with nowait; — for debug purpose

*/

 the result is exactly as expected@parmInt = 1234@parmStr = hello world

/*

روش 3: ارسال مقدار از طریق ویژگی Job Description بین استپ های جاب Agent SQL Server

ما می دانیم که هر Job Agent SQL Server دارای یک بخش توضیحات است که در زیر مشخص شده است.

sql job description

ما در واقع می توانیم از این بخش برای انتقال داده ها استفاده کنیم. تنها چیزی که باید بدانیم این است که بسیاری از جاب ها ممکن است قبلاً از این بخش استفاده کنند، بنابراین باید داده ها را به اطلاعات موجود اضافه کنیم و بعد از بازیابی مقادیر پارامتر، آنها را پاکسازی کنیم.

در استپ 1، ما کد زیر را داریم که در آن، از توکن جاب ” (ESCAPE_SQUOTE(JOBNAME))$” استفاده می کنیم.

*/

The regular business codes

 the following is to put parameter values into job description section

/*

 declare @parmInt int, @parmStr varchar(128)

— assume we need to pass the following data to next step

;’select @parmInt = 123, @parmStr = ‘hello world

;declare @desc nvarchar(512)

;declare @crlf char(2) = char(0x0d) + char(0x0a)

select @desc = description from msdb.dbo.sysjobs where name = ‘$(ESCAPE_SQUOTE(JOBNAME))

;print @desc

 append the info —

set @desc = @desc + @crlf + ‘@parmInt = ‘ + cast(@parmInt as varchar(20)) + ‘;’ + @crlf

set @desc = @desc + ‘@parmStr = ‘ + @parmStr + ‘;’ + @crlf

 — update the job description with newly appended data

exec msdb.dbo.sp_update_job @job_name = ‘$(ESCAPE_SQUOTE(JOBNAME))‘, @description = @desc

اگر شرح جاب اولیه ما مانند زیر باشد:

sql job description

پس از اجرای استپ 1 جاب، بخش توضیحات اصلاح شده را به صورت زیر مشاهده خواهیم کرد:

sql job description

در استپ 2، می توانیم اطلاعات ضمیمه شده را با کد زیر بازیابی کنیم:

;declare @parmInt int, @parmStr varchar(128)

;declare @desc nvarchar(512)

 select @desc = description from msdb.dbo.sysjobs where name = ‘$(ESCAPE_SQUOTE(JOBNAME))’

select @parmInt=cast(substring(@desc, charindex(‘@parmInt’, @desc)+len(‘@parmInt = ‘)+1, charindex(‘;’, @desc, charindex(‘@parmInt’, @desc))-charindex(‘@parmInt’, @desc) – len(‘@parmInt = ‘)-1 ) as int), @parmStr = substring(@desc, charindex(‘@parmStr’, @desc)+len(‘@parmStr = ‘)+1, charindex(‘;’, @desc, charindex(‘@parmStr’, @desc))-charindex(‘@parmStr’, @desc) – len(‘@parmStr = ‘)-1 ) 

raiserror(‘@parmInt = %d’, 0, 1, @parmInt) with nowait; — for debug purpose

raiserror(‘@parmStr = %s’, 0, 1, @parmStr) with nowait; — for debug purpose

*/

  the result is exactly as expected

 parmInt = 123@

parmStr = hello world@

/*

روش 4: انتقال مقدار از طریق فایل خارجی بین استپ های جاب Agnet SQL Server

در این روش از دو فرآیند استفاده خواهیم کرد، یکی استفاده از sqlcmd.exe و گزینه -o آن برای خروجی و تولید فایل در استپ 1 جاب و دیگری استفاده از bulk insert برای وارد کردن فایل تولید شده در استپ 2.

برای اثبات مفهوم، می‌توانیم دستور sqlcmd زیر را در استپ 1 جاب اجرا کنیم، که نوع آن باید Operating System (CmdExec) باشد.

sql job step to write parameters to a file

sqlcmd.exe -S localhost\sql2022 -d master -Q “set nocount on; select  parmInt=1234, parmStr=’hello world'” -o c:\temp\dataExch.txt -s 

‘|’

نتیجه تولید یک فایل csv از نوع c:\temp\dataExch.txt است و اگر این فایل متنی را در Notepad باز کنیم، این را خواهیم دید:

text file with parameter values

می بینیم که فایل از سه خط تشکیل شده است که خط اول برای نام متغیر، خط دوم جداکننده (delimiter) و خط سوم حاوی مقادیر است. ما از ‘|’ (نوار عمودی) به عنوان جداکننده فیلد استفاده می کنیم.

;if object_id(‘tempdb..#t’, ‘U’) is not null   drop table #t

create table #t (col_1 int, col_2 varchar(128))

 set nocount on

BULK INSERT #t

FROM ‘c:\temp\dataExch.txt’    WITH    (      FIELDTERMINATOR =’|’,    ROWTERMINATOR =’\n’ ,  FIRSTROW =3 — so we omit the column header line and the separator line )  

 declare @parmInt int, @parmStr varchar(128) — we will populate these two params

;select top 1 @parmInt = col_1, @parmStr = col_2 from #t

raiserror(‘@parmInt = %d’, 0, 1, @parmInt) with nowait; — for debug purpose

raiserror(‘@parmStr = %s’, 0, 1, @parmStr) with nowait; — for debug purpose

*/

 the result is exactly as expected

     parmInt = 1234@

parmStr = hello world@

/*

برچسب ها: بدون برچسب

نظر بگذارید

آدرس ایمیل شما منتشر نخواهد شد. قسمتهای مورد نیاز علامت گذاری شده اند *