Custom Schedule for an Agent Job

When you have a need to run an agent job on a quarterly schedule, you will find out that there is not an available template you can choose from the UI.

One way you can reach this goal is to add a first step to check month before the normal job step(s).

You can modify your existing job to add a step as start step and use the following T-SQL command to generate error by design.

If the schedule is not what you need, generate an errorĀ  in the code.

Configure the step to continue to next step if success; quit and report success if it fails.

Your other steps in your job will not run if it is not on schedule.

Here is the T-SQL code for step one to check quarter start months.


declare @rundt datetime=getdate()
If month(@rundt) not in (1,4,7,10)
THROW 51000,'Job cannot be executed on this month',1;


Use JSON to Simulate String_Agg in SQL Server 2016


Declare @table1
table(TableId int, SId int, Data varchar(200), DataOwner int)
insert into @table1 values
(1, 10, 'aaaa', 1001)
,(2, 10, 'aaaa', 1000)
,(3, 20, 'bbbb', 1000)
,(4, 10, 'ccc', 2000)
;with mycte as (
select Distinct SId , Data, DataOwner
from @table1
)
,mycte2 as (
SELECT SId , Data, (SELECT Vals = JSON_QUERY(
(
SELECT Cast(DataOwner as varchar(30)) DataOwner
FROM mycte t2 WHERE t2.SId = t1.SId and t2.Data = t1.Data
FOR JSON PATH )
) FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
) jsCol
FROM mycte t1
Group by SId , Data)
select SId , Data,
Concat(JSON_VALUE (jsCol,'$.Vals[0].DataOwner'),
','+JSON_VALUE (jsCol,'$.Vals[1].DataOwner'),
','+JSON_VALUE (jsCol,'$.Vals[2].DataOwner'),
','+JSON_VALUE (jsCol,'$.Vals[3].DataOwner') ) DataOwner
from mycte2


SUM SUM OVER Sample Code


create table WeekSales(dt datetime, Amount decimal(8,2))
insert into WeekSales values(getdate()-15, 100),(getdate()+0, 100)
,(getdate()-14, 100),(getdate()-23, 100),(getdate()-3, 100),(getdate()-3, 100)
,(getdate()-23, 100),(getdate()+41, 100),(getdate()+11, 100),(getdate()+1, 100)
,(getdate()-52, 100),(getdate()+10, 100),(getdate()+20, 100),(getdate()+0, 100)
,(getdate()-61, 100),(getdate()+53, 100),(getdate()+33, 100),(getdate()+3, 100)
,(getdate()+64, 100),(getdate()+43, 100),(getdate()+46, 100),(getdate()+6, 100)
,(getdate()+53, 100),(getdate()+33, 100),(getdate()+13, 100),(getdate()+12, 100)
,(getdate()+42, 100),(getdate()+23, 100),(getdate()+23, 100),(getdate()+24, 100)
,(getdate()+2, 100),(getdate()+4, 100),(getdate()+5, 100),(getdate()+6, 100)
,(getdate()+3, 100)
select
datename(weekday,dt) Day_Name
,SUM(Amount) Amt
,SUM(SUM(Amount)) OVER() AS sumsumTotal
, SUM(Amount)*1. / SUM(SUM(Amount )) OVER() [Weekdaypercent]
,SUM(SUM(Amount )) OVER(Order by datepart(weekday,dt)) sumsumRunningTotal
FROM WeekSales f
WHERE dt>=dateadd(day,-15,getdate()) and dt<dateadd(day,15,getdate())
GROUP BY datename(weekday,dt),datepart(weekday,dt)
drop table WeekSales


How to Delete Folder with Files from Bitbucket

From Bitbucket repository on the left, select Source<>.
On the right, select the Folder and expand the folder to see files;

Select a file and from arrow beside Edit and select Delete>> Commit.
REPEAT this process to delete each file;

From Bitbucket repository on the left, select Source<> again;

Observe that an empty folder is automatically removed from a git repository!


Parse Data with JSON

Declare @rept table(Id int Identity(1,1), ReptDesc varchar(max))
Insert into @rept (ReptDesc)
Values(
'Category: Projects; Accounting and Operations; Sales
Description: this is a transaction report'),
('Category: Technical, Accounting
Description:'),
('Category: Accounting'),
('Category: Accounting, Sales'),
(Null),
(Null)
–SQL Server 2016 or up versions
;with mycte as (
Select * , replace(replace(replace(replace(replace(replace(ReptDesc,char(10),''),char(13),''),
'Category:','{"Category":["'),',','","'), ';','","'),'Description:','"], "Description":["')+'"]}' jsonCol
from @rept
)
select id
,c.value as Category
,d.value as Description
from mycte
CROSS APPLY OPENJSON(jsoncol, '$.Category') AS c
Outer APPLY OPENJSON(jsoncol, '$.Description') AS d
/*
id Category Description
1 Projects this is a transaction report
1 Accounting and Operations this is a transaction report
1 Sales this is a transaction report
2 Technical
2 Accounting
3 Accounting NULL
4 Accounting NULL
4 Sales NULL
*/

https://social.msdn.microsoft.com/Forums/en-US/040c64dc-87eb-4d51-abbb-6ecf2c8f23c0/parse-data-from-a-table-row-and-output-the-values-formatted?forum=transactsql


Custom Reports from SSMS for SQL Server Assessment

It is our pleasure from Iowa SQL Server Users Group (IASSUG) to have Dave Bland as speaker for Des Moines PASS August 10 Meeting:

“How to do a Complete Server Assessment”

He created a series of custom SSRS reports and offered to use them from SSMS with a few clicks to access bunch of information about your server and database.

You can download the source reports from a zipped folder at Dave Bland’s blog site:

SQL Server Assessment Using SSMS and SSRS

After you download the file and unzip it a your local drive to the SSMS file folder for easy access.

Launch your SSMS and connect to an Instance(Server). Right click on Instance name(or database name) and choose the Reports>Custom Reports… and browser to the files you unzipped.

Click on the first report _LaunchingPage.rdl and you are launching the Main report page.

Your journey starts here.

I will run this report on a few new 2019 servers I set up recently to view lot of useful information in a very short time.

During the presentation, Dave walked through some interested reports and their use cases. I have come across many of them from my DBA career and I know Dave did a great favor for SQL Server community with this handy report tool.

Thanks Dave!


Split with JSON in One Column


CREATE TABLE #TEST
(OrderITEM NVARCHAR(MAX), CustomerId INT, OrderDate DATETIME)
GO
INSERT INTO #TEST(OrderITEM, CustomerId,OrderDate)
VALUES('A-100 A-105 C-100' ,1,Getdate()-30),
('A-111 A-102 D-201' ,2,Getdate()-5),
('D-400 G-10 F-220' ,3,Getdate()-20),
('H-801 M-451 D-201' ,1,Getdate()-3),
('F-701 A-102 D-201' ,4,Getdate()-6),
('G-11 A-102 D-201' ,5, Getdate()-10),
('B-710' ,6, Getdate())
select CustomerId,OrderDate
,value as OrderITEM
from #TEST
cross apply openjson('["'+(replace(OrderITEM,' ','","')+'"]'))
DROP TABLE if exists #TEST
https://social.msdn.microsoft.com/Forums/en-US/ca96a5a5-6a2a-4a8f-a579-582d67bc38d8/split-column-values-into-multiple-rows?forum=transactsql


WinSCP Send File with New Name

// Configure WinSCP with winscp.ini file export from GUI to generate this file from working machine
//in c:\Program Files (x86)\WinSCP\ folder
//copy this ini file to transfer site settings
string logname = "D:\\data\\log\\" + DateTime.Now.ToString("yyyyMMddHHmmssfff") + "_log.xml";
//// Run hidden WinSCP process
Process winscp = new Process();
winscp.StartInfo.FileName = "c:\\Program Files (x86)\\WinSCP\\winscp.com";
winscp.StartInfo.Arguments = "/log=\"" + logname + "\"";
winscp.StartInfo.UseShellExecute = false;
winscp.StartInfo.RedirectStandardInput = true;
winscp.StartInfo.RedirectStandardOutput = true;
winscp.StartInfo.CreateNoWindow = true;
winscp.Start();
//// Feed in the scripting commands
winscp.StandardInput.WriteLine("option batch abort");
winscp.StandardInput.WriteLine("option confirm off");
winscp.StandardInput.WriteLine("open sftp://user:secretPa$$word@sftp.somsite.com -hostkey=\"ssh – rsa 2048 XXX7ZpMVfJPIsq4maS429umMmfNNuwK5N6upqaEBpvg=\"");
//put a local file
//winscp.StandardInput.WriteLine("put D:\\data\\somefile.csv");
//put local file with optional remote file with a name
winscp.StandardInput.WriteLine("put D:\\data\\somefile.csv" +" newfilename_" + System.DateTime.Now.ToString("MM_dd_yyyy") + ".csv" );
//mv change the name remotely but will not overwrite file with same name
// winscp.StandardInput.WriteLine("mv somefile.csv newfilename_" + System.DateTime.Now.ToString("MM-dd-yyyy") + ".csv");
winscp.StandardInput.Close();


SP to Scripting out SSIS Environments Variables

Scripting Environments in SSIS



You may need to modify ev.base_data_type to sysname type to replace string type nvarchar type without size in the script below.


SELECT [env_var] = @tab + @tab + ', @' + ev.name + ' ' + ev.base_data_type + '= N''' + ISNULL(CONVERT(varchar(max), ev.value), '<REPLACE_ME>') + '''' , [name] = ev.name INTO #env_var FROM [SSISDB].[catalog].[folders] f INNER JOIN [SSISDB].[catalog].[environments] e ON f.folder_id = e.folder_id INNER JOIN [SSISDB].[internal].[environment_variables] ev ON e.environment_id = ev.environment_id WHERE (f.name = @folder) AND (e.name = @env);

Create Views From All Tables In a DB

https://stackoverflow.com/questions/23166423/how-to-create-view-for-all-tables-in-database
DECLARE @SQL nvarchar(MAX)
SET @SQL = N''
SELECT
@SQL = @SQL +
N'IF EXISTS(SELECT 1 FROM sys.objects WHERE name = ''v_' + t.[TABLE_NAME] + ''' AND type = ''V'') BEGIN DROP VIEW [v_' + t.[TABLE_NAME] + '] END
EXEC(''CREATE VIEW [v_' + t.[TABLE_NAME] + N'] AS SELECT ' +
STUFF(
(SELECT distinct ',' + c.[COLUMN_NAME]
FROM [INFORMATION_SCHEMA].[COLUMNS] AS c
WHERE c.[TABLE_SCHEMA] =t.[TABLE_SCHEMA] and c.[TABLE_NAME]=t.[TABLE_NAME]
FOR XML PATH(''), TYPE).value('.','nvarchar(max)')
,1,1,'')
+ ' FROM [' + t.[TABLE_NAME] + '] '')
'
FROM [INFORMATION_SCHEMA].[TABLES] t
WHERE [TABLE_TYPE]='BASE TABLE'
EXEC sp_executesql @SQL
–print @SQL