Customer support ticketing system in SQL Serve

Customer support ticketing system in SQL Server with a well-structured set of tables and stored procedures, including full examples for:

  • ✅ Insert ticket

  • ✏️ Update ticket

  • ๐Ÿ” Search/filter tickets

  • ๐Ÿ”„ Assign/close/reopen

  • ๐Ÿ“„ Pagination

  • ๐Ÿงพ Audit logging

  • ๐Ÿ“‹ Supporting tables (e.g., users, categories, statuses)


๐Ÿ“ฆ 1. Database Table Structure for Support Ticket System

๐ŸŽซ SupportTickets

CREATE TABLE SupportTickets ( TicketId INT IDENTITY(1,1) PRIMARY KEY, Title NVARCHAR(200), Description NVARCHAR(MAX), StatusId INT, CategoryId INT, PriorityId INT, CustomerId INT, AssignedTo INT NULL, CreatedBy NVARCHAR(50), CreatedDate DATETIME DEFAULT GETDATE(), UpdatedBy NVARCHAR(50), UpdatedDate DATETIME, IsDeleted BIT DEFAULT 0 );

๐Ÿ‘ค Users

CREATE TABLE Users ( UserId INT IDENTITY(1,1) PRIMARY KEY, UserName NVARCHAR(100), Role NVARCHAR(50) -- e.g., Customer, Agent, Admin );

๐Ÿ“‚ Categories

CREATE TABLE Categories ( CategoryId INT IDENTITY(1,1) PRIMARY KEY, Name NVARCHAR(100) );

๐Ÿšฆ Statuses

CREATE TABLE Statuses ( StatusId INT IDENTITY(1,1) PRIMARY KEY, Name NVARCHAR(50) -- e.g., Open, In Progress, Closed, Reopened );

๐Ÿท️ Priorities

CREATE TABLE Priorities ( PriorityId INT IDENTITY(1,1) PRIMARY KEY, Name NVARCHAR(50) -- e.g., Low, Medium, High, Urgent );

๐Ÿ“œ TicketAuditLog

CREATE TABLE TicketAuditLog ( AuditId INT IDENTITY(1,1) PRIMARY KEY, TicketId INT, Action NVARCHAR(100), PerformedBy NVARCHAR(50), ActionDate DATETIME DEFAULT GETDATE(), Notes NVARCHAR(MAX) );

⚙️ 2. Stored Procedures

✅ Insert a New Ticket

CREATE PROCEDURE usp_InsertSupportTicket @Title NVARCHAR(200), @Description NVARCHAR(MAX), @CategoryId INT, @PriorityId INT, @CustomerId INT, @CreatedBy NVARCHAR(50) AS BEGIN SET NOCOUNT ON; DECLARE @TicketId INT; BEGIN TRY BEGIN TRANSACTION; INSERT INTO SupportTickets ( Title, Description, StatusId, CategoryId, PriorityId, CustomerId, CreatedBy, CreatedDate ) VALUES ( @Title, @Description, 1, -- Default to 'Open' @CategoryId, @PriorityId, @CustomerId, @CreatedBy, GETDATE() ); SET @TicketId = SCOPE_IDENTITY(); INSERT INTO TicketAuditLog (TicketId, Action, PerformedBy, Notes) VALUES (@TicketId, 'Created', @CreatedBy, 'Ticket created.'); COMMIT; END TRY BEGIN CATCH ROLLBACK; THROW; END CATCH END

✏️ Update Ticket Info (without changing status)

CREATE PROCEDURE usp_UpdateSupportTicket @TicketId INT, @Title NVARCHAR(200), @Description NVARCHAR(MAX), @CategoryId INT, @PriorityId INT, @UpdatedBy NVARCHAR(50) AS BEGIN SET NOCOUNT ON; BEGIN TRY BEGIN TRANSACTION; UPDATE SupportTickets SET Title = @Title, Description = @Description, CategoryId = @CategoryId, PriorityId = @PriorityId, UpdatedBy = @UpdatedBy, UpdatedDate = GETDATE() WHERE TicketId = @TicketId AND IsDeleted = 0; INSERT INTO TicketAuditLog (TicketId, Action, PerformedBy, Notes) VALUES (@TicketId, 'Updated', @UpdatedBy, 'Ticket details updated.'); COMMIT; END TRY BEGIN CATCH ROLLBACK; THROW; END CATCH END

๐Ÿ”„ Change Status (Assign, Close, Reopen)

CREATE PROCEDURE usp_ChangeTicketStatus @TicketId INT, @NewStatusId INT, @AssignedTo INT = NULL, @PerformedBy NVARCHAR(50), @Notes NVARCHAR(MAX) = NULL AS BEGIN SET NOCOUNT ON; BEGIN TRY BEGIN TRANSACTION; UPDATE SupportTickets SET StatusId = @NewStatusId, AssignedTo = @AssignedTo, UpdatedBy = @PerformedBy, UpdatedDate = GETDATE() WHERE TicketId = @TicketId AND IsDeleted = 0; INSERT INTO TicketAuditLog (TicketId, Action, PerformedBy, Notes) VALUES (@TicketId, 'Status Changed', @PerformedBy, @Notes); COMMIT; END TRY BEGIN CATCH ROLLBACK; THROW; END CATCH END

๐Ÿ” Search Tickets with Filters

CREATE PROCEDURE usp_SearchSupportTickets @CustomerId INT = NULL, @AssignedTo INT = NULL, @StatusId INT = NULL, @CategoryId INT = NULL, @FromDate DATETIME = NULL, @ToDate DATETIME = NULL AS BEGIN SET NOCOUNT ON; SELECT T.TicketId, T.Title, T.StatusId, S.Name AS StatusName, T.CategoryId, C.Name AS CategoryName, T.PriorityId, P.Name AS PriorityName, T.CreatedDate, T.AssignedTo, T.CustomerId FROM SupportTickets T JOIN Statuses S ON T.StatusId = S.StatusId JOIN Categories C ON T.CategoryId = C.CategoryId JOIN Priorities P ON T.PriorityId = P.PriorityId WHERE (@CustomerId IS NULL OR T.CustomerId = @CustomerId) AND (@AssignedTo IS NULL OR T.AssignedTo = @AssignedTo) AND (@StatusId IS NULL OR T.StatusId = @StatusId) AND (@CategoryId IS NULL OR T.CategoryId = @CategoryId) AND (@FromDate IS NULL OR T.CreatedDate >= @FromDate) AND (@ToDate IS NULL OR T.CreatedDate <= @ToDate) AND T.IsDeleted = 0 ORDER BY T.CreatedDate DESC; END

๐Ÿ“„ Paged Ticket List

CREATE PROCEDURE usp_GetPagedTickets @PageNumber INT = 1, @PageSize INT = 10 AS BEGIN SET NOCOUNT ON; DECLARE @Offset INT = (@PageNumber - 1) * @PageSize; SELECT T.TicketId, T.Title, T.CreatedDate, U.UserName AS AssignedTo FROM SupportTickets T LEFT JOIN Users U ON T.AssignedTo = U.UserId WHERE T.IsDeleted = 0 ORDER BY T.CreatedDate DESC OFFSET @Offset ROWS FETCH NEXT @PageSize ROWS ONLY; END


What Is Power BI SQL Server

Power BI is a powerful business intelligence tool by Microsoft that allows you to connect to data sources like SQL Server, transform and model the data, and create interactive visualizations and dashboards. It’s widely used for reporting, analytics, and decision-making.

What Is Power BI?

Power BI consists of:

  • Power BI Desktop: A Windows application for building reports.

  • Power BI Service: A cloud platform for sharing and collaborating.

  • Power BI Gateway: Connects on-premises data (like SQL Server) to the cloud.

  • Power BI Mobile: View reports on mobile devices.

๐Ÿ”— How Power BI Connects to SQL Server

Step-by-Step Example:

  1. Open Power BI Desktop

  2. Click Get Data → Choose SQL Server

  3. Enter:

    • Server name

    • Database name (optional)

  4. Choose Import or DirectQuery mode

  5. Select tables or write a custom SQL query

  6. Click Load to bring data into Power BI


๐Ÿ“Š Example Use Case: KPI Dashboard from SQL Server

Imagine you have a SQL Server table with monthly customer service KPIs:

MonthTargetActualVarianceComments

You can:

  • Import this table into Power BI

  • Create visuals like bar charts, gauges, and trend lines

  • Use slicers to filter by month or department

  • Publish the report to Power BI Service for sharing


๐Ÿง  Advantages of Using Power BI with SQL Server

BenefitDescription
๐Ÿ”„ Real-time updatesUse DirectQuery or scheduled refresh
๐Ÿ“ˆ Rich visualizationsCharts, maps, KPIs, and custom visuals
๐Ÿ” Secure accessRole-level security and Azure integration
๐Ÿงฉ Data modelingRelationships, DAX formulas, calculated columns
๐Ÿ“ค Easy sharingPublish to Power BI Service or Teams

starter ASP.NET Core Web API project with example

Starter ASP.NET Core Web API project that follows all the best practices listed above.


๐Ÿ› ️ Starter Project Overview

We’ll build a Product Catalog API with the following features:

๐Ÿ”ง Tech Stack:

  • ASP.NET Core 8

  • Entity Framework Core (In-Memory for now)

  • DTOs and Services

  • Validation

  • API Versioning

  • Swagger (OpenAPI)

  • Global Exception Handling

  • Logging

  • Async support

  • Dependency Injection

  • Clean architecture (Controllers → Services → Repository)


๐Ÿ“ Project Structure:

mathematica

ProductCatalogApi/ ├── Controllers/ │ └── v1/ │ └── ProductsController.cs ├── Dtos/ │ └── ProductDto.cs ├── Entities/ │ └── Product.cs ├── Interfaces/ │ └── IProductService.cs │ └── IProductRepository.cs ├── Repositories/ │ └── ProductRepository.cs ├── Services/ │ └── ProductService.cs ├── Middlewares/ │ └── ExceptionMiddleware.cs ├── Data/ │ └── ApplicationDbContext.cs ├── Program.cs └── ProductCatalogApi.csproj

✅ 1. Initialize Project

Create the project:

bash

dotnet new webapi -n ProductCatalogApi cd ProductCatalogApi

Enable nullable and implicit usings in csproj (optional):

xml

<Nullable>enable</Nullable> <ImplicitUsings>enable</ImplicitUsings>

✅ 2. Create Product Entity

Entities/Product.cs

csharp

namespace ProductCatalogApi.Entities; public class Product { public int Id { get; set; } public string Name { get; set; } = string.Empty; public decimal Price { get; set; } }

✅ 3. Create DTO

Dtos/ProductDto.cs

csharp

using System.ComponentModel.DataAnnotations; namespace ProductCatalogApi.Dtos; public class ProductDto { public int Id { get; set; } [Required] [StringLength(100)] public string Name { get; set; } = string.Empty; [Range(0.01, 10000)] public decimal Price { get; set; } }

✅ 4. ApplicationDbContext

Data/ApplicationDbContext.cs

csharp

using Microsoft.EntityFrameworkCore; using ProductCatalogApi.Entities; namespace ProductCatalogApi.Data; public class ApplicationDbContext : DbContext { public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { } public DbSet<Product> Products => Set<Product>(); }

✅ 5. Repository

Interfaces/IProductRepository.cs

csharp

using ProductCatalogApi.Entities; namespace ProductCatalogApi.Interfaces; public interface IProductRepository { Task<IEnumerable<Product>> GetAllAsync(); Task<Product?> GetByIdAsync(int id); Task<Product> AddAsync(Product product); Task UpdateAsync(Product product); Task DeleteAsync(Product product); }

Repositories/ProductRepository.cs

csharp

using Microsoft.EntityFrameworkCore; using ProductCatalogApi.Data; using ProductCatalogApi.Entities; using ProductCatalogApi.Interfaces; namespace ProductCatalogApi.Repositories; public class ProductRepository : IProductRepository { private readonly ApplicationDbContext _context; public ProductRepository(ApplicationDbContext context) { _context = context; } public async Task<IEnumerable<Product>> GetAllAsync() => await _context.Products.ToListAsync(); public async Task<Product?> GetByIdAsync(int id) => await _context.Products.FindAsync(id); public async Task<Product> AddAsync(Product product) { _context.Products.Add(product); await _context.SaveChangesAsync(); return product; } public async Task UpdateAsync(Product product) { _context.Products.Update(product); await _context.SaveChangesAsync(); } public async Task DeleteAsync(Product product) { _context.Products.Remove(product); await _context.SaveChangesAsync(); } }

✅ 6. Service Layer

Interfaces/IProductService.cs

csharp

using ProductCatalogApi.Dtos; namespace ProductCatalogApi.Interfaces; public interface IProductService { Task<IEnumerable<ProductDto>> GetAllAsync(); Task<ProductDto?> GetByIdAsync(int id); Task<ProductDto> CreateAsync(ProductDto dto); Task<bool> UpdateAsync(int id, ProductDto dto); Task<bool> DeleteAsync(int id); }

Services/ProductService.cs

csharp

using ProductCatalogApi.Dtos; using ProductCatalogApi.Entities; using ProductCatalogApi.Interfaces; namespace ProductCatalogApi.Services; public class ProductService : IProductService { private readonly IProductRepository _repo; public ProductService(IProductRepository repo) { _repo = repo; } public async Task<IEnumerable<ProductDto>> GetAllAsync() { var products = await _repo.GetAllAsync(); return products.Select(p => new ProductDto { Id = p.Id, Name = p.Name, Price = p.Price }); } public async Task<ProductDto?> GetByIdAsync(int id) { var product = await _repo.GetByIdAsync(id); if (product == null) return null; return new ProductDto { Id = product.Id, Name = product.Name, Price = product.Price }; } public async Task<ProductDto> CreateAsync(ProductDto dto) { var product = new Product { Name = dto.Name, Price = dto.Price }; var result = await _repo.AddAsync(product); return new ProductDto { Id = result.Id, Name = result.Name, Price = result.Price }; } public async Task<bool> UpdateAsync(int id, ProductDto dto) { var existing = await _repo.GetByIdAsync(id); if (existing == null) return false; existing.Name = dto.Name; existing.Price = dto.Price; await _repo.UpdateAsync(existing); return true; } public async Task<bool> DeleteAsync(int id) { var existing = await _repo.GetByIdAsync(id); if (existing == null) return false; await _repo.DeleteAsync(existing); return true; } }

✅ 7. Controller

Controllers/v1/ProductsController.cs

csharp

using Microsoft.AspNetCore.Mvc; using ProductCatalogApi.Dtos; using ProductCatalogApi.Interfaces; namespace ProductCatalogApi.Controllers.v1; [ApiController] [ApiVersion("1.0")] [Route("api/v{version:apiVersion}/[controller]")] public class ProductsController : ControllerBase { private readonly IProductService _service; public ProductsController(IProductService service) { _service = service; } [HttpGet] public async Task<IActionResult> GetAll() => Ok(await _service.GetAllAsync()); [HttpGet("{id}")] public async Task<IActionResult> Get(int id) { var product = await _service.GetByIdAsync(id); if (product == null) return NotFound(); return Ok(product); } [HttpPost] public async Task<IActionResult> Create(ProductDto dto) { if (!ModelState.IsValid) return BadRequest(ModelState); var product = await _service.CreateAsync(dto); return CreatedAtAction(nameof(Get), new { id = product.Id }, product); } [HttpPut("{id}")] public async Task<IActionResult> Update(int id, ProductDto dto) { if (!ModelState.IsValid) return BadRequest(ModelState); var updated = await _service.UpdateAsync(id, dto); return updated ? NoContent() : NotFound(); } [HttpDelete("{id}")] public async Task<IActionResult> Delete(int id) { var deleted = await _service.DeleteAsync(id); return deleted ? NoContent() : NotFound(); } }

✅ 8. Middleware for Error Handling

Middlewares/ExceptionMiddleware.cs

csharp

namespace ProductCatalogApi.Middlewares; public class ExceptionMiddleware { private readonly RequestDelegate _next; private readonly ILogger<ExceptionMiddleware> _logger; public ExceptionMiddleware(RequestDelegate next, ILogger<ExceptionMiddleware> logger) { _next = next; _logger = logger; } public async Task InvokeAsync(HttpContext context) { try { await _next(context); } catch (Exception ex) { _logger.LogError(ex, "Unhandled Exception"); context.Response.StatusCode = 500; await context.Response.WriteAsJsonAsync(new { error = "An unexpected error occurred." }); } } }

✅ 9. Configure Program.cs

Program.cs

csharp

using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using ProductCatalogApi.Data; using ProductCatalogApi.Interfaces; using ProductCatalogApi.Middlewares; using ProductCatalogApi.Repositories; using ProductCatalogApi.Services; var builder = WebApplication.CreateBuilder(args); // DB builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseInMemoryDatabase("ProductDb")); // Services builder.Services.AddScoped<IProductService, ProductService>(); builder.Services.AddScoped<IProductRepository, ProductRepository>(); // Swagger builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); // Versioning builder.Services.AddApiVersioning(options => { options.DefaultApiVersion = new ApiVersion(1, 0); options.AssumeDefaultVersionWhenUnspecified = true; options.ReportApiVersions = true; }); // Controllers builder.Services.AddControllers(); var app = builder.Build(); // Middlewares app.UseMiddleware<ExceptionMiddleware>(); if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run();

✅ 10. Run the App


dotnet run

Visit:

  • Swagger: https://localhost:{port}/swagger

  • Try endpoints like:

    • GET /api/v1/products

    • POST /api/v1/products


IIS URL & Request Related Variables

 Sure! These variables are typically found in web server environments like Apache or IIS and are used by server-side applications (like PHP, Python, ASP.NET, etc.) to understand request data, file paths, and configuration settings.

Below is an explanation of each with examples where applicable.


✅ URL & Request Related Variables


1. CACHE_URL

  • Description: IIS-specific; relates to cached URLs in output caching.

  • Example: /cached-page.html

  • Use: Used internally by IIS for cached content lookup.


2. DOCUMENT_ROOT

  • Description: The absolute path to the root directory for the web server (where web content is served from).

  • Example:
    C:/inetpub/wwwroot (Windows IIS)
    /var/www/html (Apache/Linux)


3. HTTP_URL

  • Description: Often a custom environment variable; not always standard. Could represent the full HTTP URL.

  • Example: http://example.com/index.php?user=123


4. HTTP_HOST

  • Description: Host header sent by the client.

  • Example: www.example.com


5. PATH_INFO

  • Description: Extra path information provided after the script name in the URL.

  • Example: If URL is /index.php/user/123, and script is index.php, then:
    PATH_INFO = /user/123


6. PATH_TRANSLATED

  • Description: Filesystem path equivalent to PATH_INFO.

  • Example:
    C:/inetpub/wwwroot/user/123


7. QUERY_STRING

  • Description: The query string part of the URL after the ?.

  • Example:
    For /index.php?id=10&name=John,
    QUERY_STRING = id=10&name=John


8. REQUEST_FILENAME

  • Description: The absolute file path to the script being executed.

  • Example:
    /var/www/html/index.php


9. REQUEST_URI

  • Description: The full URI as requested by the client, including path and query string.

  • Example:
    /index.php?user=123


10. SCRIPT_FILENAME

  • Description: The absolute path to the script being executed (like index.php).

  • Example:
    C:/inetpub/wwwroot/index.php


11. SCRIPT_NAME

  • Description: The relative path to the script from the root of the website.

  • Example:
    /index.php


12. SCRIPT_TRANSLATED

  • Description: IIS-specific variable; maps the requested URI to a physical path.

  • Example:
    If URL is /foo/bar,
    SCRIPT_TRANSLATED = C:\inetpub\wwwroot\foo\bar


13. UNENCODED_URL

  • Description: IIS variable; shows the original URL before encoding.

  • Example:
    /path with space/file.html (not URL-encoded)


14. URL

  • Description: IIS variable; the URL portion of the request.

  • Example:
    /index.php


15. URL_PATH_INFO

  • Description: IIS variable; similar to PATH_INFO, often used in ISAPI applications.

  • Example:
    /extra/path/data



✅ IIS or Application Pool Related Variables


16. APP_POOL_ID

  • Description: Name of the IIS Application Pool that is processing the request.

  • Example:
    DefaultAppPool


17. APPL_MD_PATH

  • Description: The IIS metabase path for the application.

  • Example:
    /LM/W3SVC/1/ROOT


18. APPL_PHYSICAL_PATH

  • Description: Physical file system path to the application root.

  • Example:
    C:\inetpub\wwwroot\myapp\


19. GATEWAY_INTERFACE

  • Description: The version of the Common Gateway Interface (CGI) used.

  • Example:
    CGI/1.1


20. SERVER_SOFTWARE

  • Description: The name and version of the server software.

  • Example:
    Microsoft-IIS/10.0
    or
    Apache/2.4.41 (Unix)


21. SSI_EXEC_DISABLED

  • Description: IIS-specific; indicates that execution of commands via Server Side Includes (SSI) is disabled.

  • Example:
    true or false


✅ Summary Table

VariableDescriptionExample
CACHE_URLCached URL used by IIS/page.html
DOCUMENT_ROOTWeb root pathC:/inetpub/wwwroot
HTTP_URLFull URL (not standard)http://example.com/path
HTTP_HOSTDomain name from Host headerexample.com
PATH_INFOExtra path after script/user/123
PATH_TRANSLATEDFilesystem path from PATH_INFOC:/.../user/123
QUERY_STRINGURL query stringid=5&name=test
REQUEST_FILENAMEFull file path to requested file/var/www/index.php
REQUEST_URIEntire URI sent by client/index.php?x=1
SCRIPT_FILENAMEFull file path of the scriptC:/.../index.php
SCRIPT_NAMERelative path to the script/index.php
SCRIPT_TRANSLATEDMapped physical path of script (IIS)C:/.../foo/bar
UNENCODED_URLOriginal URL before encoding (IIS)/path with space/
URLURL part of the request (IIS)/index.php
URL_PATH_INFOExtra path info (IIS)/info/here
APP_POOL_IDName of the app pool (IIS)DefaultAppPool
APPL_MD_PATHIIS metabase path/LM/W3SVC/1/ROOT
APPL_PHYSICAL_PATHPhysical path to applicationC:/inetpub/...
GATEWAY_INTERFACECGI versionCGI/1.1
SERVER_SOFTWAREWeb server name/versionIIS/10.0
SSI_EXEC_DISABLEDWhether SSI execution is disabled (IIS)true

Explain the difference between Subject, BehaviorSubject, ReplaySubject, and AsyncSubject

 

Scenario:

You’re building a shared service that needs to hold the latest value of a user’s settings and broadcast it across multiple components.


Answer:

  • Subject: Multicast, emits only to subscribers at the time of emission.

  • BehaviorSubject: Remembers the latest emitted value, emits it immediately to new subscribers.

  • ReplaySubject: Remembers a specified number of past values and replays them to new subscribers.

  • AsyncSubject: Emits only the last value upon completion.


Example:

const subject = new BehaviorSubject<string>('default'); subject.subscribe(console.log); // logs: default subject.next('new value'); // logs: new value

SQL Server auto generate UNIQUEIDENTIFIER

 Insert data into a table ✅ Have SQL Server auto-generate both: Id (as INT IDENTITY ) RowGuid (as UNIQUEIDENTIFIER , using NEWID()...

Best for you