# T-SQL Procedures that generate T-SQL JSON CRUD procedures This project contains a set of T-SQL scripts that generate: - Stored procedures that INSERT, UPDATE, or MERGE input JSON text into table - Stored procedures that generate SELECT statements that generate JSON from SQL tables. ### Contents [About this sample](#about-this-sample)
[Setup](#setup)
[Generate](#generate)
[Modify generated source](#modify)
## About this sample - **Applies to:** SQL Server 2016 (or higher), Azure SQL Database - **Programming Language:** Transact-SQL - **Authors:** Jovan Popovic ## Setup To generate procedures, apply script in generate-json-crud.sql file. ## Generate procedures ** GENERATE CRUD Functions for WWI tables. ** ```sql declare @SchemaName sysname = 'Application' --> Name of the table where we want to insert JSON declare @TableName sysname = 'People' --> Name of the table schema where we want to insert JSON declare @JsonColumns nvarchar(max) = '|CustomFields|' --> List of pipe-separated NVARCHAR(MAX) column names that contain JSON text declare @IgnoredColumns nvarchar(max) = N'LastEditedBy' --> List of comma-separated columns that should not be imported print (codegen.GenerateJsonCreateProcedure('Website', @SchemaName, @TableName, @JsonColumns, @IgnoredColumns)) print (codegen.GenerateJsonRetrieveProcedure('Website', @SchemaName, @TableName, @JsonColumns, @IgnoredColumns)) print (codegen.GenerateJsonUpdateProcedure('Website', @SchemaName, @TableName, @JsonColumns, @IgnoredColumns)) print (codegen.GenerateJsonUpsertProcedure('Website', @SchemaName, @TableName, @JsonColumns, @IgnoredColumns)) GO declare @SchemaName sysname = 'Sales' --> Name of the table where we want to insert JSON declare @TableName sysname = 'Orders' --> Name of the table schema where we want to insert JSON declare @JsonColumns nvarchar(max) = '||' --> List of pipe-separated NVARCHAR(MAX) column names that contain JSON text declare @IgnoredColumns nvarchar(max) = N'LastEditedBy,LastEditedWhen' --> List of comma-separated columns that should not be imported print (codegen.GenerateJsonCreateProcedure('Website', @SchemaName, @TableName, @JsonColumns, @IgnoredColumns)) print (codegen.GenerateJsonRetrieveProcedure('Website', @SchemaName, @TableName, @JsonColumns, @IgnoredColumns)) print (codegen.GenerateJsonUpdateProcedure('Website', @SchemaName, @TableName, @JsonColumns, @IgnoredColumns)) print (codegen.GenerateJsonUpsertProcedure('Website', @SchemaName, @TableName, @JsonColumns, @IgnoredColumns)) GO declare @SchemaName sysname = 'Application' --> Name of the table where we want to insert JSON declare @TableName sysname = 'Countries' --> Name of the table schema where we want to insert JSON declare @JsonColumns nvarchar(max) = '||' --> List of pipe-separated NVARCHAR(MAX) column names that contain JSON text, e.g. '|AdditionalContactInfo|Demographics|' declare @IgnoredColumns nvarchar(max) = N'LastEditedBy' --> List of comma-separated columns that should not be imported print (codegen.GenerateJsonCreateProcedure('Website', @SchemaName, @TableName, @JsonColumns, @IgnoredColumns)) print (codegen.GenerateJsonRetrieveProcedure('Website', @SchemaName, @TableName, @JsonColumns, @IgnoredColumns)) print (codegen.GenerateJsonUpdateProcedure('Website', @SchemaName, @TableName, @JsonColumns, @IgnoredColumns)) print (codegen.GenerateJsonUpsertProcedure('Website', @SchemaName, @TableName, @JsonColumns, @IgnoredColumns)) GO declare @SchemaName sysname = 'Application' --> Name of the table where we want to insert JSON declare @TableName sysname = 'Cities' --> Name of the table schema where we want to insert JSON declare @JsonColumns nvarchar(max) = '||' --> List of pipe-separated NVARCHAR(MAX) column names that contain JSON text, e.g. '|AdditionalContactInfo|Demographics|' declare @IgnoredColumns nvarchar(max) = N'Location,LastEditedBy' --> List of comma-separated columns that should not be imported print (codegen.GenerateJsonCreateProcedure('Website', @SchemaName, @TableName, @JsonColumns, @IgnoredColumns)) print (codegen.GenerateJsonRetrieveProcedure('Website', @SchemaName, @TableName, @JsonColumns, @IgnoredColumns)) print (codegen.GenerateJsonUpdateProcedure('Website', @SchemaName, @TableName, @JsonColumns, @IgnoredColumns)) print (codegen.GenerateJsonUpsertProcedure('Website', @SchemaName, @TableName, @JsonColumns, @IgnoredColumns)) ``` **GENERATE CRUD Functions for Custom table.** ```sql DROP TABLE IF EXISTS dbo.Product GO CREATE TABLE dbo.Product( ProductID int IDENTITY PRIMARY KEY, Name nvarchar(50) NOT NULL, Color nvarchar(15) NULL, Size nvarchar(5) NULL, Price money NOT NULL, [Special JSON chars: " \ / ] int NULL, [Special sql chars [[ " ]] ] int NULL, Data nvarchar(4000) NULL, Tags nvarchar(4000) NULL, DateCreated datetime2 NOT NULL DEFAULT(GETDATE()) ) GO declare @SchemaName sysname = 'dbo' --> Name of the table where we want to insert JSON declare @TableName sysname = 'Product' --> Name of the table schema where we want to insert JSON declare @JsonColumns nvarchar(max) = '|Data|Tags|' --> List of pipe-separated NVARCHAR(MAX) column names that contain JSON text, e.g. '|AdditionalContactInfo|Demographics|' declare @IgnoredColumns nvarchar(max) = N'DateCreated' --> List of comma-separated columns that should not be imported print (codegen.GenerateJsonCreateProcedure('dbo', @SchemaName, @TableName, @JsonColumns, @IgnoredColumns)) print (codegen.GenerateJsonRetrieveProcedure('dbo', @SchemaName, @TableName, @JsonColumns, @IgnoredColumns)) print (codegen.GenerateJsonUpdateProcedure('dbo', @SchemaName, @TableName, @JsonColumns, @IgnoredColumns)) print (codegen.GenerateJsonUpsertProcedure('dbo', @SchemaName, @TableName, @JsonColumns, @IgnoredColumns)) ``` ## Modify generated code You can create your own functions codegen.GenerateProcedureHead and codegen.GenerateProcedureTail to generate custom header and footer for every generated procedure, e.g.: ```sql DROP FUNCTION IF EXISTS codegen.GenerateProcedureHead GO CREATE FUNCTION codegen.GenerateProcedureHead(@Table sysname, @JsonParam sysname) RETURNS NVARCHAR(max) AS BEGIN Declare @ret nvarchar(max) = ' SET XACT_ABORT ON; DECLARE @HelpMessage nvarchar(max) = N''JSON '+ @Table +' data is invalid. Execute SELECT TOP 1 * FROM ' + @Table + ' FOR JSON PATH to see an example of required JSON structure.''; IF ISJSON('+ @JsonParam + ') = 0 BEGIN PRINT @HelpMessage; THROW 51000, N'''+ @JsonParam + ' must be valid JSON data'', 1; RETURN 1; END; BEGIN TRY BEGIN TRAN; '; RETURN @ret END GO GO DROP FUNCTION IF EXISTS codegen.GenerateProcedureTail GO CREATE FUNCTION codegen.GenerateProcedureTail(@Table sysname) RETURNS NVARCHAR(max) AS BEGIN Declare @ret nvarchar(max) = ' IF @@ROWCOUNT = 0 BEGIN PRINT N''Warning: No valid '+@Table+' data found''; PRINT @HelpMessage; END; COMMIT; END TRY BEGIN CATCH PRINT @HelpMessage; PRINT ERROR_MESSAGE(); THROW 51000, N''Valid JSON was supplied but does not match the '+@Table+' array structure'', 2; IF XACT_STATE() <> 0 ROLLBACK TRAN; RETURN 1; END CATCH; '; RETURN @ret END GO ``` ## Code of Conduct This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. ## License These samples and templates are all licensed under the MIT license. See the license.txt file in the root. ## Questions Email questions to: [sqlserversamples@microsoft.com](mailto: sqlserversamples@microsoft.com).