Joseph Michael Pesch
VP Programming

SQL Table Valued Function to Parse JSON

by 18. May 2017 11:58

 

 

CREATE FUNCTION [dbo].[parseJSON]( @JSON NVARCHAR(MAX))

RETURNS @hierarchy TABLE
  (
   element_id INT IDENTITY(1, 1) NOT NULL,/* internal surrogate primary key gives the order of parsing and the list order */
   sequenceNo [int] NULL, /* the place in the sequence for the element */
   parent_ID INT,/* if the element has a parent then it is in this column. The document is the ultimate parent, so you can get the structure from recursing from the document */
   Object_ID INT,/* each list or object has an object id. This ties all elements to a parent. Lists are treated as objects here */
   NAME NVARCHAR(2000),/* the name of the object */
   StringValue NVARCHAR(MAX)NOT NULL,/*the string representation of the value of the element. */
   ValueType VARCHAR(10) NOT null/* the declared type of the value represented as a string in StringValue*/
  )
AS
BEGIN
  DECLARE
    @FirstObject INT, --the index of the first open bracket found in the JSON string
    @OpenDelimiter INT,--the index of the next open bracket found in the JSON string
    @NextOpenDelimiter INT,--the index of subsequent open bracket found in the JSON string
    @NextCloseDelimiter INT,--the index of subsequent close bracket found in the JSON string
    @Type NVARCHAR(10),--whether it denotes an object or an array
    @NextCloseDelimiterChar CHAR(1),--either a '}' or a ']'
    @Contents NVARCHAR(MAX),--the unparsed contents of the bracketed expression
    @Start INT, --index of the start of the token that you are parsing
    @end INT,--index of the end of the token that you are parsing
    @param INT,--the parameter at the end of the next Object/Array token
    @EndOfName INT,--the index of the start of the parameter at end of Object/Array token
    @token NVARCHAR(500),--either a string or object -- slayne 7/10/14: increased from 200 to 500
    @value NVARCHAR(MAX),-- the value as a string
    @SequenceNo int, -- the sequence number within a list
    @name NVARCHAR(200),--the name as a string
    @parent_ID INT,--the next parent ID to allocate
    @lenJSON INT,--the current length of the JSON String
    @characters NCHAR(36),--used to convert hex to decimal
    @result BIGINT,--the value of the hex symbol being parsed
    @index SMALLINT,--used for parsing the hex value
    @Escape INT --the index of the next escape character
  DECLARE @Strings TABLE /* in this temporary table we keep all strings, even the names of the elements, since they are 'escaped' in a different way, and may contain, unescaped, brackets denoting objects or lists. These are replaced in the JSON string by tokens representing the string */
    (
     String_ID INT IDENTITY(1, 1),
     StringValue NVARCHAR(MAX)
    )
  SELECT--initialise the characters to convert hex to ascii
    @characters='0123456789abcdefghijklmnopqrstuvwxyz',
    @SequenceNo=0,--set the sequence no. to something sensible.
  /* firstly we process all strings. This is done because [{} and ] aren't escaped in strings, which complicates an iterative parse. */
    @parent_ID=0;
  WHILE 1=1 --forever until there is nothing more to do
    BEGIN
      SELECT
        @start=PATINDEX('%[^a-zA-Z]["]%', @json collate SQL_Latin1_General_CP850_Bin);--next delimited string
      IF @start=0 BREAK--no more so drop through the WHILE loop
      IF SUBSTRING(@json, @start+1, 1)='"'
        BEGIN --Delimited Name
          SET @start=@Start+1;
          SET @end=PATINDEX('%[^\]["]%',RIGHT(@json, LEN(@json+'|')-@start)collate SQL_Latin1_General_CP850_Bin);
        END
      IF @end=0 --no end delimiter to last string
        BREAK --no more
      SELECT @token=SUBSTRING(@json, @start+1, @end-1)
      --now put in the escaped control characters
      SELECT @token=REPLACE(@token, FROMString, TOString)
      FROM
        (SELECT
          '\"' AS FromString,'"' AS ToString
         UNION ALL SELECT'\\', '\'
         UNION ALL SELECT'\/', '/'
         UNION ALL SELECT'\b', CHAR(08)
         UNION ALL SELECT'\f', CHAR(12)
         UNION ALL SELECT'\n', CHAR(10)
         UNION ALL SELECT'\r', CHAR(13)
         UNION ALL SELECT'\t', CHAR(09)
        ) substitutions
      SELECT @result=0, @escape=1
  --Begin to take out any hex escape codes
      WHILE @escape>0
        BEGIN
          SELECT @index=0,
          --find the next hex escape sequence
          @escape=PATINDEX('%\x[0-9a-f][0-9a-f][0-9a-f][0-9a-f]%', @token collate SQL_Latin1_General_CP850_Bin)
          IF @escape>0 --if there is one
            BEGIN
              WHILE @index<4 --there are always four digits to a \x sequence   
                BEGIN 
                  SELECT --determine its value
                    @result=@result+POWER(16, @index)
                    *(CHARINDEX(SUBSTRING(@token, @escape+2+3-@index, 1),
                                @characters)-1), @index=@index+1 ;
                END
                -- and replace the hex sequence by its unicode value
              SELECT @token=STUFF(@token, @escape, 6, NCHAR(@result))
            END
        END
      --now store the string away 
      INSERT INTO @Strings (StringValue) SELECT @token
      -- and replace the string with a token
      SELECT @JSON=STUFF(@json, @start, @end+1,
                    '@string'+CONVERT(NVARCHAR(5),@@identity))
    END
  -- all strings are now removed. Now we find the first leaf.  
  WHILE 1=1  --forever until there is nothing more to do
  BEGIN
  SELECT @parent_ID=@parent_ID+1
  --find the first object or list by looking for the open bracket
  SELECT @FirstObject=PATINDEX('%[{[[]%', @json collate SQL_Latin1_General_CP850_Bin)--object or array
  IF @FirstObject = 0 BREAK
  IF (SUBSTRING(@json, @FirstObject, 1)='{')
    SELECT @NextCloseDelimiterChar='}', @type='object'
  ELSE
    SELECT @NextCloseDelimiterChar=']', @type='array'
  SELECT @OpenDelimiter=@firstObject
  WHILE 1=1 --find the innermost object or list...
    BEGIN
      SELECT
        @lenJSON=LEN(@JSON+'|')-1
  --find the matching close-delimiter proceeding after the open-delimiter
      SELECT
        @NextCloseDelimiter=CHARINDEX(@NextCloseDelimiterChar, @json,
                                      @OpenDelimiter+1)
  --is there an intervening open-delimiter of either type
      SELECT @NextOpenDelimiter=PATINDEX('%[{[[]%',
             RIGHT(@json, @lenJSON-@OpenDelimiter)collate SQL_Latin1_General_CP850_Bin)--object
      IF @NextOpenDelimiter=0 
        BREAK
      SELECT @NextOpenDelimiter=@NextOpenDelimiter+@OpenDelimiter
      IF @NextCloseDelimiter<@NextOpenDelimiter 
        BREAK
      IF SUBSTRING(@json, @NextOpenDelimiter, 1)='{'
        SELECT @NextCloseDelimiterChar='}', @type='object'
      ELSE 
        SELECT @NextCloseDelimiterChar=']', @type='array'
      SELECT @OpenDelimiter=@NextOpenDelimiter
    END
  ---and parse out the list or name/value pairs
  SELECT
    @contents=SUBSTRING(@json, @OpenDelimiter+1,
                        @NextCloseDelimiter-@OpenDelimiter-1)
  SELECT
    @JSON=STUFF(@json, @OpenDelimiter,
                @NextCloseDelimiter-@OpenDelimiter+1,
                '@'+@type+CONVERT(NVARCHAR(5), @parent_ID))
  WHILE (PATINDEX('%[A-Za-z0-9@+.e]%', @contents collate SQL_Latin1_General_CP850_Bin))<>0 
    BEGIN
      IF @Type='Object'--it will be a 0-n list containing a string followed by a string, number,boolean, or null
        BEGIN
          SELECT
            @SequenceNo=0,@end=CHARINDEX(':',' '+@contents)--if there is anything, it will be a string-based name.
          SELECT  @start=PATINDEX('%[^A-Za-z@][@]%',' '+@contents collate SQL_Latin1_General_CP850_Bin)--AAAAAAAA
          SELECT @token=SUBSTRING(' '+@contents, @start+1, @End-@Start-1),
            @endofname=PATINDEX('%[0-9]%', @token collate SQL_Latin1_General_CP850_Bin),
            @param=RIGHT(@token,LEN(@token)-@endofname+1)
          SELECT
            @token=LEFT(@token, @endofname-1),
            @Contents=RIGHT(' '+@contents,LEN(' '+@contents+'|')-@end-1)
          SELECT  @name=stringvalue FROM @strings
            WHERE string_id=@param --fetch the name
        END
      ELSE 
        SELECT @Name=null,@SequenceNo=@SequenceNo+1 
      SELECT
        @end=CHARINDEX(',', @contents)-- a string-token, object-token, list-token, number,boolean, or null
      IF @end=0 
        SELECT  @end=PATINDEX('%[A-Za-z0-9@+.e][^A-Za-z0-9@+.e]%', @Contents+' ' collate SQL_Latin1_General_CP850_Bin)
          +1
       SELECT
        @start=PATINDEX('%[^A-Za-z0-9@+.e][A-Za-z0-9@+.e]%',' '+@contents collate SQL_Latin1_General_CP850_Bin)
      --select @start,@end, LEN(@contents+'|'), @contents  
      SELECT
        @Value=RTRIM(SUBSTRING(@contents, @start, @End-@Start)),
        @Contents=RIGHT(@contents+' ', LEN(@contents+'|')-@end)
      IF SUBSTRING(@value, 1, 7)='@object'
        INSERT INTO @hierarchy
          (NAME, SequenceNo, parent_ID, StringValue,Object_ID, ValueType)
          SELECT @name, @SequenceNo, @parent_ID, SUBSTRING(@value, 8, 5),
            SUBSTRING(@value, 8, 5), 'object'
      ELSE 
        IF SUBSTRING(@value, 1, 6)='@array'
          INSERT INTO @hierarchy
            (NAME, SequenceNo, parent_ID, StringValue,Object_ID, ValueType)
            SELECT @name, @SequenceNo, @parent_ID, SUBSTRING(@value, 7, 5),
              SUBSTRING(@value, 7, 5), 'array'
        ELSE 
          IF SUBSTRING(@value, 1, 7)='@string'
            INSERT INTO @hierarchy
              (NAME, SequenceNo, parent_ID, StringValue, ValueType)
              SELECT @name, @SequenceNo, @parent_ID, stringvalue, 'string'
              FROM @strings
              WHERE string_id=SUBSTRING(@value, 8, 5)
          ELSE 
            IF @value IN ('true','false') 
              INSERT INTO @hierarchy
                (NAME, SequenceNo, parent_ID, StringValue, ValueType)
                SELECT @name, @SequenceNo, @parent_ID, @value, 'boolean'
            ELSE 
              IF @value='null'
                INSERT INTO @hierarchy
                  (NAME, SequenceNo, parent_ID, StringValue, ValueType)
                  SELECT @name, @SequenceNo, @parent_ID, @value, 'null'
              ELSE 
                IF PATINDEX('%[^0-9]%', @value collate SQL_Latin1_General_CP850_Bin)>0 
                  INSERT INTO @hierarchy
                    (NAME, SequenceNo, parent_ID, StringValue, ValueType)
                    SELECT @name, @SequenceNo, @parent_ID, @value, 'real'
                ELSE 
                  INSERT INTO @hierarchy
                    (NAME, SequenceNo, parent_ID, StringValue, ValueType)
                    SELECT @name, @SequenceNo, @parent_ID, @value, 'int'
      if @Contents=' 'Select @SequenceNo=0
    END
  END
INSERT INTO @hierarchy (NAME, SequenceNo, parent_ID, StringValue,Object_ID, ValueType)
  SELECT '-',1,NULL, '', @parent_id-1, @type
--
   RETURN
END

GO

Tags:

SQL Server

SQL Backup All User Databases via Windows Task Scheduler

by 22. March 2016 18:14

1) Create the SQL procedure below
2) Add this sqlcmd to a CMD file:
    sqlcmd -S localhost -E -Q "exec master.dbo.prc_BackupUserDatabases"
3) Add this command to the CMD file (to delete files older that X days), sample deletes *.bak files older than 5 days:
    forfiles -p "C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\Backup" -s -m *.bak -d -5 -c "cmd /c del @path"
4) Add to windows task scheduler with Action = Start a Program (pointed to the CMD file)

SQL Procedure

USE [master]
GO
create procedure [dbo].[prc_BackupUserDatabases] as
begin
  declare @DatabaseName varchar(50)
        , @BackupFolder sysname = 'C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\Backup\';
  declare cur cursor for select name from sys.databases where len(owner_sid) > 1
  open cur
  while 1=1 begin
    fetch next from cur into @DatabaseName
    if @@FETCH_STATUS <> 0 break
    declare @BackupFilePath sysname = @BackupFolder + @DatabaseName + N'_' + CONVERT(char(8), GETDATE(), 112) + '.bak';
    backup database @DatabaseName to disk = @BackupFilePath with init, STATS=10;
  end
  close cur
  deallocate cur
end

Tags:

SQL Server

SQL Function to Convert Delimited String to Table

by 24. December 2015 07:58

This is a SQL function to convert a delimited string into a table.

create function [dbo].[DelimToTable] 
(@StringInput varchar(max), @Delimiter nvarchar(1))
returns @OutputTable table([String] varchar(255)) as begin
declare @String varchar(255)
while len(@StringInput) > 0 begin
set @String = left(@StringInput
, isnull(nullif(charindex(@Delimiter, @StringInput) - 1, -1)
, len(@StringInput)))
set @StringInput = substring(@StringInput
, isnull(nullif(charindex(@Delimiter, @StringInput), 0)
, len(@StringInput)) + 1, len(@StringInput))
insert into @OutputTable ([String]) values(@String)
end
return
end

Tags:

SQL Server

SQL Server Drop Extended Properties (e.g. MS_Description)

by 8. September 2015 04:38

This script will generate a set of drop statements:

--tables
 select 'EXEC sp_dropextendedproperty
 @name = '''+name+'''
 ,@level0type = ''schema''
 ,@level0name = ' + object_schema_name(extended_properties.major_id) + '
 ,@level1type = ''table''
 ,@level1name = ' + object_name(extended_properties.major_id)
 from sys.extended_properties
 where extended_properties.class_desc = 'OBJECT_OR_COLUMN'
 and extended_properties.minor_id = 0
 union
 --columns
 select 'EXEC sp_dropextendedproperty
 @name = '''+sys.extended_properties.name+'''
 ,@level0type = ''schema''
 ,@level0name = ' + object_schema_name(extended_properties.major_id) + '
 ,@level1type = ''table''
 ,@level1name = ' + object_name(extended_properties.major_id) + '
 ,@level2type = ''column''
 ,@level2name = ' + columns.name
 from sys.extended_properties
 join sys.columns
 on columns.object_id = extended_properties.major_id
 and columns.column_id = extended_properties.minor_id
 where extended_properties.class_desc = 'OBJECT_OR_COLUMN'
 and extended_properties.minor_id > 0

Tags:

SQL Server

SQL Server TSQL DateDiff Between Weekdays Only

by 20. August 2015 07:04

declare @d1 datetime, @d2 datetime
select @d1 = '8/1/2015',  @d2 = '8/20/2015'

select datediff(dd, @d1, @d2) - (datediff(wk, @d1, @d2) * 2) -
       case when datepart(dw, @d1) = 1 then 1 else 0 end +
      case when datepart(dw, @d2) = 1 then 1 else 0 end

Tags:

SQL Server

TSQL Function to Return Number of Weekdays Between Two Dates (Excludes Weekend Days)

by 4. May 2015 10:41

TSQL function to return a number of weekdays between two dates (i.e. excludes weekend days):

create function WeekdayDateDiff
(
 @BegDt as DATETIME,
 @EndDt as DATETIME
) returns int as begin
  return (datediff(dd, @BegDt, @EndDt) + 1)
  -(datediff(wk, @BegDt, @EndDt) * 2)
  -(case when datepart(dw, @BegDt) = 1 then 1 else 0 end)
  -(case when datepart(dw, @EndDt) = 7 then 1 else 0 end)
end

Tags:

SQL Server

Microsoft SQL Server TSQL Script to View All User Role Assignments

by 10. March 2015 04:01

 

/* The following will list all user role assignments in current database */


WITH RoleMembers (member_principal_id, role_principal_id)
AS
(
  SELECT
   rm1.member_principal_id,
   rm1.role_principal_id
  FROM sys.database_role_members rm1 (NOLOCK)
   UNION ALL
  SELECT
   d.member_principal_id,
   rm.role_principal_id
  FROM sys.database_role_members rm (NOLOCK)
   INNER JOIN RoleMembers AS d
   ON rm.member_principal_id = d.role_principal_id
)
select distinct rp.name as database_role, mp.name as database_user
from RoleMembers drm
  join sys.database_principals rp on (drm.role_principal_id = rp.principal_id)
  join sys.database_principals mp on (drm.member_principal_id = mp.principal_id)
order by rp.name

/* The following will list all user role assignments in all databases except master and tempdb */

create table #tmp(DatabaseName varchar(150), DatabaseRole varchar(150), DatabaseUser varchar(150))

declare @command varchar(max)

select @command = '
if ''?'' not in(''master'', ''tempdb'')
begin
    print ''?''
    use [?]
  ;
  WITH RoleMembers (member_principal_id, role_principal_id)
  AS
  (
    SELECT
     rm1.member_principal_id,
     rm1.role_principal_id
    FROM sys.database_role_members rm1 (NOLOCK)
     UNION ALL
    SELECT
     d.member_principal_id,
     rm.role_principal_id
    FROM sys.database_role_members rm (NOLOCK)
     INNER JOIN RoleMembers AS d
     ON rm.member_principal_id = d.role_principal_id
  )
  insert into #tmp select distinct ''?'', rp.name, mp.name
  from RoleMembers drm
    join sys.database_principals rp on (drm.role_principal_id = rp.principal_id)
    join sys.database_principals mp on (drm.member_principal_id = mp.principal_id)
  order by rp.name

end
'
exec sp_msforeachdb @command1 = @command

select * from #tmp

drop table #tmp

Tags:

SQL Server

Issue with ASP.Net Identity from Default Local File System Database to SQL Server Based Database

by 22. December 2014 10:12

I created a new MVC 5 web application with the "Individual User Account" option that configures the ASP.Net Identity model.  By default this uses Entity Framework Code First model with a local file system database created in the local App_Data folder.  I tried moving this to an actual SQL Server database location by creating the five dbo.aspnet_... tables and changing the web.config to point to the new location.  However, in doing so I received the error below.  Turns out to solve this I just needed to change the connection string in the web.config from the Entity Framework style to the basic style (see old vs. new connection strings below).

 <connectionStrings>

    <addname="NewSimpleConnection"connectionString="Data Source=SERVER_NAME_HERE;initial catalog=DB_NAME_HERE;user id=USER_ID_HERE;password=PASSWORD_HERE;Integrated Security=False"providerName="System.Data.SqlClient" />

    <addname="OldEtityFConnection"connectionString="metadata=res://*/MyModel.csdl|res://*/MyModel.ssdl|res://*/MyModel.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data Source=SERVER_NAME_HERE;initial catalog=DB_NAME_HERE;user id=USER_ID_HERE;password=PASSWORD_HERE;MultipleActiveResultSets=True;App=EntityFramework&quot;"providerName="System.Data.EntityClient" />

  </connectionStrings> 

Server Error in '/' Application.


 

Unable to load the specified metadata resource.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.Data.Entity.Core.MetadataException: Unable to load the specified metadata resource.

Source Error:

 

Line 114:      {
Line 115:        var user = new ApplicationUser() { UserName = model.Email, Email = model.Email };
Line 116:        IdentityResult result = await UserManager.CreateAsync(user, model.Password);
Line 117:        if (result.Succeeded)
Line 118:        {

Tags:

ASP.Net | C# | SQL Server

AdventureWorks Sample Database

by 23. September 2014 08:26

Download the 2012 SQL DB version of Microsoft AdventureWorks Sample Database here:


http://msftdbprodsamples.codeplex.com/downloads/get/165399

 

Tags:

SQL Server

Parse JSON in TSQL

by 11. July 2014 06:44

Parsing JSON using TSQL.

/*
  Repost from: https://www.simple-talk.com/sql/t-sql-programming/consuming-json-strings-in-sql-server/
*/

CREATE FUNCTION dbo.parseJSON(@JSON NVARCHAR(MAX))
RETURNS @hierarchy TABLE
  (
   element_id INT IDENTITY(1, 1) NOT NULL,/* internal surrogate primary key gives the order of parsing and the list order */
   sequenceNo [int] NULL, /* the place in the sequence for the element */
   parent_ID INT,/* if the element has a parent then it is in this column. The document is the ultimate parent, so you can get the structure from recursing from the document */
   Object_ID INT,/* each list or object has an object id. This ties all elements to a parent. Lists are treated as objects here */
   NAME NVARCHAR(2000),/* the name of the object */
   StringValue NVARCHAR(MAX)NOT NULL,/*the string representation of the value of the element. */
   ValueType VARCHAR(10) NOT null/* the declared type of the value represented as a string in StringValue*/
  )
AS
BEGIN
  DECLARE
    @FirstObject INT, --the index of the first open bracket found in the JSON string
    @OpenDelimiter INT,--the index of the next open bracket found in the JSON string
    @NextOpenDelimiter INT,--the index of subsequent open bracket found in the JSON string
    @NextCloseDelimiter INT,--the index of subsequent close bracket found in the JSON string
    @Type NVARCHAR(10),--whether it denotes an object or an array
    @NextCloseDelimiterChar CHAR(1),--either a '}' or a ']'
    @Contents NVARCHAR(MAX),--the unparsed contents of the bracketed expression
    @Start INT, --index of the start of the token that you are parsing
    @end INT,--index of the end of the token that you are parsing
    @param INT,--the parameter at the end of the next Object/Array token
    @EndOfName INT,--the index of the start of the parameter at end of Object/Array token
    @token NVARCHAR(200),--either a string or object
    @value NVARCHAR(MAX),-- the value as a string
    @SequenceNo int, -- the sequence number within a list
    @name NVARCHAR(200),--the name as a string
    @parent_ID INT,--the next parent ID to allocate
    @lenJSON INT,--the current length of the JSON String
    @characters NCHAR(36),--used to convert hex to decimal
    @result BIGINT,--the value of the hex symbol being parsed
    @index SMALLINT,--used for parsing the hex value
    @Escape INT --the index of the next escape character
  DECLARE @Strings TABLE /* in this temporary table we keep all strings, even the names of the elements, since they are 'escaped' in a different way, and may contain, unescaped, brackets denoting objects or lists. These are replaced in the JSON string by tokens representing the string */
    (
     String_ID INT IDENTITY(1, 1),
     StringValue NVARCHAR(MAX)
    )
  SELECT--initialise the characters to convert hex to ascii
    @characters='0123456789abcdefghijklmnopqrstuvwxyz',
    @SequenceNo=0,--set the sequence no. to something sensible.
  /* firstly we process all strings. This is done because [{} and ] aren't escaped in strings, which complicates an iterative parse. */
    @parent_ID=0;
  WHILE 1=1 --forever until there is nothing more to do
    BEGIN
      SELECT
        @start=PATINDEX('%[^a-zA-Z]["]%', @json collate SQL_Latin1_General_CP850_Bin);--next delimited string
      IF @start=0 BREAK--no more so drop through the WHILE loop
      IF SUBSTRING(@json, @start+1, 1)='"'
        BEGIN --Delimited Name
          SET @start=@Start+1;
          SET @end=PATINDEX('%[^\]["]%',RIGHT(@json, LEN(@json+'|')-@start)collate SQL_Latin1_General_CP850_Bin);
        END
      IF @end=0 --no end delimiter to last string
        BREAK --no more
      SELECT @token=SUBSTRING(@json, @start+1, @end-1)
      --now put in the escaped control characters
      SELECT @token=REPLACE(@token, FROMString, TOString)
      FROM
        (SELECT
          '\"' AS FromString,'"' AS ToString
         UNION ALL SELECT'\\', '\'
         UNION ALL SELECT'\/', '/'
         UNION ALL SELECT'\b', CHAR(08)
         UNION ALL SELECT'\f', CHAR(12)
         UNION ALL SELECT'\n', CHAR(10)
         UNION ALL SELECT'\r', CHAR(13)
         UNION ALL SELECT'\t', CHAR(09)
        ) substitutions
      SELECT @result=0, @escape=1
  --Begin to take out any hex escape codes
      WHILE @escape>0
        BEGIN
          SELECT @index=0,
          --find the next hex escape sequence
          @escape=PATINDEX('%\x[0-9a-f][0-9a-f][0-9a-f][0-9a-f]%', @token collate SQL_Latin1_General_CP850_Bin)
          IF @escape>0 --if there is one
            BEGIN
              WHILE @index<4 --there are always four digits to a \x sequence  
                BEGIN
                  SELECT --determine its value
                    @result=@result+POWER(16, @index)
                    *(CHARINDEX(SUBSTRING(@token, @escape+2+3-@index, 1),
                                @characters)-1), @index=@index+1 ;
                END
                -- and replace the hex sequence by its unicode value
              SELECT @token=STUFF(@token, @escape, 6, NCHAR(@result))
            END
        END
      --now store the string away
      INSERT INTO @Strings (StringValue) SELECT @token
      -- and replace the string with a token
      SELECT @JSON=STUFF(@json, @start, @end+1,
                    '@string'+CONVERT(NVARCHAR(5),@@identity))
    END
  -- all strings are now removed. Now we find the first leaf. 
  WHILE 1=1  --forever until there is nothing more to do
  BEGIN
  SELECT @parent_ID=@parent_ID+1
  --find the first object or list by looking for the open bracket
  SELECT @FirstObject=PATINDEX('%[{[[]%', @json collate SQL_Latin1_General_CP850_Bin)--object or array
  IF @FirstObject = 0 BREAK
  IF (SUBSTRING(@json, @FirstObject, 1)='{')
    SELECT @NextCloseDelimiterChar='}', @type='object'
  ELSE
    SELECT @NextCloseDelimiterChar=']', @type='array'
  SELECT @OpenDelimiter=@firstObject
  WHILE 1=1 --find the innermost object or list...
    BEGIN
      SELECT
        @lenJSON=LEN(@JSON+'|')-1
  --find the matching close-delimiter proceeding after the open-delimiter
      SELECT
        @NextCloseDelimiter=CHARINDEX(@NextCloseDelimiterChar, @json,
                                      @OpenDelimiter+1)
  --is there an intervening open-delimiter of either type
      SELECT @NextOpenDelimiter=PATINDEX('%[{[[]%',
             RIGHT(@json, @lenJSON-@OpenDelimiter)collate SQL_Latin1_General_CP850_Bin)--object
      IF @NextOpenDelimiter=0
        BREAK
      SELECT @NextOpenDelimiter=@NextOpenDelimiter+@OpenDelimiter
      IF @NextCloseDelimiter<@NextOpenDelimiter
        BREAK
      IF SUBSTRING(@json, @NextOpenDelimiter, 1)='{'
        SELECT @NextCloseDelimiterChar='}', @type='object'
      ELSE
        SELECT @NextCloseDelimiterChar=']', @type='array'
      SELECT @OpenDelimiter=@NextOpenDelimiter
    END
  ---and parse out the list or name/value pairs
  SELECT
    @contents=SUBSTRING(@json, @OpenDelimiter+1,
                        @NextCloseDelimiter-@OpenDelimiter-1)
  SELECT
    @JSON=STUFF(@json, @OpenDelimiter,
                @NextCloseDelimiter-@OpenDelimiter+1,
                '@'+@type+CONVERT(NVARCHAR(5), @parent_ID))
  WHILE (PATINDEX('%[A-Za-z0-9@+.e]%', @contents collate SQL_Latin1_General_CP850_Bin))<>0
    BEGIN
      IF @Type='Object'--it will be a 0-n list containing a string followed by a string, number,boolean, or null
        BEGIN
          SELECT
            @SequenceNo=0,@end=CHARINDEX(':',' '+@contents)--if there is anything, it will be a string-based name.
          SELECT  @start=PATINDEX('%[^A-Za-z@][@]%',' '+@contents collate SQL_Latin1_General_CP850_Bin)--AAAAAAAA
          SELECT @token=SUBSTRING(' '+@contents, @start+1, @End-@Start-1),
            @endofname=PATINDEX('%[0-9]%', @token collate SQL_Latin1_General_CP850_Bin),
            @param=RIGHT(@token,LEN(@token)-@endofname+1)
          SELECT
            @token=LEFT(@token, @endofname-1),
            @Contents=RIGHT(' '+@contents,LEN(' '+@contents+'|')-@end-1)
          SELECT  @name=stringvalue FROM @strings
            WHERE string_id=@param --fetch the name
        END
      ELSE
        SELECT @Name=null,@SequenceNo=@SequenceNo+1
      SELECT
        @end=CHARINDEX(',', @contents)-- a string-token, object-token, list-token, number,boolean, or null
      IF @end=0
        SELECT  @end=PATINDEX('%[A-Za-z0-9@+.e][^A-Za-z0-9@+.e]%', @Contents+' ' collate SQL_Latin1_General_CP850_Bin)
          +1
       SELECT
        @start=PATINDEX('%[^A-Za-z0-9@+.e][A-Za-z0-9@+.e]%',' '+@contents collate SQL_Latin1_General_CP850_Bin)
      --select @start,@end, LEN(@contents+'|'), @contents 
      SELECT
        @Value=RTRIM(SUBSTRING(@contents, @start, @End-@Start)),
        @Contents=RIGHT(@contents+' ', LEN(@contents+'|')-@end)
      IF SUBSTRING(@value, 1, 7)='@object'
        INSERT INTO @hierarchy
          (NAME, SequenceNo, parent_ID, StringValue,Object_ID, ValueType)
          SELECT @name, @SequenceNo, @parent_ID, SUBSTRING(@value, 8, 5),
            SUBSTRING(@value, 8, 5), 'object'
      ELSE
        IF SUBSTRING(@value, 1, 6)='@array'
          INSERT INTO @hierarchy
            (NAME, SequenceNo, parent_ID, StringValue,Object_ID, ValueType)
            SELECT @name, @SequenceNo, @parent_ID, SUBSTRING(@value, 7, 5),
              SUBSTRING(@value, 7, 5), 'array'
        ELSE
          IF SUBSTRING(@value, 1, 7)='@string'
            INSERT INTO @hierarchy
              (NAME, SequenceNo, parent_ID, StringValue, ValueType)
              SELECT @name, @SequenceNo, @parent_ID, stringvalue, 'string'
              FROM @strings
              WHERE string_id=SUBSTRING(@value, 8, 5)
          ELSE
            IF @value IN ('true','false')
              INSERT INTO @hierarchy
                (NAME, SequenceNo, parent_ID, StringValue, ValueType)
                SELECT @name, @SequenceNo, @parent_ID, @value, 'boolean'
            ELSE
              IF @value='null'
                INSERT INTO @hierarchy
                  (NAME, SequenceNo, parent_ID, StringValue, ValueType)
                  SELECT @name, @SequenceNo, @parent_ID, @value, 'null'
              ELSE
                IF PATINDEX('%[^0-9]%', @value collate SQL_Latin1_General_CP850_Bin)>0
                  INSERT INTO @hierarchy
                    (NAME, SequenceNo, parent_ID, StringValue, ValueType)
                    SELECT @name, @SequenceNo, @parent_ID, @value, 'real'
                ELSE
                  INSERT INTO @hierarchy
                    (NAME, SequenceNo, parent_ID, StringValue, ValueType)
                    SELECT @name, @SequenceNo, @parent_ID, @value, 'int'
      if @Contents=' 'Select @SequenceNo=0
    END
  END
INSERT INTO @hierarchy (NAME, SequenceNo, parent_ID, StringValue,Object_ID, ValueType)
  SELECT '-',1,NULL, '', @parent_id-1, @type
--
   RETURN
END
GO

-- Create the data type
IF EXISTS (SELECT * FROM sys.types WHERE name LIKE 'Hierarchy')
  DROP TYPE dbo.Hierarchy
go
CREATE TYPE dbo.Hierarchy AS TABLE
(
   element_id INT NOT NULL, /* internal surrogate primary key gives the order of parsing and the list order */
   sequenceNo [int] NULL, /* the place in the sequence for the element */
   parent_ID INT,/* if the element has a parent then it is in this column. The document is the ultimate parent, so you can get the structure from recursing from the document */
   [Object_ID] INT,/* each list or object has an object id. This ties all elements to a parent. Lists are treated as objects here */
   NAME NVARCHAR(2000),/* the name of the object, null if it hasn't got one */
   StringValue NVARCHAR(MAX) NOT NULL,/*the string representation of the value of the element. */
   ValueType VARCHAR(10) NOT null /* the declared type of the value represented as a string in StringValue*/
    PRIMARY KEY (element_id)
)

Tags:

SQL Server

Migrating SQL Server Database from Newer version (SQL 2012) to Older Version (SQL 2008 r2)

by 16. May 2014 07:08

I was trying to backup and restore a SQL 2012 database to a SQL 2008r2 server; however, that is not supported (you can only go from previous versions to newer version and not the other way). An alternative method is to use the SQL "Tasks > Copy Database" option when right-clicking on the source database.  Steps to use this method:

  • Right click on source database and select "Tasks > Copy Database"
  • Select source server
  • Select target server
    • Note: If using the "Use Windows Authentication" option make sure to add the necessary login to the source database.  (typically it would be in the form of DOMAIN\MACHINENAME$).
  • On the next screen you will have the option for either "Use the detach and attach method"; or, "Use the SQL Management Object method".  You must use the second option as the detach/attach method will fail similar to a backup/restore (i.e. cannot go from higher version to lower version).
  • Select source database
  • Select destination database
  • Provide package name
  • Schedule the package
  • Finished

At this point there will be a new SQL Agent Job on the target server with the name defined above.  Make sure the target database does not exist before running the job (there is an option to setup the job to overwrite the database if you prefer when setting up the initial job).

 

Tags:

SQL Server

SQL Select Statement to Calculate Monthly Loan Payment

by 27. January 2014 08:15

The following SQL statement will calculate a monthly loan payment (principal and interest).

select CalculatedPmt =
  cast(
    LoanAmount
      / (power(1+((NoteRate*.01)/cast(12 as float)),LoanTermMonths)-1)
      * (((NoteRate*.01)/cast(12 as float))
      * power(1+((NoteRate*.01)/cast(12 as float)),LoanTermMonths))
    as decimal(10,2))

Tags:

SQL Server

Visual Studio Open Database Error: Failed to Generate a User Instance of SQL Server

by 29. November 2013 12:48

Running SQLExpress and trying to open database from Visual Studio.  In my case I originally had SQL 2008 and 2012 installed.  Then I added 2008R2 and deleted 2008.  After that when trying to open a database (from App_Data folder of Visual Studio project) using the Server Explorer in Visual Studio I received the following error message: "Failed to generate a user instance of SQL Server due to a failure in starting the process for the user instance. The connection will be closed.".  To resolve I simply deleted the following folder and then restarted Visual Studio: C:\Users\...\AppData\Local\Microsoft\Microsoft SQL Server Data

Tags:

SQL Server | Visual Studio

SQL DBCC ShrinkFile Not Working (i.e. Executes Successfully But File Does Not Shrink)

by 22. August 2013 12:41

When attempting to run "DBCC ShrinkFile" SQL command to shrink a transaction log file on a database that has replication enabled it may appear to have run successfully; however, the log file may not actually shrink.  To resolve this issue you can add a call to "EXEC sp_repldone" to allow the server to take action on the log file.  Below is a sample process that I have added to a nightly job to take place after the full DB backup executes.

use DBName;
go
alter database DBName set recovery simple;
go
exec sp_repldone @xactid = NULL, @xact_segno = NULL, @numtrans = 0, @time = 0, @reset = 1
go
dbcc SHRINKFILE (DBName_log, 1);
go
alter database DBName set recovery full;
go

Tags:

SQL Server

SQL Statement to View Connected Login Authentication Schema in Use (i.e. SQL, NTLM, Kerberos, etc.)

by 15. April 2013 12:45
The following is a SQL statement that will return a list of active connections and the login authentication schema being used by the connection.  This is useful in validating that connections are using the expected protocol. 
select 
s.session_id,
s.login_name,
s.host_name,
c.auth_scheme
from
sys.dm_exec_connections c
inner join
sys.dm_exec_sessions s
on c.session_id = s.session_id

Tags:

SQL Server

Determine Authentication Scheme on SQL Server

by 22. March 2013 14:12

Below is a TSQL statement that will return the current authentication scheme running on your SQL server instance.

SELECT net_transport, auth_scheme FROM sys.dm_exec_connections WHERE session_id = @@SPID;

Tags:

SQL Server

ASP.Net Security Create New User Account Based on Existing User Account

by 1. February 2013 07:39

This SQL script will create a new ASP.Net user account using an existing user account as the basis.  The new user account will have the same password and roles as the existing user account.  Also included at the end of the main script is a script to change a user account password to a known defualt (e.g. Password1234).


Script to replicate user:

declare 
  @ExisitingUserName varchar(50)
, @ExisitingUserEmail
, @OldUserID uniqueidentifier
, @UserID uniqueidentifier
, @Email varchar(50)
, @UserName varchar(50)
, @DeleteIfExists bit

select
  @UserID = newid()
, @Email = 'new.user@email.com'
, @UserName = 'new.user@email.com'
, @DeleteIfExists = 0
, @ExisitingUserName = 'EXISTING_USER_NAME_HERE'
select
  @UserID
, @Email
, @UserName

select @OldUserID = UserID 
from dbo.aspnet_Users 
where UserName = @UserName

if @DeleteIfExists = 1 begin

delete from dbo.aspnet_UsersInRoles
where UserID = @OldUserID

delete from dbo.aspnet_Membership
where UserID = @OldUserID

delete from dbo.aspnet_Users 
where UserName = @UserName

end

insert into dbo.aspnet_Users
select
  ApplicationId
, @UserID
, @UserName
, lower(@UserName) /* LoweredUserName */
, null /* MobileAlias */
, 0 /* IsAnonymous */ 
, getdate() /* LastActivityDate */
from dbo.aspnet_Users
where UserName = @ExisitingUserName

insert into dbo.aspnet_Membership
select
  ApplicationId
, @UserID
, Password
, PasswordFormat
, PasswordSalt
, MobilePIN
, @Email
, @Email
, PasswordQuestion
, PasswordAnswer
, IsApproved
, IsLockedOut
, getdate() /* CreateDate */
, getdate() /* LastLoginDate */
, getdate() /* LastPasswordChangedDate */
, '1/1/1754 12:00:00 AM' /* LastLockoutDate */
, 0 /* FailedPasswordAttemptCount */
, '1/1/1754 12:00:00 AM' /* FailedPasswordAttemptWindowStart */
, 0 /* FailedPasswordAnswerAttemptCount */
, '1/1/1754 12:00:00 AM' /* FailedPasswordAnswerAttemptWindowStart */
, Comment
from aspnet_Membership
where Email = @ExisitingUserEmail

insert into dbo.aspnet_UsersInRoles
select @UserID, RoleID
from dbo.aspnet_Roles

Script to change password:

update dbo.aspnet_Membership 
set PasswordSalt = 'dArJQD4e4upwMyqCSl9iNA=='
, Password = '1mAUj77CySFAtqlfInt4UFOznAc=' /* Password1234 */
where UserId = 
(
  select UserId 
  from dbo.aspnet_Users 
  where UserName = 'USER_NAME_HERE'
)

Tags:

ASP.Net | SQL Server

SQL Read Sharepoint Document Content for SSRS Reports

by 6. December 2012 09:43

I had a case where I needed to review a few hundred SSRS reports installed on a Sharepoint 2010 envrionment.  Below is a SQL script I created to read the content from the underlying SQL database and search the report structure for certain keywords (in my case I was looking for specific database/table names in the report SQL).

create table #tmp(name varchar(150), content varchar(max))
/* Get cursor of all SSRS report (*.rdl) files to cycle through */
declare cur cursor for 
select Id, LeafName, InternalVersion 
from AllDocs where LeafName like '%.rdl'
declare @id varchar(50), @name varchar(200), @version int
open cur
while 1=1 begin
  fetch next from cur into @id, @name, @version
  if @@FETCH_STATUS <> 0 break
  /* Check is current version of the report contains specific keywords */
  if exists
  (
    select 1 
	from WSS_CONTENT_SITENAMEHERE.dbo.AllDocStreams 
	where Id = @id 
	and InternalVersion = @version 
	and 
	(
	  cast(Content as varchar(max)) like '%KEYWORD #1 HERE%' 
	  or 
	  cast(Content as varchar(max)) like '%KEYWORD #2 HERE%')
	)  
    insert into #tmp 
    select @name, cast(Content as varchar(max)) 
    from WSS_CONTENT_SITENAMEHERE.dbo.AllDocStreams 
    where Id = @id and InternalVersion = @version
end
close cur
deallocate cur
select * from #tmp
drop table #tmp

Tags:

Sharepoint | SQL Server

SQL Script to Shrink Database Transaction Log Files

by 26. October 2012 15:53

This script will operate on all databases that are ONLINE.  Will set recovery mode to SIMPLE temporarily shrink the log file then set recovery mode back to FULL.  In the case where the database recovery mode is already SIMPLE it will simply shrink the log file and leave the recovery mode set to SIMPLE.

declare @db varchar(255)
, @rcm varchar(25)
, @log varchar(255)
, @sql varchar(max) 

create table #tmp (db varchar(255), rcm varchar(25), lg varchar(255))
declare cur cursor for
select name, recovery_model_desc
/* convert(varchar(25), databasepropertyex(names, 'RECOVERY')) */
from sys.databases
where name not in('master', 'tempdb', 'model', 'msdb', 'distribution')
and state_desc = 'ONLINE' /* Skip anything OFFLINE */
open cur
while 1=1 begin
  fetch next from cur into @db, @rcm
  if @@FETCH_STATUS <> 0 break
  set @sql = 'use [' + @db + '] insert into #tmp'
      + ' select ''' + @db + ''', ''' + @rcm + ''''
      + ', name from sys.sysfiles where fileid = 2'
  exec(@sql) 
end
deallocate cur

declare cur cursor for
select * from #tmp
open cur
while 1=1 begin
  fetch next from cur into @db, @rcm, @log
  if @@FETCH_STATUS <> 0 break
  if @rcm = 'FULL' /* When FULL we will set simple then back to FULL */
    select @sql = 'use [' + @db + ']'
      + ' alter database [' + @db + '] set recovery simple with no_wait'
      + ' dbcc shrinkfile (N''' + @log + ''', 1) '
      + ' alter database [' + @db + '] set recovery full with no_wait'
   else /* When already SIMPLE just shrink and leave it alone */
    select @sql = 'use [' + @db + ']'
      + ' dbcc shrinkfile (N''' + @log + ''', 1) '
  exec(@sql)
end

drop table #tmp

Tags:

SQL Server

SQL Script to Shrink Database Transaction Log Files

by 26. October 2012 15:40

This script will operate on all databases that are ONLINE.  Will set recovery mode to SIMPLE temporarily shrink the log file then set recovery mode back to FULL.  In the case where the database recovery mode is already SIMPLE it will simply shrink the log file and leave the recovery mode set to SIMPLE.

declare @db varchar(255)
, @rcm varchar(25)
, @log varchar(255)
, @sql varchar(max) 

create table #tmp (db varchar(255), rcm varchar(25), lg varchar(255))
declare cur cursor for
select name, recovery_model_desc
/* convert(varchar(25), databasepropertyex(names, 'RECOVERY')) */
from sys.databases
where name not in('master', 'tempdb', 'model', 'msdb', 'distribution')
and state_desc = 'ONLINE' /* Skip anything OFFLINE */
open cur
while 1=1 begin
  fetch next from cur into @db, @rcm
  if @@FETCH_STATUS <> 0 break
  set @sql = 'use [' + @db + '] insert into #tmp'
      + ' select ''' + @db + ''', ''' + @rcm + ''''
      + ', name from sys.sysfiles where fileid = 2'
  exec(@sql) 
end
deallocate cur

declare cur cursor for
select * from #tmp
open cur
while 1=1 begin
  fetch next from cur into @db, @rcm, @log
  if @@FETCH_STATUS <> 0 break
  if @rcm = 'FULL' /* When FULL we will set simple then back to FULL */
    select @sql = 'use [' + @db + ']'
      + ' alter database [' + @db + '] set recovery simple with no_wait'
      + ' dbcc shrinkfile (N''' + @log + ''', 1) '
      + ' alter database [' + @db + '] set recovery full with no_wait'
   else /* When already SIMPLE just shrink and leave it alone */
    select @sql = 'use [' + @db + ']'
      + ' dbcc shrinkfile (N''' + @log + ''', 1) '
  exec(@sql)
end

drop table #tmp


Tags:

SQL Server