From b65ccdc9f4e9db0b49f4680bee713e6c31108e26 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 8 Nov 2025 11:49:39 +0000 Subject: [PATCH 1/2] Add Futon Manufacturing Database Sample MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds a comprehensive SQL Server database sample for a futon manufacturing business with multi-level bill of materials (BOM), complete sample data, and 20 manufacturing reports. Features: - Multi-level BOM supporting raw materials, components, and finished goods - Inventory management across multiple warehouses with transaction tracking - Production order management with work centers and capacity planning - Quality control inspection tracking - Purchasing and supplier performance management - Sales order and customer fulfillment tracking - 20 comprehensive manufacturing reports including: - BOM explosion and where-used analysis - Material requirements planning (MRP) - Inventory valuation and turnover analysis - Production scheduling and capacity analysis - Quality and scrap analysis - Supplier and customer performance metrics Database includes: - Complete schema with 25+ tables - Sample data: 42 items, 5 suppliers, 8 customers, 3 warehouses - Product hierarchy: 21 raw materials → 15 components → 6 finished goods - 20 reporting views for operational insights - Sample queries demonstrating common use cases - Comprehensive documentation in README Files: - 01-schema.sql - Database schema and table definitions - 02-sample-data.sql - Sample reference and master data - 03-manufacturing-reports.sql - 20 manufacturing report views - 04-sample-queries.sql - Example queries and use cases - README.md - Complete documentation and usage guide --- .../futon-manufacturing/01-schema.sql | 369 ++++++++ .../futon-manufacturing/02-sample-data.sql | 426 +++++++++ .../03-manufacturing-reports.sql | 883 ++++++++++++++++++ .../futon-manufacturing/04-sample-queries.sql | 539 +++++++++++ .../databases/futon-manufacturing/README.md | 367 ++++++++ 5 files changed, 2584 insertions(+) create mode 100644 samples/databases/futon-manufacturing/01-schema.sql create mode 100644 samples/databases/futon-manufacturing/02-sample-data.sql create mode 100644 samples/databases/futon-manufacturing/03-manufacturing-reports.sql create mode 100644 samples/databases/futon-manufacturing/04-sample-queries.sql create mode 100644 samples/databases/futon-manufacturing/README.md diff --git a/samples/databases/futon-manufacturing/01-schema.sql b/samples/databases/futon-manufacturing/01-schema.sql new file mode 100644 index 0000000000..6a142161fb --- /dev/null +++ b/samples/databases/futon-manufacturing/01-schema.sql @@ -0,0 +1,369 @@ +-- ============================================= +-- Futon Manufacturing Database Schema +-- ============================================= +-- This database manages a futon manufacturing business with multi-level +-- bill of materials, inventory, production, and sales tracking. +-- ============================================= + +USE master; +GO + +-- Drop database if exists +IF EXISTS (SELECT name FROM sys.databases WHERE name = N'FutonManufacturing') +BEGIN + ALTER DATABASE FutonManufacturing SET SINGLE_USER WITH ROLLBACK IMMEDIATE; + DROP DATABASE FutonManufacturing; +END +GO + +CREATE DATABASE FutonManufacturing; +GO + +USE FutonManufacturing; +GO + +-- ============================================= +-- Reference Tables +-- ============================================= + +-- Unit of Measure +CREATE TABLE UnitOfMeasure ( + UnitID INT IDENTITY(1,1) PRIMARY KEY, + UnitCode NVARCHAR(10) NOT NULL UNIQUE, + UnitName NVARCHAR(50) NOT NULL, + Description NVARCHAR(255) +); + +-- Item Types (Raw Material, Component, Finished Good) +CREATE TABLE ItemType ( + ItemTypeID INT IDENTITY(1,1) PRIMARY KEY, + TypeCode NVARCHAR(20) NOT NULL UNIQUE, + TypeName NVARCHAR(100) NOT NULL, + Description NVARCHAR(255) +); + +-- ============================================= +-- Items Master Table +-- ============================================= + +CREATE TABLE Items ( + ItemID INT IDENTITY(1,1) PRIMARY KEY, + ItemCode NVARCHAR(50) NOT NULL UNIQUE, + ItemName NVARCHAR(255) NOT NULL, + ItemTypeID INT NOT NULL, + UnitID INT NOT NULL, + Description NVARCHAR(MAX), + StandardCost DECIMAL(18,4) NOT NULL DEFAULT 0, + ListPrice DECIMAL(18,4) NOT NULL DEFAULT 0, + IsActive BIT NOT NULL DEFAULT 1, + LeadTimeDays INT DEFAULT 0, + ReorderPoint DECIMAL(18,2) DEFAULT 0, + SafetyStock DECIMAL(18,2) DEFAULT 0, + CreatedDate DATETIME2 DEFAULT GETDATE(), + ModifiedDate DATETIME2 DEFAULT GETDATE(), + CONSTRAINT FK_Items_ItemType FOREIGN KEY (ItemTypeID) REFERENCES ItemType(ItemTypeID), + CONSTRAINT FK_Items_UnitOfMeasure FOREIGN KEY (UnitID) REFERENCES UnitOfMeasure(UnitID) +); + +-- ============================================= +-- Bill of Materials (Multi-Level) +-- ============================================= + +CREATE TABLE BillOfMaterials ( + BOMID INT IDENTITY(1,1) PRIMARY KEY, + ParentItemID INT NOT NULL, + ComponentItemID INT NOT NULL, + Quantity DECIMAL(18,4) NOT NULL, + UnitID INT NOT NULL, + ScrapRate DECIMAL(5,2) DEFAULT 0, -- Percentage + EffectiveDate DATE DEFAULT CAST(GETDATE() AS DATE), + EndDate DATE NULL, + BOMLevel INT NOT NULL DEFAULT 0, -- 0 = top level, increases for sub-components + IsActive BIT NOT NULL DEFAULT 1, + Notes NVARCHAR(MAX), + CreatedDate DATETIME2 DEFAULT GETDATE(), + ModifiedDate DATETIME2 DEFAULT GETDATE(), + CONSTRAINT FK_BOM_ParentItem FOREIGN KEY (ParentItemID) REFERENCES Items(ItemID), + CONSTRAINT FK_BOM_ComponentItem FOREIGN KEY (ComponentItemID) REFERENCES Items(ItemID), + CONSTRAINT FK_BOM_Unit FOREIGN KEY (UnitID) REFERENCES UnitOfMeasure(UnitID), + CONSTRAINT CHK_BOM_NotSelf CHECK (ParentItemID <> ComponentItemID) +); + +-- Index for BOM queries +CREATE NONCLUSTERED INDEX IX_BOM_Parent ON BillOfMaterials(ParentItemID) INCLUDE (ComponentItemID, Quantity); +CREATE NONCLUSTERED INDEX IX_BOM_Component ON BillOfMaterials(ComponentItemID); + +-- ============================================= +-- Inventory Management +-- ============================================= + +CREATE TABLE Warehouse ( + WarehouseID INT IDENTITY(1,1) PRIMARY KEY, + WarehouseCode NVARCHAR(20) NOT NULL UNIQUE, + WarehouseName NVARCHAR(100) NOT NULL, + Address NVARCHAR(255), + City NVARCHAR(100), + State NVARCHAR(50), + ZipCode NVARCHAR(20), + IsActive BIT NOT NULL DEFAULT 1 +); + +CREATE TABLE Inventory ( + InventoryID INT IDENTITY(1,1) PRIMARY KEY, + ItemID INT NOT NULL, + WarehouseID INT NOT NULL, + QuantityOnHand DECIMAL(18,2) NOT NULL DEFAULT 0, + QuantityAllocated DECIMAL(18,2) NOT NULL DEFAULT 0, + QuantityAvailable AS (QuantityOnHand - QuantityAllocated) PERSISTED, + LastCountDate DATETIME2, + LastUpdated DATETIME2 DEFAULT GETDATE(), + CONSTRAINT FK_Inventory_Item FOREIGN KEY (ItemID) REFERENCES Items(ItemID), + CONSTRAINT FK_Inventory_Warehouse FOREIGN KEY (WarehouseID) REFERENCES Warehouse(WarehouseID), + CONSTRAINT UQ_Inventory_Item_Warehouse UNIQUE (ItemID, WarehouseID) +); + +CREATE TABLE TransactionType ( + TransactionTypeID INT IDENTITY(1,1) PRIMARY KEY, + TypeCode NVARCHAR(20) NOT NULL UNIQUE, + TypeName NVARCHAR(100) NOT NULL, + Description NVARCHAR(255) +); + +CREATE TABLE InventoryTransaction ( + TransactionID INT IDENTITY(1,1) PRIMARY KEY, + ItemID INT NOT NULL, + WarehouseID INT NOT NULL, + TransactionTypeID INT NOT NULL, + Quantity DECIMAL(18,2) NOT NULL, + UnitCost DECIMAL(18,4), + ReferenceNumber NVARCHAR(50), + ReferenceType NVARCHAR(50), -- PO, SO, WO, ADJ, etc. + Notes NVARCHAR(MAX), + TransactionDate DATETIME2 DEFAULT GETDATE(), + CreatedBy NVARCHAR(100), + CONSTRAINT FK_InvTrans_Item FOREIGN KEY (ItemID) REFERENCES Items(ItemID), + CONSTRAINT FK_InvTrans_Warehouse FOREIGN KEY (WarehouseID) REFERENCES Warehouse(WarehouseID), + CONSTRAINT FK_InvTrans_Type FOREIGN KEY (TransactionTypeID) REFERENCES TransactionType(TransactionTypeID) +); + +CREATE NONCLUSTERED INDEX IX_InvTrans_Date ON InventoryTransaction(TransactionDate DESC); +CREATE NONCLUSTERED INDEX IX_InvTrans_Item ON InventoryTransaction(ItemID, TransactionDate); + +-- ============================================= +-- Supplier Management +-- ============================================= + +CREATE TABLE Supplier ( + SupplierID INT IDENTITY(1,1) PRIMARY KEY, + SupplierCode NVARCHAR(20) NOT NULL UNIQUE, + SupplierName NVARCHAR(255) NOT NULL, + ContactName NVARCHAR(100), + Email NVARCHAR(100), + Phone NVARCHAR(20), + Address NVARCHAR(255), + City NVARCHAR(100), + State NVARCHAR(50), + ZipCode NVARCHAR(20), + Country NVARCHAR(50), + PaymentTerms NVARCHAR(50), + Rating DECIMAL(3,2), -- 0.00 to 5.00 + IsActive BIT NOT NULL DEFAULT 1, + CreatedDate DATETIME2 DEFAULT GETDATE() +); + +CREATE TABLE SupplierItem ( + SupplierItemID INT IDENTITY(1,1) PRIMARY KEY, + SupplierID INT NOT NULL, + ItemID INT NOT NULL, + SupplierPartNumber NVARCHAR(50), + UnitPrice DECIMAL(18,4) NOT NULL, + MinimumOrderQuantity DECIMAL(18,2) DEFAULT 1, + LeadTimeDays INT DEFAULT 0, + IsPreferred BIT NOT NULL DEFAULT 0, + EffectiveDate DATE DEFAULT CAST(GETDATE() AS DATE), + EndDate DATE NULL, + CONSTRAINT FK_SupplierItem_Supplier FOREIGN KEY (SupplierID) REFERENCES Supplier(SupplierID), + CONSTRAINT FK_SupplierItem_Item FOREIGN KEY (ItemID) REFERENCES Items(ItemID) +); + +CREATE TABLE PurchaseOrder ( + PurchaseOrderID INT IDENTITY(1,1) PRIMARY KEY, + PONumber NVARCHAR(50) NOT NULL UNIQUE, + SupplierID INT NOT NULL, + WarehouseID INT NOT NULL, + OrderDate DATE NOT NULL DEFAULT CAST(GETDATE() AS DATE), + ExpectedDeliveryDate DATE, + ActualDeliveryDate DATE, + Status NVARCHAR(20) NOT NULL DEFAULT 'Draft', -- Draft, Submitted, Confirmed, Shipped, Received, Cancelled + Subtotal DECIMAL(18,2) DEFAULT 0, + TaxAmount DECIMAL(18,2) DEFAULT 0, + ShippingAmount DECIMAL(18,2) DEFAULT 0, + TotalAmount DECIMAL(18,2) DEFAULT 0, + Notes NVARCHAR(MAX), + CreatedBy NVARCHAR(100), + CreatedDate DATETIME2 DEFAULT GETDATE(), + ModifiedDate DATETIME2 DEFAULT GETDATE(), + CONSTRAINT FK_PO_Supplier FOREIGN KEY (SupplierID) REFERENCES Supplier(SupplierID), + CONSTRAINT FK_PO_Warehouse FOREIGN KEY (WarehouseID) REFERENCES Warehouse(WarehouseID) +); + +CREATE TABLE PurchaseOrderDetail ( + PODetailID INT IDENTITY(1,1) PRIMARY KEY, + PurchaseOrderID INT NOT NULL, + LineNumber INT NOT NULL, + ItemID INT NOT NULL, + Quantity DECIMAL(18,2) NOT NULL, + UnitPrice DECIMAL(18,4) NOT NULL, + QuantityReceived DECIMAL(18,2) DEFAULT 0, + LineTotal AS (Quantity * UnitPrice) PERSISTED, + CONSTRAINT FK_PODetail_PO FOREIGN KEY (PurchaseOrderID) REFERENCES PurchaseOrder(PurchaseOrderID), + CONSTRAINT FK_PODetail_Item FOREIGN KEY (ItemID) REFERENCES Items(ItemID) +); + +-- ============================================= +-- Production Management +-- ============================================= + +CREATE TABLE WorkCenter ( + WorkCenterID INT IDENTITY(1,1) PRIMARY KEY, + WorkCenterCode NVARCHAR(20) NOT NULL UNIQUE, + WorkCenterName NVARCHAR(100) NOT NULL, + Description NVARCHAR(255), + Capacity DECIMAL(18,2), -- Units per day + IsActive BIT NOT NULL DEFAULT 1 +); + +CREATE TABLE ProductionOrder ( + ProductionOrderID INT IDENTITY(1,1) PRIMARY KEY, + WorkOrderNumber NVARCHAR(50) NOT NULL UNIQUE, + ItemID INT NOT NULL, -- What we're producing + WarehouseID INT NOT NULL, + WorkCenterID INT, + OrderQuantity DECIMAL(18,2) NOT NULL, + QuantityCompleted DECIMAL(18,2) DEFAULT 0, + QuantityScrapped DECIMAL(18,2) DEFAULT 0, + StartDate DATE, + PlannedCompletionDate DATE, + ActualCompletionDate DATE, + Status NVARCHAR(20) NOT NULL DEFAULT 'Planned', -- Planned, Released, InProgress, Completed, Cancelled + Priority INT DEFAULT 5, -- 1 = Highest, 10 = Lowest + Notes NVARCHAR(MAX), + CreatedBy NVARCHAR(100), + CreatedDate DATETIME2 DEFAULT GETDATE(), + ModifiedDate DATETIME2 DEFAULT GETDATE(), + CONSTRAINT FK_ProdOrder_Item FOREIGN KEY (ItemID) REFERENCES Items(ItemID), + CONSTRAINT FK_ProdOrder_Warehouse FOREIGN KEY (WarehouseID) REFERENCES Warehouse(WarehouseID), + CONSTRAINT FK_ProdOrder_WorkCenter FOREIGN KEY (WorkCenterID) REFERENCES WorkCenter(WorkCenterID) +); + +CREATE TABLE ProductionOrderMaterial ( + ProdOrderMaterialID INT IDENTITY(1,1) PRIMARY KEY, + ProductionOrderID INT NOT NULL, + ItemID INT NOT NULL, + RequiredQuantity DECIMAL(18,2) NOT NULL, + IssuedQuantity DECIMAL(18,2) DEFAULT 0, + CONSTRAINT FK_ProdMaterial_ProdOrder FOREIGN KEY (ProductionOrderID) REFERENCES ProductionOrder(ProductionOrderID), + CONSTRAINT FK_ProdMaterial_Item FOREIGN KEY (ItemID) REFERENCES Items(ItemID) +); + +CREATE TABLE ProductionCompletion ( + CompletionID INT IDENTITY(1,1) PRIMARY KEY, + ProductionOrderID INT NOT NULL, + QuantityCompleted DECIMAL(18,2) NOT NULL, + QuantityScrapped DECIMAL(18,2) DEFAULT 0, + CompletionDate DATETIME2 DEFAULT GETDATE(), + WorkCenterID INT, + Notes NVARCHAR(MAX), + CompletedBy NVARCHAR(100), + CONSTRAINT FK_Completion_ProdOrder FOREIGN KEY (ProductionOrderID) REFERENCES ProductionOrder(ProductionOrderID), + CONSTRAINT FK_Completion_WorkCenter FOREIGN KEY (WorkCenterID) REFERENCES WorkCenter(WorkCenterID) +); + +-- ============================================= +-- Quality Control +-- ============================================= + +CREATE TABLE QualityInspection ( + InspectionID INT IDENTITY(1,1) PRIMARY KEY, + ItemID INT NOT NULL, + InspectionType NVARCHAR(50) NOT NULL, -- Incoming, In-Process, Final + ReferenceType NVARCHAR(50), -- PO, WO, etc. + ReferenceNumber NVARCHAR(50), + QuantityInspected DECIMAL(18,2) NOT NULL, + QuantityAccepted DECIMAL(18,2) NOT NULL, + QuantityRejected DECIMAL(18,2) NOT NULL, + InspectionDate DATETIME2 DEFAULT GETDATE(), + InspectedBy NVARCHAR(100), + Notes NVARCHAR(MAX), + CONSTRAINT FK_Quality_Item FOREIGN KEY (ItemID) REFERENCES Items(ItemID) +); + +-- ============================================= +-- Customer and Sales Management +-- ============================================= + +CREATE TABLE Customer ( + CustomerID INT IDENTITY(1,1) PRIMARY KEY, + CustomerCode NVARCHAR(20) NOT NULL UNIQUE, + CustomerName NVARCHAR(255) NOT NULL, + ContactName NVARCHAR(100), + Email NVARCHAR(100), + Phone NVARCHAR(20), + Address NVARCHAR(255), + City NVARCHAR(100), + State NVARCHAR(50), + ZipCode NVARCHAR(20), + Country NVARCHAR(50), + CreditLimit DECIMAL(18,2), + IsActive BIT NOT NULL DEFAULT 1, + CreatedDate DATETIME2 DEFAULT GETDATE() +); + +CREATE TABLE SalesOrder ( + SalesOrderID INT IDENTITY(1,1) PRIMARY KEY, + OrderNumber NVARCHAR(50) NOT NULL UNIQUE, + CustomerID INT NOT NULL, + WarehouseID INT NOT NULL, + OrderDate DATE NOT NULL DEFAULT CAST(GETDATE() AS DATE), + RequestedDeliveryDate DATE, + ShipDate DATE, + Status NVARCHAR(20) NOT NULL DEFAULT 'Draft', -- Draft, Confirmed, InProduction, Shipped, Delivered, Cancelled + Subtotal DECIMAL(18,2) DEFAULT 0, + TaxAmount DECIMAL(18,2) DEFAULT 0, + ShippingAmount DECIMAL(18,2) DEFAULT 0, + TotalAmount DECIMAL(18,2) DEFAULT 0, + Notes NVARCHAR(MAX), + CreatedBy NVARCHAR(100), + CreatedDate DATETIME2 DEFAULT GETDATE(), + ModifiedDate DATETIME2 DEFAULT GETDATE(), + CONSTRAINT FK_SO_Customer FOREIGN KEY (CustomerID) REFERENCES Customer(CustomerID), + CONSTRAINT FK_SO_Warehouse FOREIGN KEY (WarehouseID) REFERENCES Warehouse(WarehouseID) +); + +CREATE TABLE SalesOrderDetail ( + SODetailID INT IDENTITY(1,1) PRIMARY KEY, + SalesOrderID INT NOT NULL, + LineNumber INT NOT NULL, + ItemID INT NOT NULL, + Quantity DECIMAL(18,2) NOT NULL, + UnitPrice DECIMAL(18,4) NOT NULL, + QuantityShipped DECIMAL(18,2) DEFAULT 0, + LineTotal AS (Quantity * UnitPrice) PERSISTED, + CONSTRAINT FK_SODetail_SO FOREIGN KEY (SalesOrderID) REFERENCES SalesOrder(SalesOrderID), + CONSTRAINT FK_SODetail_Item FOREIGN KEY (ItemID) REFERENCES Items(ItemID) +); + +-- ============================================= +-- Indexes for Performance +-- ============================================= + +CREATE NONCLUSTERED INDEX IX_Items_Type ON Items(ItemTypeID) INCLUDE (ItemCode, ItemName); +CREATE NONCLUSTERED INDEX IX_Items_Active ON Items(IsActive) WHERE IsActive = 1; +CREATE NONCLUSTERED INDEX IX_PO_Status ON PurchaseOrder(Status, OrderDate); +CREATE NONCLUSTERED INDEX IX_SO_Status ON SalesOrder(Status, OrderDate); +CREATE NONCLUSTERED INDEX IX_ProdOrder_Status ON ProductionOrder(Status, PlannedCompletionDate); + +GO + +PRINT 'Futon Manufacturing Database Schema created successfully!'; +GO diff --git a/samples/databases/futon-manufacturing/02-sample-data.sql b/samples/databases/futon-manufacturing/02-sample-data.sql new file mode 100644 index 0000000000..63c743b183 --- /dev/null +++ b/samples/databases/futon-manufacturing/02-sample-data.sql @@ -0,0 +1,426 @@ +-- ============================================= +-- Futon Manufacturing Sample Data +-- ============================================= + +USE FutonManufacturing; +GO + +-- ============================================= +-- Reference Data +-- ============================================= + +-- Unit of Measure +INSERT INTO UnitOfMeasure (UnitCode, UnitName, Description) VALUES +('EA', 'Each', 'Individual unit'), +('YD', 'Yard', 'Linear yard'), +('LB', 'Pound', 'Weight in pounds'), +('FT', 'Foot', 'Linear foot'), +('PC', 'Piece', 'Piece'), +('SET', 'Set', 'Set of items'), +('BOX', 'Box', 'Box'), +('ROLL', 'Roll', 'Roll of material'); + +-- Item Types +INSERT INTO ItemType (TypeCode, TypeName, Description) VALUES +('RAW', 'Raw Material', 'Raw materials purchased from suppliers'), +('COMP', 'Component', 'Manufactured components used in assemblies'), +('FG', 'Finished Goods', 'Finished products ready for sale'); + +-- Transaction Types +INSERT INTO TransactionType (TypeCode, TypeName, Description) VALUES +('PO-RCV', 'Purchase Order Receipt', 'Receipt of purchased materials'), +('PO-RET', 'Purchase Order Return', 'Return to supplier'), +('WO-ISS', 'Work Order Issue', 'Material issued to production'), +('WO-CMP', 'Work Order Completion', 'Production completion'), +('SO-SHP', 'Sales Order Shipment', 'Shipment to customer'), +('SO-RET', 'Sales Order Return', 'Customer return'), +('ADJ-POS', 'Positive Adjustment', 'Inventory increase adjustment'), +('ADJ-NEG', 'Negative Adjustment', 'Inventory decrease adjustment'), +('CYC-CNT', 'Cycle Count', 'Cycle count adjustment'); + +-- ============================================= +-- Items Master Data +-- ============================================= + +DECLARE @RawMaterialType INT = (SELECT ItemTypeID FROM ItemType WHERE TypeCode = 'RAW'); +DECLARE @ComponentType INT = (SELECT ItemTypeID FROM ItemType WHERE TypeCode = 'COMP'); +DECLARE @FinishedGoodType INT = (SELECT ItemTypeID FROM ItemType WHERE TypeCode = 'FG'); +DECLARE @EachUnit INT = (SELECT UnitID FROM UnitOfMeasure WHERE UnitCode = 'EA'); +DECLARE @YardUnit INT = (SELECT UnitID FROM UnitOfMeasure WHERE UnitCode = 'YD'); +DECLARE @PoundUnit INT = (SELECT UnitID FROM UnitOfMeasure WHERE UnitCode = 'LB'); +DECLARE @FootUnit INT = (SELECT UnitID FROM UnitOfMeasure WHERE UnitCode = 'FT'); + +-- Raw Materials: Fill Materials +INSERT INTO Items (ItemCode, ItemName, ItemTypeID, UnitID, Description, StandardCost, ListPrice, ReorderPoint, SafetyStock, LeadTimeDays) VALUES +('RM-FILL-001', 'Premium Polyester Fiber Fill', @RawMaterialType, @PoundUnit, 'High-quality polyester fiber for pillow filling', 3.50, 0, 500, 250, 14), +('RM-FILL-002', 'Memory Foam Chips', @RawMaterialType, @PoundUnit, 'Shredded memory foam for premium comfort', 8.75, 0, 300, 150, 21), +('RM-FILL-003', 'Cotton Fill', @RawMaterialType, @PoundUnit, 'Natural cotton fiber fill', 6.25, 0, 400, 200, 14), +('RM-FILL-004', 'Latex Foam Chips', @RawMaterialType, @PoundUnit, 'Natural latex foam pieces', 12.50, 0, 200, 100, 28), +('RM-FILL-005', 'Down Alternative Fill', @RawMaterialType, @PoundUnit, 'Hypoallergenic down alternative', 5.00, 0, 350, 175, 14); + +-- Raw Materials: Fabric +INSERT INTO Items (ItemCode, ItemName, ItemTypeID, UnitID, Description, StandardCost, ListPrice, ReorderPoint, SafetyStock, LeadTimeDays) VALUES +('RM-FAB-001', 'Cotton Canvas - Natural', @RawMaterialType, @YardUnit, '100% cotton canvas fabric, natural color', 8.50, 0, 200, 100, 14), +('RM-FAB-002', 'Cotton Canvas - Navy Blue', @RawMaterialType, @YardUnit, '100% cotton canvas fabric, navy blue', 8.50, 0, 200, 100, 14), +('RM-FAB-003', 'Cotton Canvas - Burgundy', @RawMaterialType, @YardUnit, '100% cotton canvas fabric, burgundy', 8.50, 0, 200, 100, 14), +('RM-FAB-004', 'Microfiber Suede - Black', @RawMaterialType, @YardUnit, 'Soft microfiber suede fabric', 12.00, 0, 150, 75, 21), +('RM-FAB-005', 'Microfiber Suede - Chocolate', @RawMaterialType, @YardUnit, 'Soft microfiber suede fabric', 12.00, 0, 150, 75, 21), +('RM-FAB-006', 'Linen Blend - Beige', @RawMaterialType, @YardUnit, 'Linen cotton blend fabric', 15.00, 0, 100, 50, 21), +('RM-FAB-007', 'Twill - Khaki', @RawMaterialType, @YardUnit, 'Durable cotton twill fabric', 9.50, 0, 180, 90, 14), +('RM-FAB-008', 'Velvet - Emerald Green', @RawMaterialType, @YardUnit, 'Luxurious velvet fabric', 18.50, 0, 80, 40, 28); + +-- Raw Materials: Frame Components +INSERT INTO Items (ItemCode, ItemName, ItemTypeID, UnitID, Description, StandardCost, ListPrice, ReorderPoint, SafetyStock, LeadTimeDays) VALUES +('RM-WOOD-001', 'Pine Frame Rail 6ft', @RawMaterialType, @EachUnit, 'Solid pine wood rail, 2x4x72in', 12.00, 0, 100, 50, 14), +('RM-WOOD-002', 'Pine Frame Rail 4ft', @RawMaterialType, @EachUnit, 'Solid pine wood rail, 2x4x48in', 8.50, 0, 100, 50, 14), +('RM-WOOD-003', 'Hardwood Slat 6ft', @RawMaterialType, @EachUnit, 'Hardwood support slat, 1x4x72in', 7.50, 0, 200, 100, 14), +('RM-WOOD-004', 'Hardwood Slat 4ft', @RawMaterialType, @EachUnit, 'Hardwood support slat, 1x4x48in', 5.00, 0, 200, 100, 14), +('RM-METAL-001', 'Steel Corner Bracket', @RawMaterialType, @EachUnit, 'Heavy-duty steel corner bracket', 2.75, 0, 400, 200, 7), +('RM-METAL-002', 'Steel Hinge Mechanism', @RawMaterialType, @EachUnit, 'Folding hinge for futon frame', 15.50, 0, 150, 75, 14), +('RM-HARD-001', 'Wood Screw 3in (100 pack)', @RawMaterialType, @EachUnit, 'Box of 100 3-inch wood screws', 8.00, 0, 50, 25, 7), +('RM-HARD-002', 'Bolt and Nut Kit (50 pack)', @RawMaterialType, @EachUnit, 'Box of 50 bolt and nut sets', 12.00, 0, 50, 25, 7), +('RM-FIN-001', 'Wood Stain - Dark Walnut (Quart)', @RawMaterialType, @EachUnit, 'Dark walnut wood stain', 18.00, 0, 30, 15, 7), +('RM-FIN-002', 'Wood Stain - Natural Oak (Quart)', @RawMaterialType, @EachUnit, 'Natural oak wood stain', 18.00, 0, 30, 15, 7), +('RM-FIN-003', 'Clear Polyurethane (Quart)', @RawMaterialType, @EachUnit, 'Clear protective finish', 22.00, 0, 30, 15, 7); + +-- Components: Pillows +INSERT INTO Items (ItemCode, ItemName, ItemTypeID, UnitID, Description, StandardCost, ListPrice, ReorderPoint, SafetyStock, LeadTimeDays) VALUES +('COMP-PIL-001', 'Standard Polyester Pillow', @ComponentType, @EachUnit, 'Standard pillow with polyester fill', 0, 0, 50, 25, 3), +('COMP-PIL-002', 'Premium Memory Foam Pillow', @ComponentType, @EachUnit, 'Premium pillow with memory foam', 0, 0, 40, 20, 3), +('COMP-PIL-003', 'Cotton Fill Pillow', @ComponentType, @EachUnit, 'Natural cotton filled pillow', 0, 0, 40, 20, 3), +('COMP-PIL-004', 'Latex Foam Pillow', @ComponentType, @EachUnit, 'Natural latex foam pillow', 0, 0, 30, 15, 3), +('COMP-PIL-005', 'Down Alternative Pillow', @ComponentType, @EachUnit, 'Hypoallergenic down alternative pillow', 0, 0, 45, 22, 3); + +-- Components: Mattresses +INSERT INTO Items (ItemCode, ItemName, ItemTypeID, UnitID, Description, StandardCost, ListPrice, ReorderPoint, SafetyStock, LeadTimeDays) VALUES +('COMP-MAT-001', 'Twin Polyester Mattress', @ComponentType, @EachUnit, 'Twin futon mattress with polyester fill', 0, 0, 20, 10, 5), +('COMP-MAT-002', 'Full Polyester Mattress', @ComponentType, @EachUnit, 'Full futon mattress with polyester fill', 0, 0, 15, 7, 5), +('COMP-MAT-003', 'Queen Memory Foam Mattress', @ComponentType, @EachUnit, 'Queen futon mattress with memory foam', 0, 0, 12, 6, 5), +('COMP-MAT-004', 'Full Cotton Mattress', @ComponentType, @EachUnit, 'Full futon mattress with cotton fill', 0, 0, 15, 7, 5), +('COMP-MAT-005', 'Queen Cotton Mattress', @ComponentType, @EachUnit, 'Queen futon mattress with cotton fill', 0, 0, 12, 6, 5); + +-- Components: Frames +INSERT INTO Items (ItemCode, ItemName, ItemTypeID, UnitID, Description, StandardCost, ListPrice, ReorderPoint, SafetyStock, LeadTimeDays) VALUES +('COMP-FRM-001', 'Twin Pine Frame - Natural Oak', @ComponentType, @EachUnit, 'Twin size pine frame, natural oak finish', 0, 0, 15, 7, 7), +('COMP-FRM-002', 'Full Pine Frame - Natural Oak', @ComponentType, @EachUnit, 'Full size pine frame, natural oak finish', 0, 0, 12, 6, 7), +('COMP-FRM-003', 'Queen Pine Frame - Natural Oak', @ComponentType, @EachUnit, 'Queen size pine frame, natural oak finish', 0, 0, 10, 5, 7), +('COMP-FRM-004', 'Full Pine Frame - Dark Walnut', @ComponentType, @EachUnit, 'Full size pine frame, dark walnut finish', 0, 0, 12, 6, 7), +('COMP-FRM-005', 'Queen Pine Frame - Dark Walnut', @ComponentType, @EachUnit, 'Queen size pine frame, dark walnut finish', 0, 0, 10, 5, 7); + +-- Finished Goods: Complete Futons +INSERT INTO Items (ItemCode, ItemName, ItemTypeID, UnitID, Description, StandardCost, ListPrice, ReorderPoint, SafetyStock, LeadTimeDays) VALUES +('FG-FUT-001', 'Twin Economy Futon - Natural Canvas', @FinishedGoodType, @EachUnit, 'Twin futon with polyester mattress, natural canvas, oak frame', 0, 299.99, 10, 5, 10), +('FG-FUT-002', 'Full Economy Futon - Navy Canvas', @FinishedGoodType, @EachUnit, 'Full futon with polyester mattress, navy canvas, oak frame', 0, 399.99, 8, 4, 10), +('FG-FUT-003', 'Full Deluxe Futon - Microfiber Black', @FinishedGoodType, @EachUnit, 'Full futon with memory foam mattress, microfiber suede, walnut frame', 0, 599.99, 6, 3, 10), +('FG-FUT-004', 'Queen Premium Futon - Velvet Emerald', @FinishedGoodType, @EachUnit, 'Queen futon with cotton mattress, velvet fabric, walnut frame', 0, 799.99, 5, 2, 10), +('FG-FUT-005', 'Full Comfort Futon - Chocolate Suede', @FinishedGoodType, @EachUnit, 'Full futon with cotton mattress, chocolate suede, oak frame', 0, 499.99, 7, 3, 10), +('FG-FUT-006', 'Queen Luxury Futon - Linen Beige', @FinishedGoodType, @EachUnit, 'Queen futon with memory foam mattress, linen blend, walnut frame', 0, 899.99, 4, 2, 10); + +GO + +-- ============================================= +-- Bill of Materials - Multi-Level +-- ============================================= + +-- Level 1: Pillows (Components made from raw materials) +-- Standard Polyester Pillow +INSERT INTO BillOfMaterials (ParentItemID, ComponentItemID, Quantity, UnitID, BOMLevel, ScrapRate) VALUES +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-PIL-001'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FILL-001'), 2.5, @PoundUnit, 1, 2.0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-PIL-001'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FAB-001'), 1.2, @YardUnit, 1, 5.0); + +-- Premium Memory Foam Pillow +INSERT INTO BillOfMaterials (ParentItemID, ComponentItemID, Quantity, UnitID, BOMLevel, ScrapRate) VALUES +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-PIL-002'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FILL-002'), 3.0, @PoundUnit, 1, 2.0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-PIL-002'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FAB-004'), 1.2, @YardUnit, 1, 5.0); + +-- Cotton Fill Pillow +INSERT INTO BillOfMaterials (ParentItemID, ComponentItemID, Quantity, UnitID, BOMLevel, ScrapRate) VALUES +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-PIL-003'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FILL-003'), 2.8, @PoundUnit, 1, 2.0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-PIL-003'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FAB-002'), 1.2, @YardUnit, 1, 5.0); + +-- Latex Foam Pillow +INSERT INTO BillOfMaterials (ParentItemID, ComponentItemID, Quantity, UnitID, BOMLevel, ScrapRate) VALUES +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-PIL-004'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FILL-004'), 3.5, @PoundUnit, 1, 2.0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-PIL-004'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FAB-006'), 1.2, @YardUnit, 1, 5.0); + +-- Down Alternative Pillow +INSERT INTO BillOfMaterials (ParentItemID, ComponentItemID, Quantity, UnitID, BOMLevel, ScrapRate) VALUES +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-PIL-005'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FILL-005'), 2.7, @PoundUnit, 1, 2.0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-PIL-005'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FAB-005'), 1.2, @YardUnit, 1, 5.0); + +-- Level 1: Mattresses (Components made from raw materials) +-- Twin Polyester Mattress +INSERT INTO BillOfMaterials (ParentItemID, ComponentItemID, Quantity, UnitID, BOMLevel, ScrapRate) VALUES +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-MAT-001'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FILL-001'), 15.0, @PoundUnit, 1, 3.0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-MAT-001'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FAB-001'), 6.5, @YardUnit, 1, 5.0); + +-- Full Polyester Mattress +INSERT INTO BillOfMaterials (ParentItemID, ComponentItemID, Quantity, UnitID, BOMLevel, ScrapRate) VALUES +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-MAT-002'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FILL-001'), 20.0, @PoundUnit, 1, 3.0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-MAT-002'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FAB-001'), 8.5, @YardUnit, 1, 5.0); + +-- Queen Memory Foam Mattress +INSERT INTO BillOfMaterials (ParentItemID, ComponentItemID, Quantity, UnitID, BOMLevel, ScrapRate) VALUES +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-MAT-003'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FILL-002'), 28.0, @PoundUnit, 1, 3.0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-MAT-003'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FAB-004'), 10.0, @YardUnit, 1, 5.0); + +-- Full Cotton Mattress +INSERT INTO BillOfMaterials (ParentItemID, ComponentItemID, Quantity, UnitID, BOMLevel, ScrapRate) VALUES +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-MAT-004'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FILL-003'), 22.0, @PoundUnit, 1, 3.0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-MAT-004'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FAB-003'), 8.5, @YardUnit, 1, 5.0); + +-- Queen Cotton Mattress +INSERT INTO BillOfMaterials (ParentItemID, ComponentItemID, Quantity, UnitID, BOMLevel, ScrapRate) VALUES +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-MAT-005'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FILL-003'), 26.0, @PoundUnit, 1, 3.0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-MAT-005'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FAB-006'), 10.0, @YardUnit, 1, 5.0); + +-- Level 1: Frames (Components made from raw materials) +-- Twin Pine Frame - Natural Oak +INSERT INTO BillOfMaterials (ParentItemID, ComponentItemID, Quantity, UnitID, BOMLevel, ScrapRate) VALUES +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-001'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-WOOD-002'), 4, @EachUnit, 1, 5.0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-001'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-WOOD-004'), 8, @EachUnit, 1, 5.0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-001'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-METAL-001'), 8, @EachUnit, 1, 1.0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-001'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-METAL-002'), 2, @EachUnit, 1, 1.0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-001'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-HARD-001'), 1, @EachUnit, 1, 0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-001'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FIN-002'), 0.5, @EachUnit, 1, 10.0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-001'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FIN-003'), 0.5, @EachUnit, 1, 10.0); + +-- Full Pine Frame - Natural Oak +INSERT INTO BillOfMaterials (ParentItemID, ComponentItemID, Quantity, UnitID, BOMLevel, ScrapRate) VALUES +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-002'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-WOOD-001'), 2, @EachUnit, 1, 5.0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-002'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-WOOD-002'), 2, @EachUnit, 1, 5.0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-002'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-WOOD-003'), 10, @EachUnit, 1, 5.0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-002'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-METAL-001'), 8, @EachUnit, 1, 1.0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-002'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-METAL-002'), 2, @EachUnit, 1, 1.0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-002'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-HARD-001'), 1, @EachUnit, 1, 0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-002'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FIN-002'), 0.75, @EachUnit, 1, 10.0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-002'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FIN-003'), 0.75, @EachUnit, 1, 10.0); + +-- Queen Pine Frame - Natural Oak +INSERT INTO BillOfMaterials (ParentItemID, ComponentItemID, Quantity, UnitID, BOMLevel, ScrapRate) VALUES +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-003'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-WOOD-001'), 4, @EachUnit, 1, 5.0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-003'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-WOOD-003'), 12, @EachUnit, 1, 5.0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-003'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-METAL-001'), 8, @EachUnit, 1, 1.0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-003'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-METAL-002'), 2, @EachUnit, 1, 1.0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-003'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-HARD-001'), 2, @EachUnit, 1, 0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-003'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FIN-002'), 1.0, @EachUnit, 1, 10.0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-003'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FIN-003'), 1.0, @EachUnit, 1, 10.0); + +-- Full Pine Frame - Dark Walnut +INSERT INTO BillOfMaterials (ParentItemID, ComponentItemID, Quantity, UnitID, BOMLevel, ScrapRate) VALUES +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-004'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-WOOD-001'), 2, @EachUnit, 1, 5.0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-004'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-WOOD-002'), 2, @EachUnit, 1, 5.0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-004'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-WOOD-003'), 10, @EachUnit, 1, 5.0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-004'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-METAL-001'), 8, @EachUnit, 1, 1.0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-004'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-METAL-002'), 2, @EachUnit, 1, 1.0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-004'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-HARD-001'), 1, @EachUnit, 1, 0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-004'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FIN-001'), 0.75, @EachUnit, 1, 10.0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-004'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FIN-003'), 0.75, @EachUnit, 1, 10.0); + +-- Queen Pine Frame - Dark Walnut +INSERT INTO BillOfMaterials (ParentItemID, ComponentItemID, Quantity, UnitID, BOMLevel, ScrapRate) VALUES +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-005'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-WOOD-001'), 4, @EachUnit, 1, 5.0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-005'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-WOOD-003'), 12, @EachUnit, 1, 5.0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-005'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-METAL-001'), 8, @EachUnit, 1, 1.0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-005'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-METAL-002'), 2, @EachUnit, 1, 1.0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-005'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-HARD-001'), 2, @EachUnit, 1, 0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-005'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FIN-001'), 1.0, @EachUnit, 1, 10.0), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-005'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FIN-003'), 1.0, @EachUnit, 1, 10.0); + +-- Level 0: Finished Goods (Made from components) +-- Twin Economy Futon - Natural Canvas +INSERT INTO BillOfMaterials (ParentItemID, ComponentItemID, Quantity, UnitID, BOMLevel, ScrapRate) VALUES +((SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-001'), (SELECT ItemID FROM Items WHERE ItemCode = 'COMP-MAT-001'), 1, @EachUnit, 0, 0.5), +((SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-001'), (SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-001'), 1, @EachUnit, 0, 0.5), +((SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-001'), (SELECT ItemID FROM Items WHERE ItemCode = 'COMP-PIL-001'), 2, @EachUnit, 0, 1.0); + +-- Full Economy Futon - Navy Canvas +INSERT INTO BillOfMaterials (ParentItemID, ComponentItemID, Quantity, UnitID, BOMLevel, ScrapRate) VALUES +((SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-002'), (SELECT ItemID FROM Items WHERE ItemCode = 'COMP-MAT-002'), 1, @EachUnit, 0, 0.5), +((SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-002'), (SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-002'), 1, @EachUnit, 0, 0.5), +((SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-002'), (SELECT ItemID FROM Items WHERE ItemCode = 'COMP-PIL-003'), 2, @EachUnit, 0, 1.0); + +-- Full Deluxe Futon - Microfiber Black +INSERT INTO BillOfMaterials (ParentItemID, ComponentItemID, Quantity, UnitID, BOMLevel, ScrapRate) VALUES +((SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-003'), (SELECT ItemID FROM Items WHERE ItemCode = 'COMP-MAT-003'), 1, @EachUnit, 0, 0.5), +((SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-003'), (SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-004'), 1, @EachUnit, 0, 0.5), +((SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-003'), (SELECT ItemID FROM Items WHERE ItemCode = 'COMP-PIL-002'), 2, @EachUnit, 0, 1.0); + +-- Queen Premium Futon - Velvet Emerald +INSERT INTO BillOfMaterials (ParentItemID, ComponentItemID, Quantity, UnitID, BOMLevel, ScrapRate) VALUES +((SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-004'), (SELECT ItemID FROM Items WHERE ItemCode = 'COMP-MAT-005'), 1, @EachUnit, 0, 0.5), +((SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-004'), (SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-005'), 1, @EachUnit, 0, 0.5), +((SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-004'), (SELECT ItemID FROM Items WHERE ItemCode = 'COMP-PIL-004'), 2, @EachUnit, 0, 1.0); + +-- Full Comfort Futon - Chocolate Suede +INSERT INTO BillOfMaterials (ParentItemID, ComponentItemID, Quantity, UnitID, BOMLevel, ScrapRate) VALUES +((SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-005'), (SELECT ItemID FROM Items WHERE ItemCode = 'COMP-MAT-004'), 1, @EachUnit, 0, 0.5), +((SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-005'), (SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-002'), 1, @EachUnit, 0, 0.5), +((SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-005'), (SELECT ItemID FROM Items WHERE ItemCode = 'COMP-PIL-005'), 2, @EachUnit, 0, 1.0); + +-- Queen Luxury Futon - Linen Beige +INSERT INTO BillOfMaterials (ParentItemID, ComponentItemID, Quantity, UnitID, BOMLevel, ScrapRate) VALUES +((SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-006'), (SELECT ItemID FROM Items WHERE ItemCode = 'COMP-MAT-003'), 1, @EachUnit, 0, 0.5), +((SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-006'), (SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-005'), 1, @EachUnit, 0, 0.5), +((SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-006'), (SELECT ItemID FROM Items WHERE ItemCode = 'COMP-PIL-002'), 2, @EachUnit, 0, 1.0); + +GO + +-- Update Standard Costs based on BOM +UPDATE Items +SET StandardCost = ( + SELECT ISNULL(SUM(c.StandardCost * b.Quantity * (1 + b.ScrapRate/100)), 0) + FROM BillOfMaterials b + INNER JOIN Items c ON b.ComponentItemID = c.ItemID + WHERE b.ParentItemID = Items.ItemID +) +WHERE ItemTypeID IN (SELECT ItemTypeID FROM ItemType WHERE TypeCode IN ('COMP', 'FG')); + +GO + +-- ============================================= +-- Warehouses +-- ============================================= + +INSERT INTO Warehouse (WarehouseCode, WarehouseName, Address, City, State, ZipCode) VALUES +('WH-MAIN', 'Main Manufacturing Facility', '1200 Industrial Parkway', 'Portland', 'OR', '97201'), +('WH-WEST', 'West Coast Distribution', '450 Commerce Drive', 'Los Angeles', 'CA', '90001'), +('WH-EAST', 'East Coast Distribution', '780 Logistics Boulevard', 'Charlotte', 'NC', '28201'); + +-- ============================================= +-- Work Centers +-- ============================================= + +INSERT INTO WorkCenter (WorkCenterCode, WorkCenterName, Description, Capacity) VALUES +('WC-SEW', 'Sewing Department', 'Pillow and mattress cover sewing', 50), +('WC-FILL', 'Filling Station', 'Fill pillows and mattresses', 60), +('WC-WOOD', 'Woodworking Shop', 'Frame construction and finishing', 30), +('WC-ASSY', 'Final Assembly', 'Futon final assembly and packaging', 40), +('WC-QC', 'Quality Control', 'Final inspection and testing', 50); + +-- ============================================= +-- Suppliers +-- ============================================= + +INSERT INTO Supplier (SupplierCode, SupplierName, ContactName, Email, Phone, Address, City, State, ZipCode, Country, PaymentTerms, Rating) VALUES +('SUP-001', 'Pacific Textile Mills', 'Sarah Johnson', 'sarah.j@pacifictextile.com', '503-555-0101', '500 Mill Street', 'Portland', 'OR', '97202', 'USA', 'Net 30', 4.5), +('SUP-002', 'Premium Fill Supply Co', 'Michael Chen', 'mchen@premiumfill.com', '206-555-0202', '1800 Manufacturing Way', 'Seattle', 'WA', '98101', 'USA', 'Net 30', 4.8), +('SUP-003', 'Northwest Lumber & Hardware', 'David Brown', 'dbrown@nwlumber.com', '503-555-0303', '2500 Timber Road', 'Eugene', 'OR', '97401', 'USA', 'Net 45', 4.3), +('SUP-004', 'Industrial Fasteners Inc', 'Lisa Martinez', 'lmartinez@indfasteners.com', '425-555-0404', '300 Industry Blvd', 'Tacoma', 'WA', '98402', 'USA', 'Net 30', 4.6), +('SUP-005', 'Luxury Fabric Imports', 'James Wilson', 'jwilson@luxuryfabric.com', '415-555-0505', '1500 Fashion Avenue', 'San Francisco', 'CA', '94102', 'USA', 'Net 60', 4.7); + +-- Supplier Items +INSERT INTO SupplierItem (SupplierID, ItemID, SupplierPartNumber, UnitPrice, MinimumOrderQuantity, LeadTimeDays, IsPreferred) VALUES +-- Pacific Textile Mills - Fabrics +((SELECT SupplierID FROM Supplier WHERE SupplierCode = 'SUP-001'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FAB-001'), 'PTM-CAN-NAT-001', 7.50, 100, 14, 1), +((SELECT SupplierID FROM Supplier WHERE SupplierCode = 'SUP-001'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FAB-002'), 'PTM-CAN-NVY-001', 7.50, 100, 14, 1), +((SELECT SupplierID FROM Supplier WHERE SupplierCode = 'SUP-001'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FAB-003'), 'PTM-CAN-BUR-001', 7.50, 100, 14, 1), +((SELECT SupplierID FROM Supplier WHERE SupplierCode = 'SUP-001'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FAB-007'), 'PTM-TWL-KHA-001', 8.75, 100, 14, 1), +-- Premium Fill Supply - Fill materials +((SELECT SupplierID FROM Supplier WHERE SupplierCode = 'SUP-002'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FILL-001'), 'PFS-POLY-001', 3.25, 500, 14, 1), +((SELECT SupplierID FROM Supplier WHERE SupplierCode = 'SUP-002'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FILL-002'), 'PFS-MEMF-001', 8.00, 300, 21, 1), +((SELECT SupplierID FROM Supplier WHERE SupplierCode = 'SUP-002'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FILL-003'), 'PFS-COTN-001', 5.75, 400, 14, 1), +((SELECT SupplierID FROM Supplier WHERE SupplierCode = 'SUP-002'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FILL-004'), 'PFS-LATX-001', 11.50, 200, 28, 1), +((SELECT SupplierID FROM Supplier WHERE SupplierCode = 'SUP-002'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FILL-005'), 'PFS-DOWN-001', 4.50, 350, 14, 1), +-- Northwest Lumber - Wood +((SELECT SupplierID FROM Supplier WHERE SupplierCode = 'SUP-003'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-WOOD-001'), 'NWL-PINE-6FT', 11.00, 50, 14, 1), +((SELECT SupplierID FROM Supplier WHERE SupplierCode = 'SUP-003'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-WOOD-002'), 'NWL-PINE-4FT', 7.75, 50, 14, 1), +((SELECT SupplierID FROM Supplier WHERE SupplierCode = 'SUP-003'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-WOOD-003'), 'NWL-SLAT-6FT', 6.90, 100, 14, 1), +((SELECT SupplierID FROM Supplier WHERE SupplierCode = 'SUP-003'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-WOOD-004'), 'NWL-SLAT-4FT', 4.60, 100, 14, 1), +((SELECT SupplierID FROM Supplier WHERE SupplierCode = 'SUP-003'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FIN-001'), 'NWL-STN-WAL', 16.50, 12, 7, 1), +((SELECT SupplierID FROM Supplier WHERE SupplierCode = 'SUP-003'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FIN-002'), 'NWL-STN-OAK', 16.50, 12, 7, 1), +((SELECT SupplierID FROM Supplier WHERE SupplierCode = 'SUP-003'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FIN-003'), 'NWL-FIN-CLR', 20.00, 12, 7, 1), +-- Industrial Fasteners - Hardware +((SELECT SupplierID FROM Supplier WHERE SupplierCode = 'SUP-004'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-METAL-001'), 'IFI-BRK-001', 2.50, 200, 7, 1), +((SELECT SupplierID FROM Supplier WHERE SupplierCode = 'SUP-004'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-METAL-002'), 'IFI-HNG-001', 14.25, 100, 14, 1), +((SELECT SupplierID FROM Supplier WHERE SupplierCode = 'SUP-004'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-HARD-001'), 'IFI-SCR-3IN', 7.25, 50, 7, 1), +((SELECT SupplierID FROM Supplier WHERE SupplierCode = 'SUP-004'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-HARD-002'), 'IFI-BLT-KIT', 11.00, 50, 7, 1), +-- Luxury Fabric Imports - Premium fabrics +((SELECT SupplierID FROM Supplier WHERE SupplierCode = 'SUP-005'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FAB-004'), 'LFI-MIC-BLK', 11.00, 80, 21, 1), +((SELECT SupplierID FROM Supplier WHERE SupplierCode = 'SUP-005'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FAB-005'), 'LFI-MIC-CHO', 11.00, 80, 21, 1), +((SELECT SupplierID FROM Supplier WHERE SupplierCode = 'SUP-005'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FAB-006'), 'LFI-LIN-BEI', 13.75, 60, 21, 1), +((SELECT SupplierID FROM Supplier WHERE SupplierCode = 'SUP-005'), (SELECT ItemID FROM Items WHERE ItemCode = 'RM-FAB-008'), 'LFI-VEL-EMR', 17.00, 50, 28, 1); + +GO + +-- ============================================= +-- Initial Inventory +-- ============================================= + +DECLARE @MainWH INT = (SELECT WarehouseID FROM Warehouse WHERE WarehouseCode = 'WH-MAIN'); + +-- Raw Materials Inventory +INSERT INTO Inventory (ItemID, WarehouseID, QuantityOnHand, LastCountDate) VALUES +-- Fill materials +((SELECT ItemID FROM Items WHERE ItemCode = 'RM-FILL-001'), @MainWH, 1500.00, '2024-11-01'), +((SELECT ItemID FROM Items WHERE ItemCode = 'RM-FILL-002'), @MainWH, 800.00, '2024-11-01'), +((SELECT ItemID FROM Items WHERE ItemCode = 'RM-FILL-003'), @MainWH, 1200.00, '2024-11-01'), +((SELECT ItemID FROM Items WHERE ItemCode = 'RM-FILL-004'), @MainWH, 450.00, '2024-11-01'), +((SELECT ItemID FROM Items WHERE ItemCode = 'RM-FILL-005'), @MainWH, 900.00, '2024-11-01'), +-- Fabrics +((SELECT ItemID FROM Items WHERE ItemCode = 'RM-FAB-001'), @MainWH, 500.00, '2024-11-01'), +((SELECT ItemID FROM Items WHERE ItemCode = 'RM-FAB-002'), @MainWH, 450.00, '2024-11-01'), +((SELECT ItemID FROM Items WHERE ItemCode = 'RM-FAB-003'), @MainWH, 380.00, '2024-11-01'), +((SELECT ItemID FROM Items WHERE ItemCode = 'RM-FAB-004'), @MainWH, 300.00, '2024-11-01'), +((SELECT ItemID FROM Items WHERE ItemCode = 'RM-FAB-005'), @MainWH, 320.00, '2024-11-01'), +((SELECT ItemID FROM Items WHERE ItemCode = 'RM-FAB-006'), @MainWH, 180.00, '2024-11-01'), +((SELECT ItemID FROM Items WHERE ItemCode = 'RM-FAB-007'), @MainWH, 400.00, '2024-11-01'), +((SELECT ItemID FROM Items WHERE ItemCode = 'RM-FAB-008'), @MainWH, 150.00, '2024-11-01'), +-- Wood +((SELECT ItemID FROM Items WHERE ItemCode = 'RM-WOOD-001'), @MainWH, 250, '2024-11-01'), +((SELECT ItemID FROM Items WHERE ItemCode = 'RM-WOOD-002'), @MainWH, 300, '2024-11-01'), +((SELECT ItemID FROM Items WHERE ItemCode = 'RM-WOOD-003'), @MainWH, 500, '2024-11-01'), +((SELECT ItemID FROM Items WHERE ItemCode = 'RM-WOOD-004'), @MainWH, 600, '2024-11-01'), +-- Metal & Hardware +((SELECT ItemID FROM Items WHERE ItemCode = 'RM-METAL-001'), @MainWH, 800, '2024-11-01'), +((SELECT ItemID FROM Items WHERE ItemCode = 'RM-METAL-002'), @MainWH, 200, '2024-11-01'), +((SELECT ItemID FROM Items WHERE ItemCode = 'RM-HARD-001'), @MainWH, 100, '2024-11-01'), +((SELECT ItemID FROM Items WHERE ItemCode = 'RM-HARD-002'), @MainWH, 80, '2024-11-01'), +-- Finishes +((SELECT ItemID FROM Items WHERE ItemCode = 'RM-FIN-001'), @MainWH, 45, '2024-11-01'), +((SELECT ItemID FROM Items WHERE ItemCode = 'RM-FIN-002'), @MainWH, 50, '2024-11-01'), +((SELECT ItemID FROM Items WHERE ItemCode = 'RM-FIN-003'), @MainWH, 55, '2024-11-01'), +-- Components +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-PIL-001'), @MainWH, 120, '2024-11-01'), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-PIL-002'), @MainWH, 85, '2024-11-01'), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-PIL-003'), @MainWH, 95, '2024-11-01'), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-PIL-004'), @MainWH, 60, '2024-11-01'), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-PIL-005'), @MainWH, 110, '2024-11-01'), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-MAT-001'), @MainWH, 45, '2024-11-01'), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-MAT-002'), @MainWH, 38, '2024-11-01'), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-MAT-003'), @MainWH, 25, '2024-11-01'), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-MAT-004'), @MainWH, 32, '2024-11-01'), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-MAT-005'), @MainWH, 28, '2024-11-01'), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-001'), @MainWH, 35, '2024-11-01'), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-002'), @MainWH, 30, '2024-11-01'), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-003'), @MainWH, 25, '2024-11-01'), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-004'), @MainWH, 28, '2024-11-01'), +((SELECT ItemID FROM Items WHERE ItemCode = 'COMP-FRM-005'), @MainWH, 22, '2024-11-01'), +-- Finished Goods +((SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-001'), @MainWH, 18, '2024-11-01'), +((SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-002'), @MainWH, 15, '2024-11-01'), +((SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-003'), @MainWH, 12, '2024-11-01'), +((SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-004'), @MainWH, 8, '2024-11-01'), +((SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-005'), @MainWH, 14, '2024-11-01'), +((SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-006'), @MainWH, 7, '2024-11-01'); + +GO + +-- ============================================= +-- Customers +-- ============================================= + +INSERT INTO Customer (CustomerCode, CustomerName, ContactName, Email, Phone, Address, City, State, ZipCode, Country, CreditLimit) VALUES +('CUST-001', 'Home Comfort Retailers', 'Jennifer Adams', 'jadams@homecomfort.com', '503-555-1001', '450 Retail Plaza', 'Portland', 'OR', '97210', 'USA', 50000), +('CUST-002', 'Furniture Warehouse Direct', 'Robert Taylor', 'rtaylor@furniturewd.com', '206-555-1002', '2200 Commerce Street', 'Seattle', 'WA', '98115', 'USA', 75000), +('CUST-003', 'Coastal Living Stores', 'Maria Garcia', 'mgarcia@coastalliving.com', '415-555-1003', '1800 Bay Avenue', 'San Francisco', 'CA', '94103', 'USA', 60000), +('CUST-004', 'University Dorm Supplies', 'Kevin Lee', 'klee@univdorm.com', '541-555-1004', '300 Campus Drive', 'Eugene', 'OR', '97403', 'USA', 40000), +('CUST-005', 'Modern Home Boutique', 'Amanda White', 'awhite@modernhome.com', '503-555-1005', '950 Design District', 'Portland', 'OR', '97209', 'USA', 35000), +('CUST-006', 'Budget Furniture Outlet', 'Chris Martinez', 'cmartinez@budgetfurniture.com', '360-555-1006', '500 Outlet Way', 'Vancouver', 'WA', '98660', 'USA', 45000), +('CUST-007', 'Luxury Living Inc', 'Patricia Johnson', 'pjohnson@luxuryliving.com', '425-555-1007', '1200 Elite Boulevard', 'Bellevue', 'WA', '98004', 'USA', 100000), +('CUST-008', 'College Town Furnishings', 'Daniel Kim', 'dkim@collegetown.com', '541-555-1008', '780 Student Lane', 'Corvallis', 'OR', '97330', 'USA', 30000); + +GO + +PRINT 'Sample data inserted successfully!'; +GO diff --git a/samples/databases/futon-manufacturing/03-manufacturing-reports.sql b/samples/databases/futon-manufacturing/03-manufacturing-reports.sql new file mode 100644 index 0000000000..5a6c6a465c --- /dev/null +++ b/samples/databases/futon-manufacturing/03-manufacturing-reports.sql @@ -0,0 +1,883 @@ +-- ============================================= +-- Top 20 Manufacturing Reports +-- Futon Manufacturing Database +-- ============================================= + +USE FutonManufacturing; +GO + +-- ============================================= +-- REPORT 1: Multi-Level BOM Explosion +-- Shows complete material requirements for any item +-- ============================================= + +CREATE OR ALTER VIEW vw_BOMExplosion AS +WITH BOMRecursive AS ( + -- Anchor: Top level + SELECT + b.ParentItemID, + p.ItemCode AS ParentItemCode, + p.ItemName AS ParentItemName, + b.ComponentItemID, + c.ItemCode AS ComponentItemCode, + c.ItemName AS ComponentItemName, + c.ItemTypeID, + t.TypeName AS ComponentType, + b.Quantity, + b.UnitID, + u.UnitCode, + b.ScrapRate, + b.BOMLevel, + CAST(b.Quantity * (1 + b.ScrapRate/100) AS DECIMAL(18,4)) AS EffectiveQuantity, + c.StandardCost, + CAST(b.Quantity * (1 + b.ScrapRate/100) * c.StandardCost AS DECIMAL(18,4)) AS ExtendedCost, + 1 AS Level, + CAST(p.ItemCode + ' > ' + c.ItemCode AS NVARCHAR(MAX)) AS BOMPath + FROM BillOfMaterials b + INNER JOIN Items p ON b.ParentItemID = p.ItemID + INNER JOIN Items c ON b.ComponentItemID = c.ItemID + INNER JOIN ItemType t ON c.ItemTypeID = t.ItemTypeID + INNER JOIN UnitOfMeasure u ON b.UnitID = u.UnitID + WHERE b.IsActive = 1 + + UNION ALL + + -- Recursive: Get sub-components + SELECT + br.ParentItemID, + br.ParentItemCode, + br.ParentItemName, + b.ComponentItemID, + c.ItemCode, + c.ItemName, + c.ItemTypeID, + t.TypeName, + br.EffectiveQuantity * b.Quantity AS Quantity, + b.UnitID, + u.UnitCode, + b.ScrapRate, + b.BOMLevel, + CAST(br.EffectiveQuantity * b.Quantity * (1 + b.ScrapRate/100) AS DECIMAL(18,4)) AS EffectiveQuantity, + c.StandardCost, + CAST(br.EffectiveQuantity * b.Quantity * (1 + b.ScrapRate/100) * c.StandardCost AS DECIMAL(18,4)) AS ExtendedCost, + br.Level + 1, + CAST(br.BOMPath + ' > ' + c.ItemCode AS NVARCHAR(MAX)) + FROM BOMRecursive br + INNER JOIN BillOfMaterials b ON br.ComponentItemID = b.ParentItemID + INNER JOIN Items c ON b.ComponentItemID = c.ItemID + INNER JOIN ItemType t ON c.ItemTypeID = t.ItemTypeID + INNER JOIN UnitOfMeasure u ON b.UnitID = u.UnitID + WHERE b.IsActive = 1 +) +SELECT + ParentItemID, + ParentItemCode, + ParentItemName, + ComponentItemID, + ComponentItemCode, + ComponentItemName, + ComponentType, + Level, + EffectiveQuantity, + UnitCode, + StandardCost, + ExtendedCost, + BOMPath +FROM BOMRecursive; +GO + +-- ============================================= +-- REPORT 2: Where-Used Report +-- Shows where each component is used +-- ============================================= + +CREATE OR ALTER VIEW vw_WhereUsed AS +WITH WhereUsedRecursive AS ( + -- Direct usage + SELECT + b.ComponentItemID, + c.ItemCode AS ComponentItemCode, + c.ItemName AS ComponentItemName, + b.ParentItemID, + p.ItemCode AS ParentItemCode, + p.ItemName AS ParentItemName, + t.TypeName AS ParentType, + b.Quantity, + u.UnitCode, + 1 AS Level, + CAST(c.ItemCode + ' used in ' + p.ItemCode AS NVARCHAR(MAX)) AS UsagePath + FROM BillOfMaterials b + INNER JOIN Items c ON b.ComponentItemID = c.ItemID + INNER JOIN Items p ON b.ParentItemID = p.ItemID + INNER JOIN ItemType t ON p.ItemTypeID = t.ItemTypeID + INNER JOIN UnitOfMeasure u ON b.UnitID = u.UnitID + WHERE b.IsActive = 1 + + UNION ALL + + -- Recursive usage + SELECT + wu.ComponentItemID, + wu.ComponentItemCode, + wu.ComponentItemName, + b.ParentItemID, + p.ItemCode, + p.ItemName, + t.TypeName, + wu.Quantity * b.Quantity AS Quantity, + u.UnitCode, + wu.Level + 1, + CAST(wu.UsagePath + ' > ' + p.ItemCode AS NVARCHAR(MAX)) + FROM WhereUsedRecursive wu + INNER JOIN BillOfMaterials b ON wu.ParentItemID = b.ComponentItemID + INNER JOIN Items p ON b.ParentItemID = p.ItemID + INNER JOIN ItemType t ON p.ItemTypeID = t.ItemTypeID + INNER JOIN UnitOfMeasure u ON b.UnitID = u.UnitID + WHERE b.IsActive = 1 +) +SELECT + ComponentItemID, + ComponentItemCode, + ComponentItemName, + ParentItemID, + ParentItemCode, + ParentItemName, + ParentType, + Level, + Quantity, + UnitCode, + UsagePath +FROM WhereUsedRecursive; +GO + +-- ============================================= +-- REPORT 3: Inventory Valuation Report +-- ============================================= + +CREATE OR ALTER VIEW vw_InventoryValuation AS +SELECT + w.WarehouseCode, + w.WarehouseName, + t.TypeName AS ItemType, + i.ItemCode, + i.ItemName, + inv.QuantityOnHand, + inv.QuantityAllocated, + inv.QuantityAvailable, + u.UnitCode, + i.StandardCost, + inv.QuantityOnHand * i.StandardCost AS InventoryValue, + inv.QuantityAvailable * i.StandardCost AS AvailableValue, + inv.LastCountDate, + DATEDIFF(DAY, inv.LastCountDate, GETDATE()) AS DaysSinceCount +FROM Inventory inv +INNER JOIN Items i ON inv.ItemID = i.ItemID +INNER JOIN ItemType t ON i.ItemTypeID = t.ItemTypeID +INNER JOIN UnitOfMeasure u ON i.UnitID = u.UnitID +INNER JOIN Warehouse w ON inv.WarehouseID = w.WarehouseID +WHERE i.IsActive = 1; +GO + +-- ============================================= +-- REPORT 4: Items Below Reorder Point +-- ============================================= + +CREATE OR ALTER VIEW vw_ItemsBelowReorderPoint AS +SELECT + w.WarehouseCode, + w.WarehouseName, + t.TypeName AS ItemType, + i.ItemCode, + i.ItemName, + inv.QuantityAvailable, + i.ReorderPoint, + i.SafetyStock, + i.ReorderPoint - inv.QuantityAvailable AS ShortageQuantity, + u.UnitCode, + i.LeadTimeDays, + s.SupplierName AS PreferredSupplier, + si.UnitPrice AS PreferredPrice, + DATEADD(DAY, i.LeadTimeDays, GETDATE()) AS ExpectedArrival +FROM Inventory inv +INNER JOIN Items i ON inv.ItemID = i.ItemID +INNER JOIN ItemType t ON i.ItemTypeID = t.ItemTypeID +INNER JOIN UnitOfMeasure u ON i.UnitID = u.UnitID +INNER JOIN Warehouse w ON inv.WarehouseID = w.WarehouseID +LEFT JOIN SupplierItem si ON i.ItemID = si.ItemID AND si.IsPreferred = 1 +LEFT JOIN Supplier s ON si.SupplierID = s.SupplierID +WHERE i.IsActive = 1 + AND inv.QuantityAvailable < i.ReorderPoint; +GO + +-- ============================================= +-- REPORT 5: Production Order Status Report +-- ============================================= + +CREATE OR ALTER VIEW vw_ProductionOrderStatus AS +SELECT + po.WorkOrderNumber, + po.Status, + i.ItemCode, + i.ItemName, + t.TypeName AS ItemType, + po.OrderQuantity, + po.QuantityCompleted, + po.QuantityScrapped, + po.OrderQuantity - po.QuantityCompleted - po.QuantityScrapped AS QuantityRemaining, + CAST((po.QuantityCompleted * 100.0 / NULLIF(po.OrderQuantity, 0)) AS DECIMAL(5,2)) AS PercentComplete, + wc.WorkCenterName, + w.WarehouseName, + po.StartDate, + po.PlannedCompletionDate, + po.ActualCompletionDate, + CASE + WHEN po.ActualCompletionDate IS NOT NULL THEN + DATEDIFF(DAY, po.PlannedCompletionDate, po.ActualCompletionDate) + ELSE + DATEDIFF(DAY, po.PlannedCompletionDate, GETDATE()) + END AS DaysVariance, + CASE + WHEN po.Status = 'Completed' THEN 'On Time' + WHEN GETDATE() > po.PlannedCompletionDate THEN 'Late' + WHEN DATEDIFF(DAY, GETDATE(), po.PlannedCompletionDate) <= 2 THEN 'At Risk' + ELSE 'On Track' + END AS ScheduleStatus, + po.Priority, + po.CreatedBy, + po.CreatedDate +FROM ProductionOrder po +INNER JOIN Items i ON po.ItemID = i.ItemID +INNER JOIN ItemType t ON i.ItemTypeID = t.ItemTypeID +INNER JOIN Warehouse w ON po.WarehouseID = w.WarehouseID +LEFT JOIN WorkCenter wc ON po.WorkCenterID = wc.WorkCenterID; +GO + +-- ============================================= +-- REPORT 6: Material Requirements Planning (MRP) +-- ============================================= + +CREATE OR ALTER VIEW vw_MaterialRequirements AS +WITH RequiredMaterials AS ( + SELECT + po.WorkOrderNumber, + po.Status, + po.PlannedCompletionDate, + i.ItemID, + i.ItemCode, + i.ItemName, + t.TypeName AS ItemType, + SUM(bom.EffectiveQuantity * (po.OrderQuantity - po.QuantityCompleted)) AS RequiredQuantity, + u.UnitCode + FROM ProductionOrder po + INNER JOIN vw_BOMExplosion bom ON po.ItemID = bom.ParentItemID + INNER JOIN Items i ON bom.ComponentItemID = i.ItemID + INNER JOIN ItemType t ON i.ItemTypeID = t.ItemTypeID + INNER JOIN UnitOfMeasure u ON i.UnitID = u.UnitID + WHERE po.Status IN ('Planned', 'Released', 'InProgress') + GROUP BY + po.WorkOrderNumber, po.Status, po.PlannedCompletionDate, + i.ItemID, i.ItemCode, i.ItemName, t.TypeName, u.UnitCode +) +SELECT + rm.WorkOrderNumber, + rm.Status, + rm.PlannedCompletionDate, + rm.ItemCode, + rm.ItemName, + rm.ItemType, + rm.RequiredQuantity, + ISNULL(inv.QuantityAvailable, 0) AS AvailableQuantity, + rm.RequiredQuantity - ISNULL(inv.QuantityAvailable, 0) AS ShortageQuantity, + CASE + WHEN ISNULL(inv.QuantityAvailable, 0) >= rm.RequiredQuantity THEN 'Sufficient' + WHEN ISNULL(inv.QuantityAvailable, 0) > 0 THEN 'Partial' + ELSE 'Out of Stock' + END AS AvailabilityStatus, + rm.UnitCode +FROM RequiredMaterials rm +LEFT JOIN ( + SELECT ItemID, SUM(QuantityAvailable) AS QuantityAvailable + FROM Inventory + GROUP BY ItemID +) inv ON rm.ItemID = inv.ItemID; +GO + +-- ============================================= +-- REPORT 7: Work Center Capacity Analysis +-- ============================================= + +CREATE OR ALTER VIEW vw_WorkCenterCapacity AS +SELECT + wc.WorkCenterCode, + wc.WorkCenterName, + wc.Capacity AS DailyCapacity, + COUNT(DISTINCT po.ProductionOrderID) AS ActiveOrders, + SUM(CASE WHEN po.Status = 'InProgress' THEN 1 ELSE 0 END) AS InProgressOrders, + SUM(po.OrderQuantity - po.QuantityCompleted) AS TotalQuantityPending, + CAST(SUM(po.OrderQuantity - po.QuantityCompleted) / NULLIF(wc.Capacity, 0) AS DECIMAL(10,2)) AS DaysOfWork, + CAST((COUNT(DISTINCT po.ProductionOrderID) * 100.0 / + NULLIF((SELECT COUNT(*) FROM ProductionOrder WHERE Status IN ('Planned', 'Released', 'InProgress')), 0)) + AS DECIMAL(5,2)) AS PercentOfTotalOrders, + MIN(po.PlannedCompletionDate) AS EarliestDueDate, + MAX(po.PlannedCompletionDate) AS LatestDueDate +FROM WorkCenter wc +LEFT JOIN ProductionOrder po ON wc.WorkCenterID = po.WorkCenterID + AND po.Status IN ('Planned', 'Released', 'InProgress') +WHERE wc.IsActive = 1 +GROUP BY wc.WorkCenterCode, wc.WorkCenterName, wc.Capacity; +GO + +-- ============================================= +-- REPORT 8: Production Completion Summary +-- ============================================= + +CREATE OR ALTER VIEW vw_ProductionCompletionSummary AS +SELECT + CAST(pc.CompletionDate AS DATE) AS CompletionDate, + DATEPART(YEAR, pc.CompletionDate) AS Year, + DATEPART(MONTH, pc.CompletionDate) AS Month, + DATEPART(WEEK, pc.CompletionDate) AS Week, + wc.WorkCenterName, + i.ItemCode, + i.ItemName, + t.TypeName AS ItemType, + COUNT(DISTINCT pc.CompletionID) AS NumberOfCompletions, + SUM(pc.QuantityCompleted) AS TotalCompleted, + SUM(pc.QuantityScrapped) AS TotalScrapped, + CAST((SUM(pc.QuantityScrapped) * 100.0 / NULLIF(SUM(pc.QuantityCompleted + pc.QuantityScrapped), 0)) + AS DECIMAL(5,2)) AS ScrapRate, + SUM(pc.QuantityCompleted * i.StandardCost) AS ProductionValue +FROM ProductionCompletion pc +INNER JOIN ProductionOrder po ON pc.ProductionOrderID = po.ProductionOrderID +INNER JOIN Items i ON po.ItemID = i.ItemID +INNER JOIN ItemType t ON i.ItemTypeID = t.ItemTypeID +LEFT JOIN WorkCenter wc ON pc.WorkCenterID = wc.WorkCenterID +GROUP BY + CAST(pc.CompletionDate AS DATE), + DATEPART(YEAR, pc.CompletionDate), + DATEPART(MONTH, pc.CompletionDate), + DATEPART(WEEK, pc.CompletionDate), + wc.WorkCenterName, + i.ItemCode, + i.ItemName, + t.TypeName; +GO + +-- ============================================= +-- REPORT 9: Quality Inspection Summary +-- ============================================= + +CREATE OR ALTER VIEW vw_QualityInspectionSummary AS +SELECT + CAST(qi.InspectionDate AS DATE) AS InspectionDate, + DATEPART(YEAR, qi.InspectionDate) AS Year, + DATEPART(MONTH, qi.InspectionDate) AS Month, + qi.InspectionType, + i.ItemCode, + i.ItemName, + t.TypeName AS ItemType, + COUNT(qi.InspectionID) AS NumberOfInspections, + SUM(qi.QuantityInspected) AS TotalInspected, + SUM(qi.QuantityAccepted) AS TotalAccepted, + SUM(qi.QuantityRejected) AS TotalRejected, + CAST((SUM(qi.QuantityAccepted) * 100.0 / NULLIF(SUM(qi.QuantityInspected), 0)) + AS DECIMAL(5,2)) AS AcceptanceRate, + CAST((SUM(qi.QuantityRejected) * 100.0 / NULLIF(SUM(qi.QuantityInspected), 0)) + AS DECIMAL(5,2)) AS RejectionRate +FROM QualityInspection qi +INNER JOIN Items i ON qi.ItemID = i.ItemID +INNER JOIN ItemType t ON i.ItemTypeID = t.ItemTypeID +GROUP BY + CAST(qi.InspectionDate AS DATE), + DATEPART(YEAR, qi.InspectionDate), + DATEPART(MONTH, qi.InspectionDate), + qi.InspectionType, + i.ItemCode, + i.ItemName, + t.TypeName; +GO + +-- ============================================= +-- REPORT 10: Supplier Performance Report +-- ============================================= + +CREATE OR ALTER VIEW vw_SupplierPerformance AS +WITH SupplierMetrics AS ( + SELECT + s.SupplierID, + s.SupplierCode, + s.SupplierName, + s.Rating, + COUNT(DISTINCT po.PurchaseOrderID) AS TotalOrders, + SUM(po.TotalAmount) AS TotalPurchaseValue, + AVG(DATEDIFF(DAY, po.OrderDate, po.ActualDeliveryDate)) AS AvgDeliveryDays, + SUM(CASE WHEN po.ActualDeliveryDate <= po.ExpectedDeliveryDate THEN 1 ELSE 0 END) AS OnTimeDeliveries, + COUNT(CASE WHEN po.ActualDeliveryDate IS NOT NULL THEN 1 END) AS CompletedDeliveries + FROM Supplier s + LEFT JOIN PurchaseOrder po ON s.SupplierID = po.SupplierID + WHERE s.IsActive = 1 + GROUP BY s.SupplierID, s.SupplierCode, s.SupplierName, s.Rating +) +SELECT + SupplierCode, + SupplierName, + Rating AS SupplierRating, + TotalOrders, + TotalPurchaseValue, + AvgDeliveryDays, + OnTimeDeliveries, + CompletedDeliveries, + CAST((OnTimeDeliveries * 100.0 / NULLIF(CompletedDeliveries, 0)) AS DECIMAL(5,2)) AS OnTimeDeliveryRate, + CASE + WHEN CAST((OnTimeDeliveries * 100.0 / NULLIF(CompletedDeliveries, 0)) AS DECIMAL(5,2)) >= 95 THEN 'Excellent' + WHEN CAST((OnTimeDeliveries * 100.0 / NULLIF(CompletedDeliveries, 0)) AS DECIMAL(5,2)) >= 85 THEN 'Good' + WHEN CAST((OnTimeDeliveries * 100.0 / NULLIF(CompletedDeliveries, 0)) AS DECIMAL(5,2)) >= 75 THEN 'Fair' + ELSE 'Poor' + END AS PerformanceGrade +FROM SupplierMetrics; +GO + +-- ============================================= +-- REPORT 11: Purchase Order Status +-- ============================================= + +CREATE OR ALTER VIEW vw_PurchaseOrderStatus AS +SELECT + po.PONumber, + po.Status, + s.SupplierName, + w.WarehouseName, + po.OrderDate, + po.ExpectedDeliveryDate, + po.ActualDeliveryDate, + DATEDIFF(DAY, po.OrderDate, ISNULL(po.ActualDeliveryDate, GETDATE())) AS DaysSinceOrder, + CASE + WHEN po.ActualDeliveryDate IS NOT NULL THEN + DATEDIFF(DAY, po.ExpectedDeliveryDate, po.ActualDeliveryDate) + ELSE + DATEDIFF(DAY, po.ExpectedDeliveryDate, GETDATE()) + END AS DaysVariance, + COUNT(DISTINCT pod.PODetailID) AS LineItems, + po.TotalAmount, + SUM(pod.LineTotal) AS LinesTotal, + SUM(pod.QuantityReceived * pod.UnitPrice) AS ReceivedValue, + CAST((SUM(pod.QuantityReceived) * 100.0 / NULLIF(SUM(pod.Quantity), 0)) + AS DECIMAL(5,2)) AS PercentReceived, + CASE + WHEN po.Status = 'Received' THEN 'Complete' + WHEN po.Status = 'Cancelled' THEN 'Cancelled' + WHEN GETDATE() > po.ExpectedDeliveryDate AND po.Status NOT IN ('Received', 'Cancelled') THEN 'Overdue' + WHEN DATEDIFF(DAY, GETDATE(), po.ExpectedDeliveryDate) <= 3 THEN 'Due Soon' + ELSE 'On Track' + END AS DeliveryStatus +FROM PurchaseOrder po +INNER JOIN Supplier s ON po.SupplierID = s.SupplierID +INNER JOIN Warehouse w ON po.WarehouseID = w.WarehouseID +LEFT JOIN PurchaseOrderDetail pod ON po.PurchaseOrderID = pod.PurchaseOrderID +GROUP BY + po.PONumber, po.Status, s.SupplierName, w.WarehouseName, + po.OrderDate, po.ExpectedDeliveryDate, po.ActualDeliveryDate, + po.TotalAmount, po.PurchaseOrderID; +GO + +-- ============================================= +-- REPORT 12: Sales Order Backlog +-- ============================================= + +CREATE OR ALTER VIEW vw_SalesOrderBacklog AS +SELECT + so.OrderNumber, + so.Status, + c.CustomerName, + c.CustomerCode, + w.WarehouseName, + so.OrderDate, + so.RequestedDeliveryDate, + so.ShipDate, + DATEDIFF(DAY, so.OrderDate, GETDATE()) AS DaysOpen, + DATEDIFF(DAY, GETDATE(), so.RequestedDeliveryDate) AS DaysUntilDue, + COUNT(DISTINCT sod.SODetailID) AS LineItems, + SUM(sod.Quantity) AS TotalQuantityOrdered, + SUM(sod.QuantityShipped) AS TotalQuantityShipped, + SUM(sod.Quantity - sod.QuantityShipped) AS QuantityBacklog, + so.TotalAmount, + SUM(sod.LineTotal) AS OrderValue, + SUM((sod.Quantity - sod.QuantityShipped) * sod.UnitPrice) AS BacklogValue, + CAST((SUM(sod.QuantityShipped) * 100.0 / NULLIF(SUM(sod.Quantity), 0)) + AS DECIMAL(5,2)) AS PercentComplete, + CASE + WHEN so.Status = 'Delivered' THEN 'Complete' + WHEN so.Status = 'Cancelled' THEN 'Cancelled' + WHEN GETDATE() > so.RequestedDeliveryDate AND so.Status NOT IN ('Delivered', 'Shipped') THEN 'Overdue' + WHEN DATEDIFF(DAY, GETDATE(), so.RequestedDeliveryDate) <= 5 THEN 'Due Soon' + ELSE 'On Track' + END AS FulfillmentStatus +FROM SalesOrder so +INNER JOIN Customer c ON so.CustomerID = c.CustomerID +INNER JOIN Warehouse w ON so.WarehouseID = w.WarehouseID +LEFT JOIN SalesOrderDetail sod ON so.SalesOrderID = sod.SalesOrderID +WHERE so.Status NOT IN ('Delivered', 'Cancelled') +GROUP BY + so.OrderNumber, so.Status, c.CustomerName, c.CustomerCode, w.WarehouseName, + so.OrderDate, so.RequestedDeliveryDate, so.ShipDate, so.TotalAmount; +GO + +-- ============================================= +-- REPORT 13: Cost Roll-Up by Item +-- ============================================= + +CREATE OR ALTER VIEW vw_CostRollUp AS +WITH ItemCosts AS ( + SELECT + ParentItemID, + ParentItemCode, + ParentItemName, + SUM(ExtendedCost) AS TotalMaterialCost, + COUNT(DISTINCT ComponentItemID) AS NumberOfComponents + FROM vw_BOMExplosion + GROUP BY ParentItemID, ParentItemCode, ParentItemName +) +SELECT + i.ItemCode, + i.ItemName, + t.TypeName AS ItemType, + i.StandardCost AS CurrentStandardCost, + ISNULL(ic.TotalMaterialCost, 0) AS CalculatedMaterialCost, + i.StandardCost - ISNULL(ic.TotalMaterialCost, 0) AS LaborAndOverhead, + ISNULL(ic.NumberOfComponents, 0) AS ComponentCount, + i.ListPrice, + i.ListPrice - i.StandardCost AS GrossProfit, + CAST(((i.ListPrice - i.StandardCost) * 100.0 / NULLIF(i.ListPrice, 0)) + AS DECIMAL(5,2)) AS GrossMarginPercent +FROM Items i +INNER JOIN ItemType t ON i.ItemTypeID = t.ItemTypeID +LEFT JOIN ItemCosts ic ON i.ItemID = ic.ParentItemID +WHERE i.IsActive = 1; +GO + +-- ============================================= +-- REPORT 14: Inventory Turnover Analysis +-- ============================================= + +CREATE OR ALTER VIEW vw_InventoryTurnover AS +WITH TransactionSummary AS ( + SELECT + it.ItemID, + SUM(CASE WHEN it.Quantity < 0 THEN ABS(it.Quantity) ELSE 0 END) AS QuantityIssued, + SUM(CASE WHEN it.Quantity > 0 THEN it.Quantity ELSE 0 END) AS QuantityReceived, + COUNT(*) AS TransactionCount, + MIN(it.TransactionDate) AS FirstTransaction, + MAX(it.TransactionDate) AS LastTransaction + FROM InventoryTransaction it + WHERE it.TransactionDate >= DATEADD(MONTH, -12, GETDATE()) + GROUP BY it.ItemID +) +SELECT + i.ItemCode, + i.ItemName, + t.TypeName AS ItemType, + inv.QuantityOnHand, + inv.QuantityAvailable, + ts.QuantityIssued AS Annual Usage, + ts.QuantityReceived AS AnnualReceipts, + ts.TransactionCount, + CAST(ts.QuantityIssued / NULLIF(inv.QuantityOnHand, 0) AS DECIMAL(10,2)) AS TurnoverRatio, + CAST((inv.QuantityOnHand * 365.0) / NULLIF(ts.QuantityIssued, 0) AS DECIMAL(10,1)) AS DaysOnHand, + inv.QuantityOnHand * i.StandardCost AS InventoryValue, + ts.FirstTransaction, + ts.LastTransaction, + DATEDIFF(DAY, ts.LastTransaction, GETDATE()) AS DaysSinceLastActivity, + CASE + WHEN CAST(ts.QuantityIssued / NULLIF(inv.QuantityOnHand, 0) AS DECIMAL(10,2)) >= 12 THEN 'Fast Moving' + WHEN CAST(ts.QuantityIssued / NULLIF(inv.QuantityOnHand, 0) AS DECIMAL(10,2)) >= 4 THEN 'Normal' + WHEN CAST(ts.QuantityIssued / NULLIF(inv.QuantityOnHand, 0) AS DECIMAL(10,2)) >= 1 THEN 'Slow Moving' + ELSE 'Non-Moving' + END AS MovementClass +FROM Items i +INNER JOIN ItemType t ON i.ItemTypeID = t.ItemTypeID +INNER JOIN Inventory inv ON i.ItemID = inv.ItemID +LEFT JOIN TransactionSummary ts ON i.ItemID = ts.ItemID +WHERE i.IsActive = 1 AND inv.QuantityOnHand > 0; +GO + +-- ============================================= +-- REPORT 15: Late Production Orders +-- ============================================= + +CREATE OR ALTER VIEW vw_LateProductionOrders AS +SELECT + po.WorkOrderNumber, + po.Status, + i.ItemCode, + i.ItemName, + t.TypeName AS ItemType, + po.OrderQuantity, + po.QuantityCompleted, + po.OrderQuantity - po.QuantityCompleted AS QuantityRemaining, + wc.WorkCenterName, + po.StartDate, + po.PlannedCompletionDate, + DATEDIFF(DAY, po.PlannedCompletionDate, GETDATE()) AS DaysLate, + po.Priority, + CASE + WHEN DATEDIFF(DAY, po.PlannedCompletionDate, GETDATE()) > 10 THEN 'Critical' + WHEN DATEDIFF(DAY, po.PlannedCompletionDate, GETDATE()) > 5 THEN 'High' + WHEN DATEDIFF(DAY, po.PlannedCompletionDate, GETDATE()) > 2 THEN 'Medium' + ELSE 'Low' + END AS LatenessSeverity, + (po.OrderQuantity - po.QuantityCompleted) * i.StandardCost AS ValueAtRisk +FROM ProductionOrder po +INNER JOIN Items i ON po.ItemID = i.ItemID +INNER JOIN ItemType t ON i.ItemTypeID = t.ItemTypeID +LEFT JOIN WorkCenter wc ON po.WorkCenterID = wc.WorkCenterID +WHERE po.Status IN ('Planned', 'Released', 'InProgress') + AND po.PlannedCompletionDate < CAST(GETDATE() AS DATE); +GO + +-- ============================================= +-- REPORT 16: Component Shortage Report +-- ============================================= + +CREATE OR ALTER VIEW vw_ComponentShortage AS +WITH ProductionNeeds AS ( + SELECT + i.ItemID, + i.ItemCode, + i.ItemName, + t.TypeName AS ItemType, + SUM(bom.EffectiveQuantity * (po.OrderQuantity - po.QuantityCompleted)) AS RequiredQuantity, + MIN(po.PlannedCompletionDate) AS EarliestNeedDate, + COUNT(DISTINCT po.ProductionOrderID) AS AffectedOrders + FROM ProductionOrder po + INNER JOIN vw_BOMExplosion bom ON po.ItemID = bom.ParentItemID + INNER JOIN Items i ON bom.ComponentItemID = i.ItemID + INNER JOIN ItemType t ON i.ItemTypeID = t.ItemTypeID + WHERE po.Status IN ('Planned', 'Released', 'InProgress') + GROUP BY i.ItemID, i.ItemCode, i.ItemName, t.TypeName +) +SELECT + pn.ItemCode, + pn.ItemName, + pn.ItemType, + pn.RequiredQuantity, + ISNULL(inv.QuantityAvailable, 0) AS AvailableQuantity, + pn.RequiredQuantity - ISNULL(inv.QuantityAvailable, 0) AS ShortageQuantity, + pn.EarliestNeedDate, + DATEDIFF(DAY, GETDATE(), pn.EarliestNeedDate) AS DaysUntilNeeded, + pn.AffectedOrders, + CASE + WHEN DATEDIFF(DAY, GETDATE(), pn.EarliestNeedDate) <= 2 THEN 'Urgent' + WHEN DATEDIFF(DAY, GETDATE(), pn.EarliestNeedDate) <= 5 THEN 'High' + WHEN DATEDIFF(DAY, GETDATE(), pn.EarliestNeedDate) <= 10 THEN 'Medium' + ELSE 'Low' + END AS UrgencyLevel, + s.SupplierName AS PreferredSupplier, + si.LeadTimeDays, + DATEADD(DAY, si.LeadTimeDays, GETDATE()) AS PossibleArrival, + CASE + WHEN DATEADD(DAY, si.LeadTimeDays, GETDATE()) <= pn.EarliestNeedDate THEN 'Can Meet' + ELSE 'Will Be Late' + END AS SupplyStatus +FROM ProductionNeeds pn +LEFT JOIN ( + SELECT ItemID, SUM(QuantityAvailable) AS QuantityAvailable + FROM Inventory + GROUP BY ItemID +) inv ON pn.ItemID = inv.ItemID +LEFT JOIN SupplierItem si ON pn.ItemID = si.ItemID AND si.IsPreferred = 1 +LEFT JOIN Supplier s ON si.SupplierID = s.SupplierID +WHERE pn.RequiredQuantity > ISNULL(inv.QuantityAvailable, 0); +GO + +-- ============================================= +-- REPORT 17: Daily Production Schedule +-- ============================================= + +CREATE OR ALTER VIEW vw_DailyProductionSchedule AS +SELECT + po.PlannedCompletionDate AS ScheduledDate, + DATENAME(WEEKDAY, po.PlannedCompletionDate) AS DayOfWeek, + wc.WorkCenterName, + po.WorkOrderNumber, + po.Status, + i.ItemCode, + i.ItemName, + po.OrderQuantity - po.QuantityCompleted AS QuantityToProduce, + po.Priority, + CAST(((po.OrderQuantity - po.QuantityCompleted) / NULLIF(wc.Capacity, 0)) + AS DECIMAL(10,2)) AS EstimatedDays, + (po.OrderQuantity - po.QuantityCompleted) * i.StandardCost AS ProductionValue, + CASE + WHEN EXISTS ( + SELECT 1 FROM vw_ComponentShortage cs + INNER JOIN vw_BOMExplosion bom ON cs.ItemCode = bom.ComponentItemCode + WHERE bom.ParentItemID = po.ItemID + ) THEN 'Material Shortage' + WHEN po.PlannedCompletionDate < GETDATE() THEN 'Overdue' + WHEN po.PlannedCompletionDate = CAST(GETDATE() AS DATE) THEN 'Due Today' + ELSE 'On Schedule' + END AS ProductionStatus +FROM ProductionOrder po +INNER JOIN Items i ON po.ItemID = i.ItemID +LEFT JOIN WorkCenter wc ON po.WorkCenterID = wc.WorkCenterID +WHERE po.Status IN ('Planned', 'Released', 'InProgress') + AND po.PlannedCompletionDate BETWEEN CAST(GETDATE() AS DATE) AND DATEADD(DAY, 14, CAST(GETDATE() AS DATE)); +GO + +-- ============================================= +-- REPORT 18: Scrap and Waste Analysis +-- ============================================= + +CREATE OR ALTER VIEW vw_ScrapWasteAnalysis AS +SELECT + CAST(pc.CompletionDate AS DATE) AS CompletionDate, + DATEPART(YEAR, pc.CompletionDate) AS Year, + DATEPART(MONTH, pc.CompletionDate) AS Month, + wc.WorkCenterName, + i.ItemCode, + i.ItemName, + t.TypeName AS ItemType, + SUM(pc.QuantityCompleted) AS TotalCompleted, + SUM(pc.QuantityScrapped) AS TotalScrapped, + SUM(pc.QuantityCompleted + pc.QuantityScrapped) AS TotalProduced, + CAST((SUM(pc.QuantityScrapped) * 100.0 / + NULLIF(SUM(pc.QuantityCompleted + pc.QuantityScrapped), 0)) + AS DECIMAL(5,2)) AS ScrapRate, + SUM(pc.QuantityScrapped * i.StandardCost) AS ScrapValue, + COUNT(DISTINCT pc.ProductionOrderID) AS NumberOfOrders, + AVG(i.StandardCost) AS AvgUnitCost, + CASE + WHEN CAST((SUM(pc.QuantityScrapped) * 100.0 / + NULLIF(SUM(pc.QuantityCompleted + pc.QuantityScrapped), 0)) + AS DECIMAL(5,2)) > 10 THEN 'High' + WHEN CAST((SUM(pc.QuantityScrapped) * 100.0 / + NULLIF(SUM(pc.QuantityCompleted + pc.QuantityScrapped), 0)) + AS DECIMAL(5,2)) > 5 THEN 'Medium' + ELSE 'Low' + END AS ScrapLevel +FROM ProductionCompletion pc +INNER JOIN ProductionOrder po ON pc.ProductionOrderID = po.ProductionOrderID +INNER JOIN Items i ON po.ItemID = i.ItemID +INNER JOIN ItemType t ON i.ItemTypeID = t.ItemTypeID +LEFT JOIN WorkCenter wc ON pc.WorkCenterID = wc.WorkCenterID +GROUP BY + CAST(pc.CompletionDate AS DATE), + DATEPART(YEAR, pc.CompletionDate), + DATEPART(MONTH, pc.CompletionDate), + wc.WorkCenterName, + i.ItemCode, + i.ItemName, + t.TypeName; +GO + +-- ============================================= +-- REPORT 19: Customer Order Fulfillment Rate +-- ============================================= + +CREATE OR ALTER VIEW vw_CustomerFulfillmentRate AS +WITH CustomerMetrics AS ( + SELECT + c.CustomerID, + c.CustomerCode, + c.CustomerName, + COUNT(DISTINCT so.SalesOrderID) AS TotalOrders, + SUM(so.TotalAmount) AS TotalOrderValue, + SUM(CASE WHEN so.Status = 'Delivered' THEN 1 ELSE 0 END) AS DeliveredOrders, + SUM(CASE WHEN so.Status = 'Delivered' AND so.ShipDate <= so.RequestedDeliveryDate + THEN 1 ELSE 0 END) AS OnTimeDeliveries, + SUM(CASE WHEN so.Status = 'Delivered' THEN so.TotalAmount ELSE 0 END) AS DeliveredValue, + AVG(CASE WHEN so.ShipDate IS NOT NULL + THEN DATEDIFF(DAY, so.OrderDate, so.ShipDate) END) AS AvgDaysToShip, + AVG(CASE WHEN so.Status = 'Delivered' + THEN DATEDIFF(DAY, so.RequestedDeliveryDate, so.ShipDate) END) AS AvgDeliveryVariance + FROM Customer c + LEFT JOIN SalesOrder so ON c.CustomerID = so.CustomerID + WHERE c.IsActive = 1 + GROUP BY c.CustomerID, c.CustomerCode, c.CustomerName +) +SELECT + CustomerCode, + CustomerName, + TotalOrders, + TotalOrderValue, + DeliveredOrders, + OnTimeDeliveries, + DeliveredValue, + TotalOrders - DeliveredOrders AS PendingOrders, + TotalOrderValue - DeliveredValue AS PendingValue, + CAST((DeliveredOrders * 100.0 / NULLIF(TotalOrders, 0)) + AS DECIMAL(5,2)) AS FulfillmentRate, + CAST((OnTimeDeliveries * 100.0 / NULLIF(DeliveredOrders, 0)) + AS DECIMAL(5,2)) AS OnTimeDeliveryRate, + AvgDaysToShip, + AvgDeliveryVariance, + CASE + WHEN CAST((OnTimeDeliveries * 100.0 / NULLIF(DeliveredOrders, 0)) AS DECIMAL(5,2)) >= 95 THEN 'Excellent' + WHEN CAST((OnTimeDeliveries * 100.0 / NULLIF(DeliveredOrders, 0)) AS DECIMAL(5,2)) >= 85 THEN 'Good' + WHEN CAST((OnTimeDeliveries * 100.0 / NULLIF(DeliveredOrders, 0)) AS DECIMAL(5,2)) >= 75 THEN 'Fair' + ELSE 'Poor' + END AS ServiceLevel +FROM CustomerMetrics +WHERE TotalOrders > 0; +GO + +-- ============================================= +-- REPORT 20: Raw Material Usage by Period +-- ============================================= + +CREATE OR ALTER VIEW vw_RawMaterialUsage AS +SELECT + DATEPART(YEAR, it.TransactionDate) AS Year, + DATEPART(MONTH, it.TransactionDate) AS Month, + DATEPART(QUARTER, it.TransactionDate) AS Quarter, + t.TypeName AS ItemType, + i.ItemCode, + i.ItemName, + u.UnitCode, + SUM(CASE WHEN it.Quantity < 0 THEN ABS(it.Quantity) ELSE 0 END) AS TotalUsage, + SUM(CASE WHEN it.Quantity > 0 THEN it.Quantity ELSE 0 END) AS TotalReceipts, + COUNT(CASE WHEN it.Quantity < 0 THEN 1 END) AS NumberOfIssues, + AVG(CASE WHEN it.Quantity < 0 THEN ABS(it.Quantity) END) AS AvgIssueQuantity, + SUM(CASE WHEN it.Quantity < 0 THEN ABS(it.Quantity) * ISNULL(it.UnitCost, i.StandardCost) + ELSE 0 END) AS TotalUsageValue, + AVG(CASE WHEN it.Quantity < 0 THEN ISNULL(it.UnitCost, i.StandardCost) END) AS AvgUnitCost +FROM InventoryTransaction it +INNER JOIN Items i ON it.ItemID = i.ItemID +INNER JOIN ItemType t ON i.ItemTypeID = t.ItemTypeID +INNER JOIN UnitOfMeasure u ON i.UnitID = u.UnitID +WHERE t.TypeCode = 'RAW' + AND it.TransactionDate >= DATEADD(MONTH, -12, GETDATE()) +GROUP BY + DATEPART(YEAR, it.TransactionDate), + DATEPART(MONTH, it.TransactionDate), + DATEPART(QUARTER, it.TransactionDate), + t.TypeName, + i.ItemCode, + i.ItemName, + u.UnitCode; +GO + +PRINT 'All 20 manufacturing reports created successfully!'; +PRINT ''; +PRINT 'Available Reports:'; +PRINT '1. vw_BOMExplosion - Multi-Level BOM Explosion'; +PRINT '2. vw_WhereUsed - Where-Used Report'; +PRINT '3. vw_InventoryValuation - Inventory Valuation'; +PRINT '4. vw_ItemsBelowReorderPoint - Items Below Reorder Point'; +PRINT '5. vw_ProductionOrderStatus - Production Order Status'; +PRINT '6. vw_MaterialRequirements - Material Requirements Planning'; +PRINT '7. vw_WorkCenterCapacity - Work Center Capacity Analysis'; +PRINT '8. vw_ProductionCompletionSummary - Production Completion Summary'; +PRINT '9. vw_QualityInspectionSummary - Quality Inspection Summary'; +PRINT '10. vw_SupplierPerformance - Supplier Performance'; +PRINT '11. vw_PurchaseOrderStatus - Purchase Order Status'; +PRINT '12. vw_SalesOrderBacklog - Sales Order Backlog'; +PRINT '13. vw_CostRollUp - Cost Roll-Up by Item'; +PRINT '14. vw_InventoryTurnover - Inventory Turnover Analysis'; +PRINT '15. vw_LateProductionOrders - Late Production Orders'; +PRINT '16. vw_ComponentShortage - Component Shortage Report'; +PRINT '17. vw_DailyProductionSchedule - Daily Production Schedule'; +PRINT '18. vw_ScrapWasteAnalysis - Scrap and Waste Analysis'; +PRINT '19. vw_CustomerFulfillmentRate - Customer Order Fulfillment Rate'; +PRINT '20. vw_RawMaterialUsage - Raw Material Usage by Period'; +GO diff --git a/samples/databases/futon-manufacturing/04-sample-queries.sql b/samples/databases/futon-manufacturing/04-sample-queries.sql new file mode 100644 index 0000000000..164b7ec94f --- /dev/null +++ b/samples/databases/futon-manufacturing/04-sample-queries.sql @@ -0,0 +1,539 @@ +-- ============================================= +-- Sample Queries and Use Cases +-- Futon Manufacturing Database +-- ============================================= + +USE FutonManufacturing; +GO + +PRINT '============================================='; +PRINT 'SAMPLE QUERIES FOR FUTON MANUFACTURING DATABASE'; +PRINT '============================================='; +PRINT ''; + +-- ============================================= +-- 1. BILL OF MATERIALS QUERIES +-- ============================================= + +PRINT '1. BOM Explosion - Show all materials needed for Queen Luxury Futon'; +PRINT '---------------------------------------------------------------------'; +SELECT + REPLICATE(' ', Level - 1) + ComponentItemName AS Component, + ComponentType, + EffectiveQuantity, + UnitCode, + StandardCost AS UnitCost, + ExtendedCost, + BOMPath +FROM vw_BOMExplosion +WHERE ParentItemCode = 'FG-FUT-006' +ORDER BY Level, ComponentItemCode; +GO + +PRINT ''; +PRINT '2. Where Used - Find all products using Memory Foam'; +PRINT '---------------------------------------------------------------------'; +SELECT + ComponentItemName AS [Component], + ParentItemName AS [Used In], + ParentType, + Quantity, + UnitCode, + Level +FROM vw_WhereUsed +WHERE ComponentItemCode = 'RM-FILL-002' +ORDER BY Level, ParentItemCode; +GO + +PRINT ''; +PRINT '3. Calculate total raw material cost for each finished good'; +PRINT '---------------------------------------------------------------------'; +SELECT + ItemCode, + ItemName, + CalculatedMaterialCost AS MaterialCost, + LaborAndOverhead, + CurrentStandardCost AS TotalCost, + ListPrice, + GrossProfit, + GrossMarginPercent AS [Margin %], + ComponentCount +FROM vw_CostRollUp +WHERE ItemType = 'Finished Goods' +ORDER BY GrossMarginPercent DESC; +GO + +-- ============================================= +-- 2. INVENTORY MANAGEMENT QUERIES +-- ============================================= + +PRINT ''; +PRINT '4. Current Inventory Valuation by Type'; +PRINT '---------------------------------------------------------------------'; +SELECT + ItemType, + COUNT(DISTINCT ItemCode) AS ItemCount, + SUM(QuantityOnHand) AS TotalQuantity, + SUM(InventoryValue) AS TotalValue, + AVG(StandardCost) AS AvgUnitCost +FROM vw_InventoryValuation +GROUP BY ItemType +ORDER BY TotalValue DESC; +GO + +PRINT ''; +PRINT '5. Items Needing Reorder (Below Reorder Point)'; +PRINT '---------------------------------------------------------------------'; +SELECT + ItemType, + ItemCode, + ItemName, + QuantityAvailable AS Available, + ReorderPoint AS [Reorder Point], + ShortageQuantity AS Shortage, + PreferredSupplier AS Supplier, + PreferredPrice AS Price, + LeadTimeDays AS [Lead Days], + ExpectedArrival +FROM vw_ItemsBelowReorderPoint +ORDER BY ShortageQuantity DESC; +GO + +PRINT ''; +PRINT '6. Inventory Turnover - Identify slow moving items'; +PRINT '---------------------------------------------------------------------'; +SELECT TOP 10 + ItemCode, + ItemName, + ItemType, + QuantityOnHand AS [On Hand], + [Annual Usage], + TurnoverRatio AS [Turns/Year], + DaysOnHand AS [Days Supply], + InventoryValue AS [Inv Value], + MovementClass +FROM vw_InventoryTurnover +WHERE MovementClass IN ('Slow Moving', 'Non-Moving') +ORDER BY InventoryValue DESC; +GO + +-- ============================================= +-- 3. PRODUCTION PLANNING QUERIES +-- ============================================= + +PRINT ''; +PRINT '7. Material Requirements for Open Production Orders'; +PRINT '---------------------------------------------------------------------'; +SELECT + ItemCode, + ItemName, + ItemType, + SUM(RequiredQuantity) AS TotalRequired, + SUM(AvailableQuantity) AS TotalAvailable, + SUM(ShortageQuantity) AS TotalShortage, + COUNT(DISTINCT WorkOrderNumber) AS AffectedOrders +FROM vw_MaterialRequirements +GROUP BY ItemCode, ItemName, ItemType +HAVING SUM(ShortageQuantity) > 0 +ORDER BY SUM(ShortageQuantity) DESC; +GO + +PRINT ''; +PRINT '8. Work Center Capacity and Utilization'; +PRINT '---------------------------------------------------------------------'; +SELECT + WorkCenterName, + DailyCapacity, + ActiveOrders, + InProgressOrders, + TotalQuantityPending AS [Qty Pending], + DaysOfWork AS [Days Backlog], + PercentOfTotalOrders AS [% of Orders], + EarliestDueDate, + LatestDueDate +FROM vw_WorkCenterCapacity +ORDER BY DaysOfWork DESC; +GO + +PRINT ''; +PRINT '9. Production Schedule for Next 7 Days'; +PRINT '---------------------------------------------------------------------'; +SELECT + ScheduledDate, + DayOfWeek, + WorkCenterName, + WorkOrderNumber, + ItemName, + QuantityToProduce AS Quantity, + Priority, + ProductionStatus AS Status +FROM vw_DailyProductionSchedule +WHERE ScheduledDate BETWEEN CAST(GETDATE() AS DATE) AND DATEADD(DAY, 7, CAST(GETDATE() AS DATE)) +ORDER BY ScheduledDate, Priority, WorkCenterName; +GO + +-- ============================================= +-- 4. QUALITY AND SCRAP ANALYSIS +-- ============================================= + +PRINT ''; +PRINT '10. Scrap Analysis - Items with High Scrap Rates'; +PRINT '---------------------------------------------------------------------'; +SELECT + ItemCode, + ItemName, + ItemType, + SUM(TotalCompleted) AS Completed, + SUM(TotalScrapped) AS Scrapped, + AVG(ScrapRate) AS [Avg Scrap %], + SUM(ScrapValue) AS [Scrap $], + ScrapLevel +FROM vw_ScrapWasteAnalysis +GROUP BY ItemCode, ItemName, ItemType, ScrapLevel +HAVING AVG(ScrapRate) > 5 +ORDER BY SUM(ScrapValue) DESC; +GO + +-- ============================================= +-- 5. SUPPLIER PERFORMANCE QUERIES +-- ============================================= + +PRINT ''; +PRINT '11. Supplier Performance Scorecard'; +PRINT '---------------------------------------------------------------------'; +SELECT + SupplierName, + SupplierRating AS Rating, + TotalOrders AS Orders, + TotalPurchaseValue AS [Purchase Value], + OnTimeDeliveryRate AS [OT Delivery %], + AvgDeliveryDays AS [Avg Days], + PerformanceGrade AS Grade +FROM vw_SupplierPerformance +ORDER BY OnTimeDeliveryRate DESC; +GO + +-- ============================================= +-- 6. SALES AND CUSTOMER QUERIES +-- ============================================= + +PRINT ''; +PRINT '12. Customer Fulfillment Performance'; +PRINT '---------------------------------------------------------------------'; +SELECT + CustomerName, + TotalOrders AS Orders, + TotalOrderValue AS [Order Value], + DeliveredOrders AS Delivered, + PendingOrders AS Pending, + FulfillmentRate AS [Fulfill %], + OnTimeDeliveryRate AS [OnTime %], + AvgDaysToShip AS [Avg Ship Days], + ServiceLevel +FROM vw_CustomerFulfillmentRate +ORDER BY TotalOrderValue DESC; +GO + +PRINT ''; +PRINT '13. Sales Order Backlog Summary'; +PRINT '---------------------------------------------------------------------'; +SELECT + FulfillmentStatus AS Status, + COUNT(*) AS OrderCount, + SUM(TotalQuantityOrdered) AS TotalUnits, + SUM(QuantityBacklog) AS BacklogUnits, + SUM(OrderValue) AS OrderValue, + SUM(BacklogValue) AS BacklogValue, + AVG(DaysOpen) AS AvgDaysOpen +FROM vw_SalesOrderBacklog +GROUP BY FulfillmentStatus +ORDER BY BacklogValue DESC; +GO + +-- ============================================= +-- 7. PRODUCTION STATUS QUERIES +-- ============================================= + +PRINT ''; +PRINT '14. Late Production Orders - Overdue Work'; +PRINT '---------------------------------------------------------------------'; +SELECT + WorkOrderNumber, + ItemName, + OrderQuantity, + QuantityRemaining, + PlannedCompletionDate, + DaysLate, + LatenessSeverity, + ValueAtRisk, + WorkCenterName +FROM vw_LateProductionOrders +ORDER BY DaysLate DESC; +GO + +PRINT ''; +PRINT '15. Component Shortages Affecting Production'; +PRINT '---------------------------------------------------------------------'; +SELECT + ItemCode, + ItemName, + RequiredQuantity, + AvailableQuantity, + ShortageQuantity, + EarliestNeedDate, + DaysUntilNeeded, + AffectedOrders, + UrgencyLevel, + PreferredSupplier, + SupplyStatus +FROM vw_ComponentShortage +WHERE UrgencyLevel IN ('Urgent', 'High') +ORDER BY DaysUntilNeeded; +GO + +-- ============================================= +-- 8. ADVANCED ANALYTICAL QUERIES +-- ============================================= + +PRINT ''; +PRINT '16. Product Profitability Analysis'; +PRINT '---------------------------------------------------------------------'; +SELECT + i.ItemCode, + i.ItemName, + i.StandardCost, + i.ListPrice, + i.ListPrice - i.StandardCost AS GrossProfit, + CAST(((i.ListPrice - i.StandardCost) * 100.0 / NULLIF(i.ListPrice, 0)) AS DECIMAL(5,2)) AS [Margin %], + ISNULL(inv.QuantityOnHand, 0) AS [Stock Level], + i.ReorderPoint, + CASE + WHEN ISNULL(inv.QuantityOnHand, 0) < i.ReorderPoint THEN 'Low Stock' + WHEN ISNULL(inv.QuantityOnHand, 0) > i.ReorderPoint * 2 THEN 'Overstock' + ELSE 'Normal' + END AS StockStatus +FROM Items i +INNER JOIN ItemType t ON i.ItemTypeID = t.ItemTypeID +LEFT JOIN ( + SELECT ItemID, SUM(QuantityOnHand) AS QuantityOnHand + FROM Inventory + GROUP BY ItemID +) inv ON i.ItemID = inv.ItemID +WHERE t.TypeCode = 'FG' AND i.IsActive = 1 +ORDER BY [Margin %] DESC; +GO + +PRINT ''; +PRINT '17. Monthly Production Trend Analysis'; +PRINT '---------------------------------------------------------------------'; +SELECT + Year, + Month, + ItemType, + COUNT(DISTINCT ItemCode) AS Products, + SUM(TotalCompleted) AS UnitsProduced, + SUM(TotalScrapped) AS UnitsScrapped, + AVG(ScrapRate) AS [Avg Scrap %], + SUM(ProductionValue) AS [Production Value] +FROM vw_ProductionCompletionSummary +GROUP BY Year, Month, ItemType +ORDER BY Year DESC, Month DESC, ItemType; +GO + +PRINT ''; +PRINT '18. Top 10 Most Used Raw Materials (by value)'; +PRINT '---------------------------------------------------------------------'; +SELECT TOP 10 + ItemName, + ItemCode, + SUM(TotalUsage) AS TotalUsageQty, + UnitCode, + SUM(TotalUsageValue) AS UsageValue, + AVG(AvgUnitCost) AS AvgCost, + COUNT(*) AS Periods +FROM vw_RawMaterialUsage +GROUP BY ItemName, ItemCode, UnitCode +ORDER BY SUM(TotalUsageValue) DESC; +GO + +PRINT ''; +PRINT '19. Purchase Order Aging Analysis'; +PRINT '---------------------------------------------------------------------'; +SELECT + DeliveryStatus AS Status, + COUNT(*) AS OrderCount, + SUM(TotalAmount) AS TotalValue, + AVG(DaysSinceOrder) AS AvgDaysOpen, + SUM(CASE WHEN Status = 'Received' THEN 0 ELSE TotalAmount END) AS OpenValue +FROM vw_PurchaseOrderStatus +GROUP BY DeliveryStatus +ORDER BY OpenValue DESC; +GO + +PRINT ''; +PRINT '20. ABC Inventory Classification (by value)'; +PRINT '---------------------------------------------------------------------'; +WITH InventoryValue AS ( + SELECT + ItemCode, + ItemName, + ItemType, + QuantityOnHand, + InventoryValue, + SUM(InventoryValue) OVER () AS TotalInventoryValue, + InventoryValue * 100.0 / SUM(InventoryValue) OVER () AS PercentOfTotal, + SUM(InventoryValue * 100.0 / SUM(InventoryValue) OVER ()) + OVER (ORDER BY InventoryValue DESC) AS CumulativePercent + FROM vw_InventoryValuation +) +SELECT + ItemCode, + ItemName, + ItemType, + QuantityOnHand, + InventoryValue, + CAST(PercentOfTotal AS DECIMAL(5,2)) AS [% of Total], + CAST(CumulativePercent AS DECIMAL(5,2)) AS [Cumulative %], + CASE + WHEN CumulativePercent <= 80 THEN 'A' + WHEN CumulativePercent <= 95 THEN 'B' + ELSE 'C' + END AS ABCClass +FROM InventoryValue +WHERE InventoryValue > 0 +ORDER BY InventoryValue DESC; +GO + +-- ============================================= +-- 21. WHAT-IF SCENARIOS +-- ============================================= + +PRINT ''; +PRINT '21. What-If: Material Requirements for New Sales Order'; +PRINT '---------------------------------------------------------------------'; +-- Example: What if we need to produce 10 Queen Luxury Futons? +DECLARE @ItemCode NVARCHAR(50) = 'FG-FUT-006'; +DECLARE @Quantity DECIMAL(18,2) = 10; + +WITH MaterialNeeds AS ( + SELECT + ComponentItemCode, + ComponentItemName, + ComponentType, + SUM(EffectiveQuantity * @Quantity) AS RequiredQty, + UnitCode, + MAX(StandardCost) AS UnitCost, + SUM(ExtendedCost * @Quantity) AS TotalCost + FROM vw_BOMExplosion + WHERE ParentItemCode = @ItemCode + GROUP BY ComponentItemCode, ComponentItemName, ComponentType, UnitCode +) +SELECT + mn.ComponentItemName AS Material, + mn.ComponentType AS Type, + mn.RequiredQty AS Required, + ISNULL(inv.QuantityAvailable, 0) AS Available, + mn.RequiredQty - ISNULL(inv.QuantityAvailable, 0) AS Shortage, + mn.UnitCode, + mn.UnitCost, + mn.TotalCost, + CASE + WHEN ISNULL(inv.QuantityAvailable, 0) >= mn.RequiredQty THEN 'OK' + WHEN ISNULL(inv.QuantityAvailable, 0) > 0 THEN 'Partial' + ELSE 'Out of Stock' + END AS Status +FROM MaterialNeeds mn +LEFT JOIN ( + SELECT ItemID, i.ItemCode, SUM(QuantityAvailable) AS QuantityAvailable + FROM Inventory inv + INNER JOIN Items i ON inv.ItemID = i.ItemID + GROUP BY ItemID, i.ItemCode +) inv ON mn.ComponentItemCode = inv.ItemCode +ORDER BY mn.ComponentType, mn.ComponentItemName; +GO + +-- ============================================= +-- 22. KEY PERFORMANCE INDICATORS (KPIs) +-- ============================================= + +PRINT ''; +PRINT '22. Manufacturing KPI Dashboard'; +PRINT '---------------------------------------------------------------------'; +SELECT + 'Total Inventory Value' AS KPI, + CAST(SUM(InventoryValue) AS DECIMAL(18,2)) AS Value, + NULL AS Percent, + 'USD' AS Unit +FROM vw_InventoryValuation + +UNION ALL + +SELECT + 'Production Orders On Time', + COUNT(*), + CAST(COUNT(*) * 100.0 / (SELECT COUNT(*) FROM ProductionOrder WHERE Status = 'Completed') AS DECIMAL(5,2)), + '%' +FROM ProductionOrder +WHERE Status = 'Completed' AND ActualCompletionDate <= PlannedCompletionDate + +UNION ALL + +SELECT + 'Average Scrap Rate', + NULL, + CAST(AVG(ScrapRate) AS DECIMAL(5,2)), + '%' +FROM vw_ScrapWasteAnalysis + +UNION ALL + +SELECT + 'Supplier On-Time Delivery', + NULL, + CAST(AVG(OnTimeDeliveryRate) AS DECIMAL(5,2)), + '%' +FROM vw_SupplierPerformance + +UNION ALL + +SELECT + 'Customer Fulfillment Rate', + NULL, + CAST(AVG(FulfillmentRate) AS DECIMAL(5,2)), + '%' +FROM vw_CustomerFulfillmentRate + +UNION ALL + +SELECT + 'Items Below Reorder Point', + COUNT(*), + CAST(COUNT(*) * 100.0 / (SELECT COUNT(*) FROM Items WHERE IsActive = 1) AS DECIMAL(5,2)), + '%' +FROM vw_ItemsBelowReorderPoint + +UNION ALL + +SELECT + 'Late Production Orders', + COUNT(*), + NULL, + 'orders' +FROM vw_LateProductionOrders + +UNION ALL + +SELECT + 'Open Sales Order Backlog Value', + SUM(BacklogValue), + NULL, + 'USD' +FROM vw_SalesOrderBacklog; +GO + +PRINT ''; +PRINT '============================================='; +PRINT 'Sample queries completed successfully!'; +PRINT 'Use these as templates for your own analysis.'; +PRINT '============================================='; +GO diff --git a/samples/databases/futon-manufacturing/README.md b/samples/databases/futon-manufacturing/README.md new file mode 100644 index 0000000000..4a5a4565e5 --- /dev/null +++ b/samples/databases/futon-manufacturing/README.md @@ -0,0 +1,367 @@ +# Futon Manufacturing Database + +A comprehensive SQL Server database designed for a futon manufacturing business with multi-level bill of materials (BOM), inventory management, production tracking, and sales operations. + +## Overview + +This database manages the complete manufacturing lifecycle for a futon manufacturer that produces finished futons from raw materials (fill, fabric, frames) through intermediate components (pillows, mattresses, frames) to finished goods. + +## Features + +- **Multi-Level Bill of Materials (BOM)**: Supports complex product structures with multiple levels of assembly +- **Inventory Management**: Track inventory across multiple warehouses with transaction history +- **Production Management**: Work orders, production completions, and work center capacity tracking +- **Quality Control**: Inspection tracking for incoming, in-process, and final products +- **Purchasing**: Purchase orders and supplier management +- **Sales**: Customer orders and fulfillment tracking +- **20 Manufacturing Reports**: Comprehensive reporting views for operational insights + +## Database Structure + +### Core Tables + +#### Reference Tables +- `UnitOfMeasure` - Units like EA (Each), YD (Yard), LB (Pound) +- `ItemType` - Raw Material, Component, Finished Good +- `TransactionType` - Types of inventory transactions + +#### Master Data +- `Items` - All products (raw materials, components, finished goods) +- `BillOfMaterials` - Multi-level product structure +- `Warehouse` - Storage locations +- `WorkCenter` - Production work centers +- `Supplier` - Vendor information +- `Customer` - Customer information + +#### Operational Tables +- `Inventory` - Current inventory levels by warehouse +- `InventoryTransaction` - All inventory movements +- `PurchaseOrder` / `PurchaseOrderDetail` - Purchasing +- `ProductionOrder` / `ProductionOrderMaterial` / `ProductionCompletion` - Production +- `SalesOrder` / `SalesOrderDetail` - Sales +- `QualityInspection` - Quality control records + +## Product Hierarchy + +The database includes three levels of products: + +### Level 1: Raw Materials +- **Fill Materials**: Polyester fiber, memory foam, cotton, latex foam, down alternative +- **Fabrics**: Canvas (various colors), microfiber suede, linen blend, twill, velvet +- **Frame Materials**: Pine rails, hardwood slats, steel brackets, hinges, hardware +- **Finishes**: Wood stains and polyurethane + +### Level 2: Components +- **Pillows**: Various fills and fabric combinations +- **Mattresses**: Twin, Full, Queen sizes with different fill types +- **Frames**: Different sizes and finishes (Natural Oak, Dark Walnut) + +### Level 3: Finished Goods +- Complete futons combining mattress, frame, and pillows +- Multiple configurations from economy to luxury models +- Sizes: Twin, Full, Queen + +## Installation + +Run the SQL scripts in order: + +```sql +-- 1. Create database and schema +:r 01-schema.sql + +-- 2. Insert sample data +:r 02-sample-data.sql + +-- 3. Create manufacturing reports +:r 03-manufacturing-reports.sql + +-- 4. (Optional) Run sample queries +:r 04-sample-queries.sql +``` + +## Manufacturing Reports + +### 1. Multi-Level BOM Explosion (`vw_BOMExplosion`) +Shows complete material requirements for any item, recursively expanding through all levels. + +```sql +-- Get all materials needed to build a specific futon +SELECT * FROM vw_BOMExplosion +WHERE ParentItemCode = 'FG-FUT-001' +ORDER BY Level, ComponentItemCode; +``` + +### 2. Where-Used Report (`vw_WhereUsed`) +Shows where each component is used throughout the product structure. + +```sql +-- Find all products that use a specific fabric +SELECT * FROM vw_WhereUsed +WHERE ComponentItemCode = 'RM-FAB-001'; +``` + +### 3. Inventory Valuation (`vw_InventoryValuation`) +Current inventory value by warehouse and item type. + +```sql +-- Total inventory value by type +SELECT ItemType, SUM(InventoryValue) AS TotalValue +FROM vw_InventoryValuation +GROUP BY ItemType; +``` + +### 4. Items Below Reorder Point (`vw_ItemsBelowReorderPoint`) +Items that need to be reordered with supplier information. + +```sql +-- Get critical shortages +SELECT * FROM vw_ItemsBelowReorderPoint +ORDER BY ShortageQuantity DESC; +``` + +### 5. Production Order Status (`vw_ProductionOrderStatus`) +Track production orders with completion percentages and schedule status. + +```sql +-- Active production orders with status +SELECT * FROM vw_ProductionOrderStatus +WHERE Status IN ('Planned', 'Released', 'InProgress') +ORDER BY PlannedCompletionDate; +``` + +### 6. Material Requirements Planning - MRP (`vw_MaterialRequirements`) +Calculate material needs for all open production orders. + +```sql +-- Material shortages for production +SELECT * FROM vw_MaterialRequirements +WHERE AvailabilityStatus IN ('Out of Stock', 'Partial') +ORDER BY PlannedCompletionDate; +``` + +### 7. Work Center Capacity Analysis (`vw_WorkCenterCapacity`) +Analyze workload and capacity by work center. + +```sql +-- Work center utilization +SELECT * FROM vw_WorkCenterCapacity +ORDER BY DaysOfWork DESC; +``` + +### 8. Production Completion Summary (`vw_ProductionCompletionSummary`) +Production output and scrap rates by period. + +```sql +-- Monthly production summary +SELECT Year, Month, SUM(TotalCompleted) AS Units, AVG(ScrapRate) AS AvgScrapRate +FROM vw_ProductionCompletionSummary +GROUP BY Year, Month; +``` + +### 9. Quality Inspection Summary (`vw_QualityInspectionSummary`) +Quality metrics and acceptance rates. + +```sql +-- Quality performance by inspection type +SELECT InspectionType, AVG(AcceptanceRate) AS AvgAcceptanceRate +FROM vw_QualityInspectionSummary +GROUP BY InspectionType; +``` + +### 10. Supplier Performance (`vw_SupplierPerformance`) +Evaluate supplier delivery performance and ratings. + +```sql +-- Top performing suppliers +SELECT * FROM vw_SupplierPerformance +ORDER BY OnTimeDeliveryRate DESC; +``` + +### 11. Purchase Order Status (`vw_PurchaseOrderStatus`) +Track purchase orders and receiving progress. + +```sql +-- Overdue purchase orders +SELECT * FROM vw_PurchaseOrderStatus +WHERE DeliveryStatus = 'Overdue'; +``` + +### 12. Sales Order Backlog (`vw_SalesOrderBacklog`) +Monitor unfulfilled customer orders. + +```sql +-- Orders due soon +SELECT * FROM vw_SalesOrderBacklog +WHERE FulfillmentStatus = 'Due Soon' +ORDER BY RequestedDeliveryDate; +``` + +### 13. Cost Roll-Up (`vw_CostRollUp`) +Item costs with material cost breakdown and profit margins. + +```sql +-- Profit analysis for finished goods +SELECT * FROM vw_CostRollUp +WHERE ItemType = 'Finished Goods' +ORDER BY GrossMarginPercent DESC; +``` + +### 14. Inventory Turnover Analysis (`vw_InventoryTurnover`) +Analyze inventory movement and identify slow-moving items. + +```sql +-- Slow and non-moving inventory +SELECT * FROM vw_InventoryTurnover +WHERE MovementClass IN ('Slow Moving', 'Non-Moving'); +``` + +### 15. Late Production Orders (`vw_LateProductionOrders`) +Production orders past their due date. + +```sql +-- Critical late orders +SELECT * FROM vw_LateProductionOrders +WHERE LatenessSeverity IN ('Critical', 'High') +ORDER BY DaysLate DESC; +``` + +### 16. Component Shortage Report (`vw_ComponentShortage`) +Identify component shortages affecting production. + +```sql +-- Urgent shortages +SELECT * FROM vw_ComponentShortage +WHERE UrgencyLevel = 'Urgent' +ORDER BY DaysUntilNeeded; +``` + +### 17. Daily Production Schedule (`vw_DailyProductionSchedule`) +2-week production schedule by work center. + +```sql +-- This week's production schedule +SELECT * FROM vw_DailyProductionSchedule +WHERE ScheduledDate BETWEEN CAST(GETDATE() AS DATE) AND DATEADD(DAY, 7, CAST(GETDATE() AS DATE)) +ORDER BY ScheduledDate, Priority; +``` + +### 18. Scrap and Waste Analysis (`vw_ScrapWasteAnalysis`) +Track scrap rates and waste costs. + +```sql +-- High scrap items +SELECT * FROM vw_ScrapWasteAnalysis +WHERE ScrapLevel = 'High' +ORDER BY ScrapValue DESC; +``` + +### 19. Customer Order Fulfillment Rate (`vw_CustomerFulfillmentRate`) +Customer service levels and on-time delivery. + +```sql +-- Customer service performance +SELECT * FROM vw_CustomerFulfillmentRate +ORDER BY TotalOrderValue DESC; +``` + +### 20. Raw Material Usage by Period (`vw_RawMaterialUsage`) +Material consumption trends over time. + +```sql +-- Monthly material usage trends +SELECT Year, Month, ItemName, SUM(TotalUsage) AS Usage +FROM vw_RawMaterialUsage +GROUP BY Year, Month, ItemName +ORDER BY Year, Month, ItemName; +``` + +## Sample Data + +The database includes sample data for: +- 21 Raw materials (fills, fabrics, wood, metal, hardware, finishes) +- 15 Components (5 pillow types, 5 mattress types, 5 frame types) +- 6 Finished futon products +- 5 Suppliers with pricing +- 8 Customers +- 3 Warehouses +- 5 Work centers +- Initial inventory levels + +## Use Cases + +### Manufacturing Operations +1. **BOM Management**: Maintain multi-level product structures +2. **Production Planning**: Schedule work orders based on capacity +3. **Material Planning**: Calculate material requirements (MRP) +4. **Inventory Control**: Track materials, WIP, and finished goods +5. **Quality Management**: Monitor inspection results and defect rates + +### Cost Accounting +1. **Cost Roll-Up**: Calculate product costs from component costs +2. **Scrap Analysis**: Track waste and its financial impact +3. **Inventory Valuation**: Value inventory using standard costs +4. **Variance Analysis**: Compare actual vs. standard costs + +### Supply Chain +1. **Supplier Management**: Track supplier performance +2. **Purchase Planning**: Identify reorder needs +3. **Receiving**: Process incoming materials +4. **Lead Time Management**: Monitor delivery performance + +### Sales & Distribution +1. **Order Management**: Process customer orders +2. **Fulfillment**: Track order completion and shipping +3. **Customer Service**: Monitor service levels +4. **Backlog Management**: Manage unfulfilled orders + +## Schema Highlights + +### Multi-Level BOM +The `BillOfMaterials` table supports unlimited BOM levels with: +- Recursive relationships +- Scrap rate tracking +- Effective dating +- Unit of measure flexibility + +### Inventory Tracking +- Real-time available quantity (on-hand minus allocated) +- Complete transaction history +- Multi-warehouse support +- Cycle counting capabilities + +### Production Control +- Work order management +- Material issue tracking +- Production completion recording +- Work center capacity planning + +## Performance Considerations + +The database includes indexes on: +- BOM parent and component lookups +- Inventory transactions by item and date +- Order status and date ranges +- Item type filtering + +## Future Enhancements + +Potential areas for expansion: +- Routing (labor operations per work center) +- Shop floor data collection +- Advanced planning and scheduling +- Lot/serial number tracking +- Multi-currency support +- Cost variance tracking +- Demand forecasting + +## License + +This sample database is provided as-is for educational and demonstration purposes. + +## Author + +Created as part of SQL Server Samples repository for demonstrating manufacturing database design patterns. + +## Version History + +- 1.0.0 - Initial release with complete schema, sample data, and 20 reports From 0152dc1a715430dc2544c466a23630955cdca495 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 8 Nov 2025 12:07:13 +0000 Subject: [PATCH 2/2] Add Sales Operations with 20 Reports - Multi-Channel Support This commit adds comprehensive sales operations capabilities to the Futon Manufacturing Database, including support for Retail, Online, and Wholesale sales channels. New Features: - Multi-channel sales support (Retail, Online, Wholesale) - Retail store management with 7 sample stores - Sales territories and representative tracking - Sales quotation and conversion tracking - Sales returns and refund management - Promotional campaigns and pricing - Channel-specific price lists - 20 comprehensive sales operations reports Sales Reports (20 total): 1. Sales Performance by Channel - Multi-channel analysis 2. Store Performance - Individual store metrics 3. Sales Rep Performance - Territory and conversion tracking 4. Customer Sales Analysis - Segmentation and status 5. Product Sales Performance - By channel profitability 6. Sales Trend Analysis - MoM and YoY growth 7. Order Value Analysis - AOV and order size distribution 8. Returns Analysis - By reason, product, channel 9. Quote Conversion - Pipeline and win rates 10. Discount Analysis - Impact on margins 11. Top Products - Ranked by multiple metrics 12. Sales by Territory - Geographic performance 13. Channel Profitability - Full P&L by channel 14. Customer Lifetime Value - CLV with tiers 15. Sales Growth Analysis - Trends and patterns 16. Order Size Distribution - Basket analysis 17. Product Mix Analysis - Cross-sell opportunities 18. Time-Based Analysis - Day/hour patterns 19. Sales Pipeline - Funnel conversion rates 20. RFM Segmentation - Customer targeting Sample Data Added: - 6 sales territories across regions - 8 sales representatives - 7 retail stores (Portland, Seattle, SF, LA) - 15 sales orders across all channels - 2 sales returns with reasons - 2 sales quotes - 4 promotional campaigns - 3 channel-specific price lists Database Enhancements: - SalesChannel table (Retail, Online, Wholesale) - Store table for retail locations - SalesTerritory and SalesRep tables - SalesReturn and SalesReturnDetail tables - SalesQuote and SalesQuoteDetail tables - Promotion table for campaigns - PriceList and PriceListDetail tables - Enhanced SalesOrder with channel, store, and rep tracking - Discount tracking at order and line level Files Added: - 05-sales-schema-enhancements.sql - Sales tables and enhancements - 06-sales-sample-data.sql - Sales sample data (territories, reps, stores, orders) - 07-sales-reports.sql - 20 sales operations report views - 08-sales-sample-queries.sql - Example queries for sales analysis Documentation: - Updated README with sales reports documentation - Added sales operations use cases - Updated installation instructions - Version bumped to 2.0.0 --- .../05-sales-schema-enhancements.sql | 247 +++++ .../06-sales-sample-data.sql | 366 +++++++ .../futon-manufacturing/07-sales-reports.sql | 905 ++++++++++++++++++ .../08-sales-sample-queries.sql | 593 ++++++++++++ .../databases/futon-manufacturing/README.md | 235 ++++- 5 files changed, 2342 insertions(+), 4 deletions(-) create mode 100644 samples/databases/futon-manufacturing/05-sales-schema-enhancements.sql create mode 100644 samples/databases/futon-manufacturing/06-sales-sample-data.sql create mode 100644 samples/databases/futon-manufacturing/07-sales-reports.sql create mode 100644 samples/databases/futon-manufacturing/08-sales-sample-queries.sql diff --git a/samples/databases/futon-manufacturing/05-sales-schema-enhancements.sql b/samples/databases/futon-manufacturing/05-sales-schema-enhancements.sql new file mode 100644 index 0000000000..f0f63649ff --- /dev/null +++ b/samples/databases/futon-manufacturing/05-sales-schema-enhancements.sql @@ -0,0 +1,247 @@ +-- ============================================= +-- Sales Operations Schema Enhancements +-- Futon Manufacturing Database +-- ============================================= +-- Adds sales channel tracking, stores, and enhanced +-- sales operations capabilities +-- ============================================= + +USE FutonManufacturing; +GO + +-- ============================================= +-- Sales Channels and Stores +-- ============================================= + +CREATE TABLE SalesChannel ( + SalesChannelID INT IDENTITY(1,1) PRIMARY KEY, + ChannelCode NVARCHAR(20) NOT NULL UNIQUE, + ChannelName NVARCHAR(100) NOT NULL, + Description NVARCHAR(255), + IsActive BIT NOT NULL DEFAULT 1 +); + +INSERT INTO SalesChannel (ChannelCode, ChannelName, Description) VALUES +('RETAIL', 'Retail Store', 'Physical retail store sales'), +('ONLINE', 'Online/E-Commerce', 'Online website and marketplace sales'), +('WHOLESALE', 'Wholesale', 'Bulk sales to retailers and distributors'); + +CREATE TABLE Store ( + StoreID INT IDENTITY(1,1) PRIMARY KEY, + StoreCode NVARCHAR(20) NOT NULL UNIQUE, + StoreName NVARCHAR(100) NOT NULL, + SalesChannelID INT NOT NULL, + Manager NVARCHAR(100), + Phone NVARCHAR(20), + Email NVARCHAR(100), + Address NVARCHAR(255), + City NVARCHAR(100), + State NVARCHAR(50), + ZipCode NVARCHAR(20), + OpenDate DATE, + IsActive BIT NOT NULL DEFAULT 1, + CONSTRAINT FK_Store_SalesChannel FOREIGN KEY (SalesChannelID) REFERENCES SalesChannel(SalesChannelID) +); + +CREATE TABLE SalesTerritory ( + TerritoryID INT IDENTITY(1,1) PRIMARY KEY, + TerritoryCode NVARCHAR(20) NOT NULL UNIQUE, + TerritoryName NVARCHAR(100) NOT NULL, + Region NVARCHAR(50), + IsActive BIT NOT NULL DEFAULT 1 +); + +CREATE TABLE SalesRep ( + SalesRepID INT IDENTITY(1,1) PRIMARY KEY, + EmployeeCode NVARCHAR(20) NOT NULL UNIQUE, + FirstName NVARCHAR(50) NOT NULL, + LastName NVARCHAR(50) NOT NULL, + Email NVARCHAR(100), + Phone NVARCHAR(20), + TerritoryID INT, + HireDate DATE, + IsActive BIT NOT NULL DEFAULT 1, + CONSTRAINT FK_SalesRep_Territory FOREIGN KEY (TerritoryID) REFERENCES SalesTerritory(TerritoryID) +); + +-- ============================================= +-- Enhance Existing Tables +-- ============================================= + +-- Add sales channel tracking to SalesOrder +ALTER TABLE SalesOrder ADD SalesChannelID INT NULL; +ALTER TABLE SalesOrder ADD StoreID INT NULL; +ALTER TABLE SalesOrder ADD SalesRepID INT NULL; +ALTER TABLE SalesOrder ADD DiscountAmount DECIMAL(18,2) DEFAULT 0; +ALTER TABLE SalesOrder ADD NetAmount AS (TotalAmount - DiscountAmount) PERSISTED; + +ALTER TABLE SalesOrder ADD CONSTRAINT FK_SalesOrder_SalesChannel + FOREIGN KEY (SalesChannelID) REFERENCES SalesChannel(SalesChannelID); +ALTER TABLE SalesOrder ADD CONSTRAINT FK_SalesOrder_Store + FOREIGN KEY (StoreID) REFERENCES Store(StoreID); +ALTER TABLE SalesOrder ADD CONSTRAINT FK_SalesOrder_SalesRep + FOREIGN KEY (SalesRepID) REFERENCES SalesRep(SalesRepID); + +-- Add discount tracking to SalesOrderDetail +ALTER TABLE SalesOrderDetail ADD DiscountPercent DECIMAL(5,2) DEFAULT 0; +ALTER TABLE SalesOrderDetail ADD DiscountAmount AS (LineTotal * DiscountPercent / 100) PERSISTED; +ALTER TABLE SalesOrderDetail ADD NetAmount AS (LineTotal - (LineTotal * DiscountPercent / 100)) PERSISTED; + +-- Add customer segmentation +ALTER TABLE Customer ADD CustomerType NVARCHAR(20) DEFAULT 'Retail'; -- Retail, Wholesale, Online +ALTER TABLE Customer ADD SalesRepID INT NULL; +ALTER TABLE Customer ADD TerritoryID INT NULL; + +ALTER TABLE Customer ADD CONSTRAINT FK_Customer_SalesRep + FOREIGN KEY (SalesRepID) REFERENCES SalesRep(SalesRepID); +ALTER TABLE Customer ADD CONSTRAINT FK_Customer_Territory + FOREIGN KEY (TerritoryID) REFERENCES SalesTerritory(TerritoryID); + +-- ============================================= +-- Sales Returns and Exchanges +-- ============================================= + +CREATE TABLE ReturnReason ( + ReturnReasonID INT IDENTITY(1,1) PRIMARY KEY, + ReasonCode NVARCHAR(20) NOT NULL UNIQUE, + ReasonDescription NVARCHAR(255) NOT NULL, + IsActive BIT NOT NULL DEFAULT 1 +); + +INSERT INTO ReturnReason (ReasonCode, ReasonDescription) VALUES +('DEFECT', 'Product defect or quality issue'), +('DAMAGE', 'Damaged during shipping'), +('WRONG', 'Wrong item received'), +('NOFIT', 'Does not fit/wrong size'), +('EXPECT', 'Did not meet expectations'), +('CHANGE', 'Customer changed mind'), +('LATE', 'Delivery too late'), +('OTHER', 'Other reason'); + +CREATE TABLE SalesReturn ( + ReturnID INT IDENTITY(1,1) PRIMARY KEY, + ReturnNumber NVARCHAR(50) NOT NULL UNIQUE, + SalesOrderID INT NOT NULL, + CustomerID INT NOT NULL, + ReturnDate DATE NOT NULL DEFAULT CAST(GETDATE() AS DATE), + ReturnReasonID INT NOT NULL, + Status NVARCHAR(20) NOT NULL DEFAULT 'Pending', -- Pending, Approved, Received, Refunded, Denied + RefundAmount DECIMAL(18,2) DEFAULT 0, + RestockingFee DECIMAL(18,2) DEFAULT 0, + Notes NVARCHAR(MAX), + ApprovedBy NVARCHAR(100), + ApprovedDate DATETIME2, + CreatedDate DATETIME2 DEFAULT GETDATE(), + CONSTRAINT FK_Return_SalesOrder FOREIGN KEY (SalesOrderID) REFERENCES SalesOrder(SalesOrderID), + CONSTRAINT FK_Return_Customer FOREIGN KEY (CustomerID) REFERENCES Customer(CustomerID), + CONSTRAINT FK_Return_Reason FOREIGN KEY (ReturnReasonID) REFERENCES ReturnReason(ReturnReasonID) +); + +CREATE TABLE SalesReturnDetail ( + ReturnDetailID INT IDENTITY(1,1) PRIMARY KEY, + ReturnID INT NOT NULL, + SODetailID INT NOT NULL, + ItemID INT NOT NULL, + QuantityReturned DECIMAL(18,2) NOT NULL, + UnitPrice DECIMAL(18,4) NOT NULL, + RefundAmount DECIMAL(18,2) NOT NULL, + Disposition NVARCHAR(50), -- Restock, Scrap, Repair, RMA + CONSTRAINT FK_ReturnDetail_Return FOREIGN KEY (ReturnID) REFERENCES SalesReturn(ReturnID), + CONSTRAINT FK_ReturnDetail_SODetail FOREIGN KEY (SODetailID) REFERENCES SalesOrderDetail(SODetailID), + CONSTRAINT FK_ReturnDetail_Item FOREIGN KEY (ItemID) REFERENCES Items(ItemID) +); + +-- ============================================= +-- Sales Quotations +-- ============================================= + +CREATE TABLE SalesQuote ( + QuoteID INT IDENTITY(1,1) PRIMARY KEY, + QuoteNumber NVARCHAR(50) NOT NULL UNIQUE, + CustomerID INT NOT NULL, + SalesChannelID INT, + SalesRepID INT, + QuoteDate DATE NOT NULL DEFAULT CAST(GETDATE() AS DATE), + ExpirationDate DATE, + Status NVARCHAR(20) NOT NULL DEFAULT 'Draft', -- Draft, Sent, Accepted, Declined, Expired + Subtotal DECIMAL(18,2) DEFAULT 0, + DiscountAmount DECIMAL(18,2) DEFAULT 0, + TaxAmount DECIMAL(18,2) DEFAULT 0, + TotalAmount DECIMAL(18,2) DEFAULT 0, + ConvertedToOrderID INT NULL, + Notes NVARCHAR(MAX), + CreatedBy NVARCHAR(100), + CreatedDate DATETIME2 DEFAULT GETDATE(), + CONSTRAINT FK_Quote_Customer FOREIGN KEY (CustomerID) REFERENCES Customer(CustomerID), + CONSTRAINT FK_Quote_SalesChannel FOREIGN KEY (SalesChannelID) REFERENCES SalesChannel(SalesChannelID), + CONSTRAINT FK_Quote_SalesRep FOREIGN KEY (SalesRepID) REFERENCES SalesRep(SalesRepID), + CONSTRAINT FK_Quote_ConvertedOrder FOREIGN KEY (ConvertedToOrderID) REFERENCES SalesOrder(SalesOrderID) +); + +CREATE TABLE SalesQuoteDetail ( + QuoteDetailID INT IDENTITY(1,1) PRIMARY KEY, + QuoteID INT NOT NULL, + LineNumber INT NOT NULL, + ItemID INT NOT NULL, + Quantity DECIMAL(18,2) NOT NULL, + UnitPrice DECIMAL(18,4) NOT NULL, + DiscountPercent DECIMAL(5,2) DEFAULT 0, + LineTotal AS (Quantity * UnitPrice * (1 - DiscountPercent/100)) PERSISTED, + CONSTRAINT FK_QuoteDetail_Quote FOREIGN KEY (QuoteID) REFERENCES SalesQuote(QuoteID), + CONSTRAINT FK_QuoteDetail_Item FOREIGN KEY (ItemID) REFERENCES Items(ItemID) +); + +-- ============================================= +-- Promotions and Pricing +-- ============================================= + +CREATE TABLE Promotion ( + PromotionID INT IDENTITY(1,1) PRIMARY KEY, + PromotionCode NVARCHAR(50) NOT NULL UNIQUE, + PromotionName NVARCHAR(255) NOT NULL, + Description NVARCHAR(MAX), + DiscountPercent DECIMAL(5,2), + DiscountAmount DECIMAL(18,2), + StartDate DATE NOT NULL, + EndDate DATE NOT NULL, + IsActive BIT NOT NULL DEFAULT 1, + MinimumPurchase DECIMAL(18,2) DEFAULT 0, + ApplicableChannels NVARCHAR(255) -- CSV: RETAIL,ONLINE,WHOLESALE +); + +CREATE TABLE PriceList ( + PriceListID INT IDENTITY(1,1) PRIMARY KEY, + PriceListCode NVARCHAR(20) NOT NULL UNIQUE, + PriceListName NVARCHAR(100) NOT NULL, + SalesChannelID INT, + EffectiveDate DATE NOT NULL, + EndDate DATE, + IsActive BIT NOT NULL DEFAULT 1, + CONSTRAINT FK_PriceList_SalesChannel FOREIGN KEY (SalesChannelID) REFERENCES SalesChannel(SalesChannelID) +); + +CREATE TABLE PriceListDetail ( + PriceListDetailID INT IDENTITY(1,1) PRIMARY KEY, + PriceListID INT NOT NULL, + ItemID INT NOT NULL, + UnitPrice DECIMAL(18,4) NOT NULL, + MinimumQuantity DECIMAL(18,2) DEFAULT 1, + CONSTRAINT FK_PriceListDetail_PriceList FOREIGN KEY (PriceListID) REFERENCES PriceList(PriceListID), + CONSTRAINT FK_PriceListDetail_Item FOREIGN KEY (ItemID) REFERENCES Items(ItemID) +); + +-- ============================================= +-- Indexes for Performance +-- ============================================= + +CREATE NONCLUSTERED INDEX IX_SalesOrder_Channel ON SalesOrder(SalesChannelID, OrderDate); +CREATE NONCLUSTERED INDEX IX_SalesOrder_Store ON SalesOrder(StoreID, OrderDate); +CREATE NONCLUSTERED INDEX IX_SalesOrder_SalesRep ON SalesOrder(SalesRepID, OrderDate); +CREATE NONCLUSTERED INDEX IX_Customer_Type ON Customer(CustomerType); +CREATE NONCLUSTERED INDEX IX_SalesReturn_Date ON SalesReturn(ReturnDate); +CREATE NONCLUSTERED INDEX IX_SalesQuote_Status ON SalesQuote(Status, QuoteDate); + +GO + +PRINT 'Sales operations schema enhancements completed successfully!'; +GO diff --git a/samples/databases/futon-manufacturing/06-sales-sample-data.sql b/samples/databases/futon-manufacturing/06-sales-sample-data.sql new file mode 100644 index 0000000000..e17683ca36 --- /dev/null +++ b/samples/databases/futon-manufacturing/06-sales-sample-data.sql @@ -0,0 +1,366 @@ +-- ============================================= +-- Sales Operations Sample Data +-- Futon Manufacturing Database +-- ============================================= + +USE FutonManufacturing; +GO + +-- ============================================= +-- Sales Territories +-- ============================================= + +INSERT INTO SalesTerritory (TerritoryCode, TerritoryName, Region) VALUES +('NW-01', 'Pacific Northwest', 'West'), +('CA-01', 'Northern California', 'West'), +('CA-02', 'Southern California', 'West'), +('MW-01', 'Upper Midwest', 'Central'), +('SE-01', 'Southeast', 'East'), +('NE-01', 'Northeast', 'East'); + +-- ============================================= +-- Sales Representatives +-- ============================================= + +INSERT INTO SalesRep (EmployeeCode, FirstName, LastName, Email, Phone, TerritoryID, HireDate) VALUES +('SR-001', 'Michael', 'Johnson', 'mjohnson@futonmfg.com', '503-555-2001', (SELECT TerritoryID FROM SalesTerritory WHERE TerritoryCode = 'NW-01'), '2020-03-15'), +('SR-002', 'Emily', 'Williams', 'ewilliams@futonmfg.com', '415-555-2002', (SELECT TerritoryID FROM SalesTerritory WHERE TerritoryCode = 'CA-01'), '2019-06-20'), +('SR-003', 'David', 'Brown', 'dbrown@futonmfg.com', '310-555-2003', (SELECT TerritoryID FROM SalesTerritory WHERE TerritoryCode = 'CA-02'), '2021-01-10'), +('SR-004', 'Sarah', 'Davis', 'sdavis@futonmfg.com', '312-555-2004', (SELECT TerritoryID FROM SalesTerritory WHERE TerritoryCode = 'MW-01'), '2020-08-05'), +('SR-005', 'James', 'Miller', 'jmiller@futonmfg.com', '404-555-2005', (SELECT TerritoryID FROM SalesTerritory WHERE TerritoryCode = 'SE-01'), '2018-11-12'), +('SR-006', 'Jessica', 'Wilson', 'jwilson@futonmfg.com', '617-555-2006', (SELECT TerritoryID FROM SalesTerritory WHERE TerritoryCode = 'NE-01'), '2019-04-18'), +('SR-007', 'Robert', 'Moore', 'rmoore@futonmfg.com', '206-555-2007', (SELECT TerritoryID FROM SalesTerritory WHERE TerritoryCode = 'NW-01'), '2022-02-14'), +('SR-008', 'Amanda', 'Taylor', 'ataylor@futonmfg.com', '503-555-2008', (SELECT TerritoryID FROM SalesTerritory WHERE TerritoryCode = 'NW-01'), '2021-09-01'); + +-- ============================================= +-- Retail Stores +-- ============================================= + +DECLARE @RetailChannel INT = (SELECT SalesChannelID FROM SalesChannel WHERE ChannelCode = 'RETAIL'); +DECLARE @OnlineChannel INT = (SELECT SalesChannelID FROM SalesChannel WHERE ChannelCode = 'ONLINE'); +DECLARE @WholesaleChannel INT = (SELECT SalesChannelID FROM SalesChannel WHERE ChannelCode = 'WHOLESALE'); + +INSERT INTO Store (StoreCode, StoreName, SalesChannelID, Manager, Phone, Address, City, State, ZipCode, OpenDate) VALUES +-- Retail Stores +('STR-PDX-01', 'Portland Downtown Store', @RetailChannel, 'Lisa Anderson', '503-555-3001', '450 SW Broadway', 'Portland', 'OR', '97205', '2015-03-01'), +('STR-PDX-02', 'Portland East Side', @RetailChannel, 'Mark Thompson', '503-555-3002', '2200 E Burnside St', 'Portland', 'OR', '97214', '2018-06-15'), +('STR-SEA-01', 'Seattle Capitol Hill', @RetailChannel, 'Jennifer Lee', '206-555-3003', '1500 E Pine St', 'Seattle', 'WA', '98122', '2016-09-01'), +('STR-SF-01', 'San Francisco Store', @RetailChannel, 'Brian Chen', '415-555-3004', '850 Market St', 'San Francisco', 'CA', '94102', '2017-04-20'), +('STR-LA-01', 'Los Angeles Store', @RetailChannel, 'Maria Rodriguez', '310-555-3005', '1200 Wilshire Blvd', 'Los Angeles', 'CA', '90017', '2019-11-10'), +-- Online Channel (Virtual Store) +('ONLINE-01', 'E-Commerce Platform', @OnlineChannel, 'Thomas Wright', '503-555-4001', '1200 Industrial Parkway', 'Portland', 'OR', '97201', '2016-01-01'), +-- Wholesale (Virtual Store) +('WHSL-01', 'Wholesale Division', @WholesaleChannel, 'Patricia Martinez', '503-555-5001', '1200 Industrial Parkway', 'Portland', 'OR', '97201', '2015-01-01'); + +-- ============================================= +-- Update Existing Customers +-- ============================================= + +UPDATE Customer SET CustomerType = 'Retail', SalesRepID = (SELECT SalesRepID FROM SalesRep WHERE EmployeeCode = 'SR-001'), + TerritoryID = (SELECT TerritoryID FROM SalesTerritory WHERE TerritoryCode = 'NW-01') +WHERE CustomerCode = 'CUST-001'; + +UPDATE Customer SET CustomerType = 'Retail', SalesRepID = (SELECT SalesRepID FROM SalesRep WHERE EmployeeCode = 'SR-007'), + TerritoryID = (SELECT TerritoryID FROM SalesTerritory WHERE TerritoryCode = 'NW-01') +WHERE CustomerCode = 'CUST-002'; + +UPDATE Customer SET CustomerType = 'Retail', SalesRepID = (SELECT SalesRepID FROM SalesRep WHERE EmployeeCode = 'SR-002'), + TerritoryID = (SELECT TerritoryID FROM SalesTerritory WHERE TerritoryCode = 'CA-01') +WHERE CustomerCode = 'CUST-003'; + +UPDATE Customer SET CustomerType = 'Wholesale', SalesRepID = (SELECT SalesRepID FROM SalesRep WHERE EmployeeCode = 'SR-001'), + TerritoryID = (SELECT TerritoryID FROM SalesTerritory WHERE TerritoryCode = 'NW-01') +WHERE CustomerCode = 'CUST-004'; + +UPDATE Customer SET CustomerType = 'Online', SalesRepID = (SELECT SalesRepID FROM SalesRep WHERE EmployeeCode = 'SR-008'), + TerritoryID = (SELECT TerritoryID FROM SalesTerritory WHERE TerritoryCode = 'NW-01') +WHERE CustomerCode = 'CUST-005'; + +UPDATE Customer SET CustomerType = 'Wholesale', SalesRepID = (SELECT SalesRepID FROM SalesRep WHERE EmployeeCode = 'SR-007'), + TerritoryID = (SELECT TerritoryID FROM SalesTerritory WHERE TerritoryCode = 'NW-01') +WHERE CustomerCode = 'CUST-006'; + +UPDATE Customer SET CustomerType = 'Retail', SalesRepID = (SELECT SalesRepID FROM SalesRep WHERE EmployeeCode = 'SR-002'), + TerritoryID = (SELECT TerritoryID FROM SalesTerritory WHERE TerritoryCode = 'CA-01') +WHERE CustomerCode = 'CUST-007'; + +UPDATE Customer SET CustomerType = 'Wholesale', SalesRepID = (SELECT SalesRepID FROM SalesRep WHERE EmployeeCode = 'SR-001'), + TerritoryID = (SELECT TerritoryID FROM SalesTerritory WHERE TerritoryCode = 'NW-01') +WHERE CustomerCode = 'CUST-008'; + +-- ============================================= +-- Sample Sales Orders with Channel Data +-- ============================================= + +-- Get IDs we'll need +DECLARE @MainWH INT = (SELECT WarehouseID FROM Warehouse WHERE WarehouseCode = 'WH-MAIN'); +DECLARE @WestWH INT = (SELECT WarehouseID FROM Warehouse WHERE WarehouseCode = 'WH-WEST'); +DECLARE @EastWH INT = (SELECT WarehouseID FROM Warehouse WHERE WarehouseCode = 'WH-EAST'); + +-- Sales Orders for October 2024 +INSERT INTO SalesOrder (OrderNumber, CustomerID, WarehouseID, SalesChannelID, StoreID, SalesRepID, OrderDate, RequestedDeliveryDate, ShipDate, Status, Subtotal, TaxAmount, ShippingAmount, DiscountAmount, TotalAmount, CreatedBy) VALUES +-- Retail Store Sales +('SO-2024-1001', (SELECT CustomerID FROM Customer WHERE CustomerCode = 'CUST-001'), @MainWH, @RetailChannel, + (SELECT StoreID FROM Store WHERE StoreCode = 'STR-PDX-01'), (SELECT SalesRepID FROM SalesRep WHERE EmployeeCode = 'SR-001'), + '2024-10-01', '2024-10-05', '2024-10-04', 'Delivered', 1199.97, 95.00, 50.00, 60.00, 1284.97, 'system'), + +('SO-2024-1002', (SELECT CustomerID FROM Customer WHERE CustomerCode = 'CUST-003'), @WestWH, @RetailChannel, + (SELECT StoreID FROM Store WHERE StoreCode = 'STR-SF-01'), (SELECT SalesRepID FROM SalesRep WHERE EmployeeCode = 'SR-002'), + '2024-10-02', '2024-10-08', '2024-10-07', 'Delivered', 1599.98, 128.00, 75.00, 0, 1802.98, 'system'), + +('SO-2024-1003', (SELECT CustomerID FROM Customer WHERE CustomerCode = 'CUST-007'), @WestWH, @RetailChannel, + (SELECT StoreID FROM Store WHERE StoreCode = 'STR-LA-01'), (SELECT SalesRepID FROM SalesRep WHERE EmployeeCode = 'SR-003'), + '2024-10-03', '2024-10-10', '2024-10-09', 'Delivered', 2399.97, 192.00, 100.00, 120.00, 2571.97, 'system'), + +-- Online Sales +('SO-2024-1004', (SELECT CustomerID FROM Customer WHERE CustomerCode = 'CUST-005'), @MainWH, @OnlineChannel, + (SELECT StoreID FROM Store WHERE StoreCode = 'ONLINE-01'), (SELECT SalesRepID FROM SalesRep WHERE EmployeeCode = 'SR-008'), + '2024-10-05', '2024-10-12', '2024-10-08', 'Delivered', 799.99, 64.00, 25.00, 40.00, 848.99, 'system'), + +('SO-2024-1005', (SELECT CustomerID FROM Customer WHERE CustomerCode = 'CUST-005'), @MainWH, @OnlineChannel, + (SELECT StoreID FROM Store WHERE StoreCode = 'ONLINE-01'), (SELECT SalesRepID FROM SalesRep WHERE EmployeeCode = 'SR-008'), + '2024-10-07', '2024-10-14', '2024-10-10', 'Delivered', 599.99, 48.00, 25.00, 0, 672.99, 'system'), + +-- Wholesale Orders +('SO-2024-1006', (SELECT CustomerID FROM Customer WHERE CustomerCode = 'CUST-004'), @MainWH, @WholesaleChannel, + (SELECT StoreID FROM Store WHERE StoreCode = 'WHSL-01'), (SELECT SalesRepID FROM SalesRep WHERE EmployeeCode = 'SR-001'), + '2024-10-08', '2024-10-20', '2024-10-18', 'Delivered', 9999.60, 0, 500.00, 999.96, 9499.64, 'system'), + +('SO-2024-1007', (SELECT CustomerID FROM Customer WHERE CustomerCode = 'CUST-006'), @MainWH, @WholesaleChannel, + (SELECT StoreID FROM Store WHERE StoreCode = 'WHSL-01'), (SELECT SalesRepID FROM SalesRep WHERE EmployeeCode = 'SR-007'), + '2024-10-10', '2024-10-25', '2024-10-22', 'Delivered', 7999.68, 0, 400.00, 800.00, 7599.68, 'system'), + +('SO-2024-1008', (SELECT CustomerID FROM Customer WHERE CustomerCode = 'CUST-008'), @MainWH, @WholesaleChannel, + (SELECT StoreID FROM Store WHERE StoreCode = 'WHSL-01'), (SELECT SalesRepID FROM SalesRep WHERE EmployeeCode = 'SR-001'), + '2024-10-12', '2024-10-30', '2024-10-28', 'Delivered', 5999.76, 0, 300.00, 600.00, 5699.76, 'system'), + +-- November Sales (Recent) +('SO-2024-1101', (SELECT CustomerID FROM Customer WHERE CustomerCode = 'CUST-001'), @MainWH, @RetailChannel, + (SELECT StoreID FROM Store WHERE StoreCode = 'STR-PDX-02'), (SELECT SalesRepID FROM SalesRep WHERE EmployeeCode = 'SR-001'), + '2024-11-01', '2024-11-08', '2024-11-05', 'Delivered', 899.99, 72.00, 50.00, 45.00, 976.99, 'system'), + +('SO-2024-1102', (SELECT CustomerID FROM Customer WHERE CustomerCode = 'CUST-002'), @MainWH, @RetailChannel, + (SELECT StoreID FROM Store WHERE StoreCode = 'STR-SEA-01'), (SELECT SalesRepID FROM SalesRep WHERE EmployeeCode = 'SR-007'), + '2024-11-02', '2024-11-10', NULL, 'Shipped', 1199.98, 96.00, 60.00, 0, 1355.98, 'system'), + +('SO-2024-1103', (SELECT CustomerID FROM Customer WHERE CustomerCode = 'CUST-005'), @MainWH, @OnlineChannel, + (SELECT StoreID FROM Store WHERE StoreCode = 'ONLINE-01'), (SELECT SalesRepID FROM SalesRep WHERE EmployeeCode = 'SR-008'), + '2024-11-03', '2024-11-12', NULL, 'InProduction', 1599.98, 128.00, 50.00, 80.00, 1697.98, 'system'), + +('SO-2024-1104', (SELECT CustomerID FROM Customer WHERE CustomerCode = 'CUST-004'), @MainWH, @WholesaleChannel, + (SELECT StoreID FROM Store WHERE StoreCode = 'WHSL-01'), (SELECT SalesRepID FROM SalesRep WHERE EmployeeCode = 'SR-001'), + '2024-11-04', '2024-11-20', NULL, 'Confirmed', 11999.40, 0, 600.00, 1200.00, 11399.40, 'system'), + +('SO-2024-1105', (SELECT CustomerID FROM Customer WHERE CustomerCode = 'CUST-003'), @WestWH, @RetailChannel, + (SELECT StoreID FROM Store WHERE StoreCode = 'STR-SF-01'), (SELECT SalesRepID FROM SalesRep WHERE EmployeeCode = 'SR-002'), + '2024-11-05', '2024-11-15', NULL, 'Confirmed', 2399.96, 192.00, 100.00, 120.00, 2571.96, 'system'), + +('SO-2024-1106', (SELECT CustomerID FROM Customer WHERE CustomerCode = 'CUST-007'), @WestWH, @OnlineChannel, + (SELECT StoreID FROM Store WHERE StoreCode = 'ONLINE-01'), (SELECT SalesRepID FROM SalesRep WHERE EmployeeCode = 'SR-008'), + '2024-11-06', '2024-11-16', NULL, 'Confirmed', 1799.97, 144.00, 50.00, 90.00, 1903.97, 'system'), + +('SO-2024-1107', (SELECT CustomerID FROM Customer WHERE CustomerCode = 'CUST-006'), @MainWH, @WholesaleChannel, + (SELECT StoreID FROM Store WHERE StoreCode = 'WHSL-01'), (SELECT SalesRepID FROM SalesRep WHERE EmployeeCode = 'SR-007'), + '2024-11-07', '2024-11-25', NULL, 'Confirmed', 9599.52, 0, 500.00, 960.00, 9139.52, 'system'); + +-- ============================================= +-- Sales Order Details +-- ============================================= + +-- SO-2024-1001 (Retail - PDX Downtown) +INSERT INTO SalesOrderDetail (SalesOrderID, LineNumber, ItemID, Quantity, UnitPrice, DiscountPercent) VALUES +((SELECT SalesOrderID FROM SalesOrder WHERE OrderNumber = 'SO-2024-1001'), 1, + (SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-002'), 2, 399.99, 5.0), +((SELECT SalesOrderID FROM SalesOrder WHERE OrderNumber = 'SO-2024-1001'), 2, + (SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-001'), 1, 299.99, 0); + +-- SO-2024-1002 (Retail - SF) +INSERT INTO SalesOrderDetail (SalesOrderID, LineNumber, ItemID, Quantity, UnitPrice, DiscountPercent) VALUES +((SELECT SalesOrderID FROM SalesOrder WHERE OrderNumber = 'SO-2024-1002'), 1, + (SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-003'), 1, 599.99, 0), +((SELECT SalesOrderID FROM SalesOrder WHERE OrderNumber = 'SO-2024-1002'), 2, + (SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-006'), 1, 899.99, 0); + +-- SO-2024-1003 (Retail - LA) +INSERT INTO SalesOrderDetail (SalesOrderID, LineNumber, ItemID, Quantity, UnitPrice, DiscountPercent) VALUES +((SELECT SalesOrderID FROM SalesOrder WHERE OrderNumber = 'SO-2024-1003'), 1, + (SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-006'), 2, 899.99, 5.0), +((SELECT SalesOrderID FROM SalesOrder WHERE OrderNumber = 'SO-2024-1003'), 2, + (SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-004'), 1, 799.99, 0); + +-- SO-2024-1004 (Online) +INSERT INTO SalesOrderDetail (SalesOrderID, LineNumber, ItemID, Quantity, UnitPrice, DiscountPercent) VALUES +((SELECT SalesOrderID FROM SalesOrder WHERE OrderNumber = 'SO-2024-1004'), 1, + (SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-004'), 1, 799.99, 5.0); + +-- SO-2024-1005 (Online) +INSERT INTO SalesOrderDetail (SalesOrderID, LineNumber, ItemID, Quantity, UnitPrice, DiscountPercent) VALUES +((SELECT SalesOrderID FROM SalesOrder WHERE OrderNumber = 'SO-2024-1005'), 1, + (SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-003'), 1, 599.99, 0); + +-- SO-2024-1006 (Wholesale - Large order) +INSERT INTO SalesOrderDetail (SalesOrderID, LineNumber, ItemID, Quantity, UnitPrice, DiscountPercent) VALUES +((SELECT SalesOrderID FROM SalesOrder WHERE OrderNumber = 'SO-2024-1006'), 1, + (SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-001'), 12, 299.99, 10.0), +((SELECT SalesOrderID FROM SalesOrder WHERE OrderNumber = 'SO-2024-1006'), 2, + (SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-002'), 15, 399.99, 10.0), +((SELECT SalesOrderID FROM SalesOrder WHERE OrderNumber = 'SO-2024-1006'), 3, + (SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-005'), 8, 499.99, 10.0); + +-- SO-2024-1007 (Wholesale) +INSERT INTO SalesOrderDetail (SalesOrderID, LineNumber, ItemID, Quantity, UnitPrice, DiscountPercent) VALUES +((SELECT SalesOrderID FROM SalesOrder WHERE OrderNumber = 'SO-2024-1007'), 1, + (SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-002'), 10, 399.99, 10.0), +((SELECT SalesOrderID FROM SalesOrder WHERE OrderNumber = 'SO-2024-1007'), 2, + (SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-003'), 10, 599.99, 10.0); + +-- SO-2024-1008 (Wholesale) +INSERT INTO SalesOrderDetail (SalesOrderID, LineNumber, ItemID, Quantity, UnitPrice, DiscountPercent) VALUES +((SELECT SalesOrderID FROM SalesOrder WHERE OrderNumber = 'SO-2024-1008'), 1, + (SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-001'), 20, 299.99, 10.0); + +-- November orders +INSERT INTO SalesOrderDetail (SalesOrderID, LineNumber, ItemID, Quantity, UnitPrice, DiscountPercent) VALUES +((SELECT SalesOrderID FROM SalesOrder WHERE OrderNumber = 'SO-2024-1101'), 1, + (SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-006'), 1, 899.99, 5.0); + +INSERT INTO SalesOrderDetail (SalesOrderID, LineNumber, ItemID, Quantity, UnitPrice, DiscountPercent) VALUES +((SELECT SalesOrderID FROM SalesOrder WHERE OrderNumber = 'SO-2024-1102'), 1, + (SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-002'), 3, 399.99, 0); + +INSERT INTO SalesOrderDetail (SalesOrderID, LineNumber, ItemID, Quantity, UnitPrice, DiscountPercent) VALUES +((SELECT SalesOrderID FROM SalesOrder WHERE OrderNumber = 'SO-2024-1103'), 1, + (SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-004'), 2, 799.99, 5.0); + +INSERT INTO SalesOrderDetail (SalesOrderID, LineNumber, ItemID, Quantity, UnitPrice, DiscountPercent) VALUES +((SELECT SalesOrderID FROM SalesOrder WHERE OrderNumber = 'SO-2024-1104'), 1, + (SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-002'), 15, 399.99, 10.0), +((SELECT SalesOrderID FROM SalesOrder WHERE OrderNumber = 'SO-2024-1104'), 2, + (SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-005'), 10, 499.99, 10.0); + +INSERT INTO SalesOrderDetail (SalesOrderID, LineNumber, ItemID, Quantity, UnitPrice, DiscountPercent) VALUES +((SELECT SalesOrderID FROM SalesOrder WHERE OrderNumber = 'SO-2024-1105'), 1, + (SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-004'), 3, 799.99, 5.0); + +INSERT INTO SalesOrderDetail (SalesOrderID, LineNumber, ItemID, Quantity, UnitPrice, DiscountPercent) VALUES +((SELECT SalesOrderID FROM SalesOrder WHERE OrderNumber = 'SO-2024-1106'), 1, + (SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-003'), 3, 599.99, 5.0); + +INSERT INTO SalesOrderDetail (SalesOrderID, LineNumber, ItemID, Quantity, UnitPrice, DiscountPercent) VALUES +((SELECT SalesOrderID FROM SalesOrder WHERE OrderNumber = 'SO-2024-1107'), 1, + (SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-001'), 16, 299.99, 10.0), +((SELECT SalesOrderID FROM SalesOrder WHERE OrderNumber = 'SO-2024-1107'), 2, + (SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-002'), 12, 399.99, 10.0); + +-- Update shipped quantities for delivered orders +UPDATE SalesOrderDetail SET QuantityShipped = Quantity +WHERE SalesOrderID IN ( + SELECT SalesOrderID FROM SalesOrder + WHERE Status IN ('Delivered', 'Shipped') +); + +-- ============================================= +-- Sample Sales Returns +-- ============================================= + +INSERT INTO SalesReturn (ReturnNumber, SalesOrderID, CustomerID, ReturnDate, ReturnReasonID, Status, RefundAmount, RestockingFee, ApprovedBy, ApprovedDate) VALUES +('RET-2024-001', + (SELECT SalesOrderID FROM SalesOrder WHERE OrderNumber = 'SO-2024-1001'), + (SELECT CustomerID FROM Customer WHERE CustomerCode = 'CUST-001'), + '2024-10-10', + (SELECT ReturnReasonID FROM ReturnReason WHERE ReasonCode = 'CHANGE'), + 'Refunded', 399.99, 0, 'Manager1', '2024-10-10'), + +('RET-2024-002', + (SELECT SalesOrderID FROM SalesOrder WHERE OrderNumber = 'SO-2024-1003'), + (SELECT CustomerID FROM Customer WHERE CustomerCode = 'CUST-007'), + '2024-10-15', + (SELECT ReturnReasonID FROM ReturnReason WHERE ReasonCode = 'DEFECT'), + 'Refunded', 899.99, 0, 'Manager2', '2024-10-15'); + +INSERT INTO SalesReturnDetail (ReturnID, SODetailID, ItemID, QuantityReturned, UnitPrice, RefundAmount, Disposition) VALUES +((SELECT ReturnID FROM SalesReturn WHERE ReturnNumber = 'RET-2024-001'), + (SELECT SODetailID FROM SalesOrderDetail WHERE SalesOrderID = (SELECT SalesOrderID FROM SalesOrder WHERE OrderNumber = 'SO-2024-1001') AND LineNumber = 1), + (SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-002'), 1, 399.99, 399.99, 'Restock'), + +((SELECT ReturnID FROM SalesReturn WHERE ReturnNumber = 'RET-2024-002'), + (SELECT SODetailID FROM SalesOrderDetail WHERE SalesOrderID = (SELECT SalesOrderID FROM SalesOrder WHERE OrderNumber = 'SO-2024-1003') AND LineNumber = 1), + (SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-006'), 1, 899.99, 899.99, 'Scrap'); + +-- ============================================= +-- Sample Sales Quotes +-- ============================================= + +INSERT INTO SalesQuote (QuoteNumber, CustomerID, SalesChannelID, SalesRepID, QuoteDate, ExpirationDate, Status, Subtotal, DiscountAmount, TaxAmount, TotalAmount) VALUES +('QT-2024-001', + (SELECT CustomerID FROM Customer WHERE CustomerCode = 'CUST-004'), + @WholesaleChannel, + (SELECT SalesRepID FROM SalesRep WHERE EmployeeCode = 'SR-001'), + '2024-11-05', '2024-12-05', 'Sent', 14999.25, 1500.00, 0, 13499.25), + +('QT-2024-002', + (SELECT CustomerID FROM Customer WHERE CustomerCode = 'CUST-006'), + @WholesaleChannel, + (SELECT SalesRepID FROM SalesRep WHERE EmployeeCode = 'SR-007'), + '2024-11-06', '2024-12-06', 'Sent', 11999.40, 1200.00, 0, 10799.40); + +INSERT INTO SalesQuoteDetail (QuoteID, LineNumber, ItemID, Quantity, UnitPrice, DiscountPercent) VALUES +((SELECT QuoteID FROM SalesQuote WHERE QuoteNumber = 'QT-2024-001'), 1, + (SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-005'), 25, 499.99, 10.0), +((SELECT QuoteID FROM SalesQuote WHERE QuoteNumber = 'QT-2024-001'), 2, + (SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-003'), 5, 599.99, 10.0); + +INSERT INTO SalesQuoteDetail (QuoteID, LineNumber, ItemID, Quantity, UnitPrice, DiscountPercent) VALUES +((SELECT QuoteID FROM SalesQuote WHERE QuoteNumber = 'QT-2024-002'), 1, + (SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-002'), 20, 399.99, 10.0), +((SELECT QuoteID FROM SalesQuote WHERE QuoteNumber = 'QT-2024-002'), 2, + (SELECT ItemID FROM Items WHERE ItemCode = 'FG-FUT-004'), 10, 799.99, 10.0); + +-- ============================================= +-- Promotions +-- ============================================= + +INSERT INTO Promotion (PromotionCode, PromotionName, Description, DiscountPercent, StartDate, EndDate, IsActive, MinimumPurchase, ApplicableChannels) VALUES +('FALL2024', 'Fall Clearance Sale', 'Fall season clearance event', 15.0, '2024-09-15', '2024-11-30', 1, 500.00, 'RETAIL,ONLINE'), +('BULK10', 'Wholesale Bulk Discount', '10% off bulk wholesale orders', 10.0, '2024-01-01', '2024-12-31', 1, 5000.00, 'WHOLESALE'), +('BLACKFRI', 'Black Friday Special', 'Black Friday mega sale', 25.0, '2024-11-29', '2024-11-29', 1, 0, 'RETAIL,ONLINE'), +('HOLIDAY24', 'Holiday Season Sale', 'Holiday promotional pricing', 20.0, '2024-12-01', '2024-12-31', 1, 750.00, 'RETAIL,ONLINE'); + +-- ============================================= +-- Price Lists +-- ============================================= + +INSERT INTO PriceList (PriceListCode, PriceListName, SalesChannelID, EffectiveDate, IsActive) VALUES +('PL-RETAIL', 'Retail Price List', @RetailChannel, '2024-01-01', 1), +('PL-ONLINE', 'Online Price List', @OnlineChannel, '2024-01-01', 1), +('PL-WHOLESALE', 'Wholesale Price List', @WholesaleChannel, '2024-01-01', 1); + +-- Insert price list details for finished goods +INSERT INTO PriceListDetail (PriceListID, ItemID, UnitPrice, MinimumQuantity) +SELECT + (SELECT PriceListID FROM PriceList WHERE PriceListCode = 'PL-RETAIL'), + ItemID, + ListPrice, + 1 +FROM Items WHERE ItemTypeID = (SELECT ItemTypeID FROM ItemType WHERE TypeCode = 'FG'); + +INSERT INTO PriceListDetail (PriceListID, ItemID, UnitPrice, MinimumQuantity) +SELECT + (SELECT PriceListID FROM PriceList WHERE PriceListCode = 'PL-ONLINE'), + ItemID, + ListPrice * 0.98, -- 2% discount for online + 1 +FROM Items WHERE ItemTypeID = (SELECT ItemTypeID FROM ItemType WHERE TypeCode = 'FG'); + +INSERT INTO PriceListDetail (PriceListID, ItemID, UnitPrice, MinimumQuantity) +SELECT + (SELECT PriceListID FROM PriceList WHERE PriceListCode = 'PL-WHOLESALE'), + ItemID, + ListPrice * 0.85, -- 15% discount for wholesale base + 10 +FROM Items WHERE ItemTypeID = (SELECT ItemTypeID FROM ItemType WHERE TypeCode = 'FG'); + +GO + +PRINT 'Sales operations sample data inserted successfully!'; +GO diff --git a/samples/databases/futon-manufacturing/07-sales-reports.sql b/samples/databases/futon-manufacturing/07-sales-reports.sql new file mode 100644 index 0000000000..697fb6c264 --- /dev/null +++ b/samples/databases/futon-manufacturing/07-sales-reports.sql @@ -0,0 +1,905 @@ +-- ============================================= +-- Top 20 Sales Operations Reports +-- Futon Manufacturing Database +-- ============================================= + +USE FutonManufacturing; +GO + +-- ============================================= +-- REPORT 1: Sales Performance by Channel +-- ============================================= + +CREATE OR ALTER VIEW vw_Sales_ByChannel AS +SELECT + sc.ChannelCode, + sc.ChannelName, + DATEPART(YEAR, so.OrderDate) AS Year, + DATEPART(MONTH, so.OrderDate) AS Month, + DATEPART(QUARTER, so.OrderDate) AS Quarter, + COUNT(DISTINCT so.SalesOrderID) AS OrderCount, + COUNT(DISTINCT so.CustomerID) AS UniqueCustomers, + SUM(so.Subtotal) AS GrossSales, + SUM(so.DiscountAmount) AS TotalDiscounts, + SUM(so.NetAmount) AS NetSales, + AVG(so.NetAmount) AS AvgOrderValue, + SUM(CASE WHEN so.Status = 'Delivered' THEN so.NetAmount ELSE 0 END) AS DeliveredSales, + SUM(CASE WHEN so.Status IN ('Confirmed', 'InProduction', 'Shipped') THEN so.NetAmount ELSE 0 END) AS PipelineSales, + CAST(AVG(so.DiscountAmount * 100.0 / NULLIF(so.Subtotal, 0)) AS DECIMAL(5,2)) AS AvgDiscountPercent +FROM SalesOrder so +INNER JOIN SalesChannel sc ON so.SalesChannelID = sc.SalesChannelID +GROUP BY + sc.ChannelCode, + sc.ChannelName, + DATEPART(YEAR, so.OrderDate), + DATEPART(MONTH, so.OrderDate), + DATEPART(QUARTER, so.OrderDate); +GO + +-- ============================================= +-- REPORT 2: Store Performance Report +-- ============================================= + +CREATE OR ALTER VIEW vw_Sales_StorePerformance AS +SELECT + s.StoreCode, + s.StoreName, + s.City, + s.State, + sc.ChannelName, + s.Manager, + COUNT(DISTINCT so.SalesOrderID) AS TotalOrders, + COUNT(DISTINCT so.CustomerID) AS UniqueCustomers, + SUM(so.Subtotal) AS GrossSales, + SUM(so.DiscountAmount) AS TotalDiscounts, + SUM(so.NetAmount) AS NetSales, + AVG(so.NetAmount) AS AvgOrderValue, + SUM(CASE WHEN so.Status = 'Delivered' THEN 1 ELSE 0 END) AS CompletedOrders, + CAST(SUM(CASE WHEN so.Status = 'Delivered' THEN 1 ELSE 0 END) * 100.0 / + NULLIF(COUNT(so.SalesOrderID), 0) AS DECIMAL(5,2)) AS CompletionRate, + MIN(so.OrderDate) AS FirstSale, + MAX(so.OrderDate) AS LastSale, + DATEDIFF(DAY, MIN(so.OrderDate), MAX(so.OrderDate)) + 1 AS DaysActive, + SUM(so.NetAmount) / NULLIF(DATEDIFF(DAY, MIN(so.OrderDate), MAX(so.OrderDate)) + 1, 0) AS AvgDailySales +FROM Store s +LEFT JOIN SalesOrder so ON s.StoreID = so.StoreID +LEFT JOIN SalesChannel sc ON s.SalesChannelID = sc.SalesChannelID +GROUP BY + s.StoreCode, + s.StoreName, + s.City, + s.State, + sc.ChannelName, + s.Manager; +GO + +-- ============================================= +-- REPORT 3: Sales Representative Performance +-- ============================================= + +CREATE OR ALTER VIEW vw_Sales_RepPerformance AS +SELECT + sr.EmployeeCode, + sr.FirstName + ' ' + sr.LastName AS SalesRepName, + st.TerritoryName, + st.Region, + COUNT(DISTINCT so.SalesOrderID) AS TotalOrders, + COUNT(DISTINCT so.CustomerID) AS UniqueCustomers, + SUM(so.Subtotal) AS GrossSales, + SUM(so.DiscountAmount) AS TotalDiscounts, + SUM(so.NetAmount) AS NetSales, + AVG(so.NetAmount) AS AvgOrderValue, + SUM(CASE WHEN so.Status = 'Delivered' THEN so.NetAmount ELSE 0 END) AS DeliveredSales, + CAST(AVG(DATEDIFF(DAY, so.OrderDate, so.ShipDate)) AS DECIMAL(10,1)) AS AvgDaysToShip, + -- Quote performance + COUNT(DISTINCT sq.QuoteID) AS QuotesCreated, + SUM(CASE WHEN sq.Status = 'Accepted' THEN 1 ELSE 0 END) AS QuotesAccepted, + CAST(SUM(CASE WHEN sq.Status = 'Accepted' THEN 1 ELSE 0 END) * 100.0 / + NULLIF(COUNT(DISTINCT sq.QuoteID), 0) AS DECIMAL(5,2)) AS QuoteWinRate, + -- Rankings + RANK() OVER (ORDER BY SUM(so.NetAmount) DESC) AS SalesRank +FROM SalesRep sr +LEFT JOIN SalesTerritory st ON sr.TerritoryID = st.TerritoryID +LEFT JOIN SalesOrder so ON sr.SalesRepID = so.SalesRepID +LEFT JOIN SalesQuote sq ON sr.SalesRepID = sq.SalesRepID +WHERE sr.IsActive = 1 +GROUP BY + sr.EmployeeCode, + sr.FirstName, + sr.LastName, + st.TerritoryName, + st.Region; +GO + +-- ============================================= +-- REPORT 4: Customer Sales Analysis +-- ============================================= + +CREATE OR ALTER VIEW vw_Sales_CustomerAnalysis AS +WITH CustomerMetrics AS ( + SELECT + c.CustomerID, + c.CustomerCode, + c.CustomerName, + c.CustomerType, + c.City, + c.State, + sr.FirstName + ' ' + sr.LastName AS SalesRep, + st.TerritoryName, + COUNT(DISTINCT so.SalesOrderID) AS TotalOrders, + SUM(so.NetAmount) AS TotalSales, + AVG(so.NetAmount) AS AvgOrderValue, + MAX(so.OrderDate) AS LastOrderDate, + MIN(so.OrderDate) AS FirstOrderDate, + DATEDIFF(DAY, MIN(so.OrderDate), MAX(so.OrderDate)) AS CustomerLifespanDays, + SUM(CASE WHEN so.Status = 'Delivered' THEN so.NetAmount ELSE 0 END) AS DeliveredSales, + SUM(CASE WHEN so.Status IN ('Confirmed', 'InProduction') THEN so.NetAmount ELSE 0 END) AS PendingSales, + -- Returns + COUNT(DISTINCT sr2.ReturnID) AS TotalReturns, + ISNULL(SUM(sr2.RefundAmount), 0) AS TotalRefunds + FROM Customer c + LEFT JOIN SalesOrder so ON c.CustomerID = so.CustomerID + LEFT JOIN SalesRep sr ON c.SalesRepID = sr.SalesRepID + LEFT JOIN SalesTerritory st ON c.TerritoryID = st.TerritoryID + LEFT JOIN SalesReturn sr2 ON c.CustomerID = sr2.CustomerID + WHERE c.IsActive = 1 + GROUP BY + c.CustomerID, c.CustomerCode, c.CustomerName, c.CustomerType, + c.City, c.State, sr.FirstName, sr.LastName, st.TerritoryName +) +SELECT + *, + CASE + WHEN TotalOrders = 0 THEN 'No Orders' + WHEN TotalOrders = 1 THEN 'One-Time' + WHEN TotalOrders BETWEEN 2 AND 5 THEN 'Occasional' + WHEN TotalOrders BETWEEN 6 AND 10 THEN 'Regular' + ELSE 'VIP' + END AS CustomerSegment, + CAST(TotalRefunds * 100.0 / NULLIF(TotalSales, 0) AS DECIMAL(5,2)) AS ReturnRate, + DATEDIFF(DAY, LastOrderDate, GETDATE()) AS DaysSinceLastOrder, + CASE + WHEN DATEDIFF(DAY, LastOrderDate, GETDATE()) <= 30 THEN 'Active' + WHEN DATEDIFF(DAY, LastOrderDate, GETDATE()) <= 90 THEN 'Recent' + WHEN DATEDIFF(DAY, LastOrderDate, GETDATE()) <= 180 THEN 'Inactive' + ELSE 'Dormant' + END AS CustomerStatus, + TotalSales / NULLIF(CustomerLifespanDays / 30.0, 0) AS AvgMonthlyValue +FROM CustomerMetrics; +GO + +-- ============================================= +-- REPORT 5: Product Sales Performance +-- ============================================= + +CREATE OR ALTER VIEW vw_Sales_ProductPerformance AS +SELECT + i.ItemCode, + i.ItemName, + COUNT(DISTINCT sod.SalesOrderID) AS OrderCount, + SUM(sod.Quantity) AS TotalUnitsSold, + SUM(sod.NetAmount) AS TotalRevenue, + AVG(sod.UnitPrice) AS AvgSellingPrice, + i.StandardCost AS UnitCost, + AVG(sod.UnitPrice) - i.StandardCost AS AvgGrossProfitPerUnit, + SUM(sod.NetAmount - (sod.Quantity * i.StandardCost)) AS TotalGrossProfit, + CAST((AVG(sod.UnitPrice) - i.StandardCost) * 100.0 / NULLIF(AVG(sod.UnitPrice), 0) + AS DECIMAL(5,2)) AS GrossMarginPercent, + AVG(sod.DiscountPercent) AS AvgDiscountPercent, + -- By Channel + SUM(CASE WHEN sc.ChannelCode = 'RETAIL' THEN sod.Quantity ELSE 0 END) AS RetailUnits, + SUM(CASE WHEN sc.ChannelCode = 'ONLINE' THEN sod.Quantity ELSE 0 END) AS OnlineUnits, + SUM(CASE WHEN sc.ChannelCode = 'WHOLESALE' THEN sod.Quantity ELSE 0 END) AS WholesaleUnits, + -- Rankings + RANK() OVER (ORDER BY SUM(sod.Quantity) DESC) AS UnitSalesRank, + RANK() OVER (ORDER BY SUM(sod.NetAmount) DESC) AS RevenueRank, + RANK() OVER (ORDER BY SUM(sod.NetAmount - (sod.Quantity * i.StandardCost)) DESC) AS ProfitRank +FROM Items i +INNER JOIN ItemType it ON i.ItemTypeID = it.ItemTypeID +LEFT JOIN SalesOrderDetail sod ON i.ItemID = sod.ItemID +LEFT JOIN SalesOrder so ON sod.SalesOrderID = so.SalesOrderID +LEFT JOIN SalesChannel sc ON so.SalesChannelID = sc.SalesChannelID +WHERE it.TypeCode = 'FG' AND i.IsActive = 1 +GROUP BY + i.ItemCode, + i.ItemName, + i.StandardCost; +GO + +-- ============================================= +-- REPORT 6: Sales Trend Analysis +-- ============================================= + +CREATE OR ALTER VIEW vw_Sales_TrendAnalysis AS +WITH MonthlySales AS ( + SELECT + DATEPART(YEAR, OrderDate) AS Year, + DATEPART(MONTH, OrderDate) AS Month, + DATEPART(QUARTER, OrderDate) AS Quarter, + DATEFROMPARTS(DATEPART(YEAR, OrderDate), DATEPART(MONTH, OrderDate), 1) AS MonthStart, + COUNT(DISTINCT SalesOrderID) AS OrderCount, + COUNT(DISTINCT CustomerID) AS UniqueCustomers, + SUM(Subtotal) AS GrossSales, + SUM(DiscountAmount) AS Discounts, + SUM(NetAmount) AS NetSales, + AVG(NetAmount) AS AvgOrderValue + FROM SalesOrder + GROUP BY + DATEPART(YEAR, OrderDate), + DATEPART(MONTH, OrderDate), + DATEPART(QUARTER, OrderDate), + DATEFROMPARTS(DATEPART(YEAR, OrderDate), DATEPART(MONTH, OrderDate), 1) +) +SELECT + Year, + Month, + Quarter, + MonthStart, + OrderCount, + UniqueCustomers, + GrossSales, + Discounts, + NetSales, + AvgOrderValue, + -- Prior month comparison + LAG(NetSales, 1) OVER (ORDER BY Year, Month) AS PriorMonthSales, + NetSales - LAG(NetSales, 1) OVER (ORDER BY Year, Month) AS MoMChange, + CAST((NetSales - LAG(NetSales, 1) OVER (ORDER BY Year, Month)) * 100.0 / + NULLIF(LAG(NetSales, 1) OVER (ORDER BY Year, Month), 0) AS DECIMAL(5,2)) AS MoMChangePercent, + -- Prior year comparison + LAG(NetSales, 12) OVER (ORDER BY Year, Month) AS PriorYearSales, + NetSales - LAG(NetSales, 12) OVER (ORDER BY Year, Month) AS YoYChange, + CAST((NetSales - LAG(NetSales, 12) OVER (ORDER BY Year, Month)) * 100.0 / + NULLIF(LAG(NetSales, 12) OVER (ORDER BY Year, Month), 0) AS DECIMAL(5,2)) AS YoYChangePercent, + -- Moving averages + AVG(NetSales) OVER (ORDER BY Year, Month ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS ThreeMonthAvg, + AVG(NetSales) OVER (ORDER BY Year, Month ROWS BETWEEN 5 PRECEDING AND CURRENT ROW) AS SixMonthAvg +FROM MonthlySales; +GO + +-- ============================================= +-- REPORT 7: Average Order Value Analysis +-- ============================================= + +CREATE OR ALTER VIEW vw_Sales_OrderValueAnalysis AS +SELECT + sc.ChannelName, + c.CustomerType, + st.TerritoryName, + st.Region, + COUNT(DISTINCT so.SalesOrderID) AS OrderCount, + AVG(so.Subtotal) AS AvgSubtotal, + AVG(so.DiscountAmount) AS AvgDiscount, + AVG(so.NetAmount) AS AvgNetAmount, + AVG(so.TaxAmount) AS AvgTax, + AVG(so.ShippingAmount) AS AvgShipping, + MIN(so.NetAmount) AS MinOrderValue, + MAX(so.NetAmount) AS MaxOrderValue, + STDEV(so.NetAmount) AS StdDevOrderValue, + -- Order size buckets + SUM(CASE WHEN so.NetAmount < 500 THEN 1 ELSE 0 END) AS SmallOrders, + SUM(CASE WHEN so.NetAmount BETWEEN 500 AND 1999 THEN 1 ELSE 0 END) AS MediumOrders, + SUM(CASE WHEN so.NetAmount BETWEEN 2000 AND 4999 THEN 1 ELSE 0 END) AS LargeOrders, + SUM(CASE WHEN so.NetAmount >= 5000 THEN 1 ELSE 0 END) AS EnterpriseOrders +FROM SalesOrder so +INNER JOIN SalesChannel sc ON so.SalesChannelID = sc.SalesChannelID +INNER JOIN Customer c ON so.CustomerID = c.CustomerID +LEFT JOIN SalesRep sr ON so.SalesRepID = sr.SalesRepID +LEFT JOIN SalesTerritory st ON sr.TerritoryID = st.TerritoryID +GROUP BY + sc.ChannelName, + c.CustomerType, + st.TerritoryName, + st.Region; +GO + +-- ============================================= +-- REPORT 8: Sales Returns Analysis +-- ============================================= + +CREATE OR ALTER VIEW vw_Sales_ReturnsAnalysis AS +SELECT + DATEPART(YEAR, sr.ReturnDate) AS Year, + DATEPART(MONTH, sr.ReturnDate) AS Month, + rr.ReasonCode, + rr.ReasonDescription, + c.CustomerName, + c.CustomerType, + sc.ChannelName, + COUNT(DISTINCT sr.ReturnID) AS ReturnCount, + SUM(sr.RefundAmount) AS TotalRefunds, + AVG(sr.RefundAmount) AS AvgRefundAmount, + SUM(sr.RestockingFee) AS TotalRestockingFees, + -- Item details + i.ItemCode, + i.ItemName, + SUM(srd.QuantityReturned) AS UnitsReturned, + srd.Disposition, + -- Calculate return rate + COUNT(DISTINCT sr.ReturnID) * 100.0 / + NULLIF((SELECT COUNT(*) FROM SalesOrder WHERE Status = 'Delivered'), 0) AS ReturnRatePercent +FROM SalesReturn sr +INNER JOIN ReturnReason rr ON sr.ReturnReasonID = rr.ReturnReasonID +INNER JOIN Customer c ON sr.CustomerID = c.CustomerID +INNER JOIN SalesOrder so ON sr.SalesOrderID = so.SalesOrderID +INNER JOIN SalesChannel sc ON so.SalesChannelID = sc.SalesChannelID +INNER JOIN SalesReturnDetail srd ON sr.ReturnID = srd.ReturnID +INNER JOIN Items i ON srd.ItemID = i.ItemID +GROUP BY + DATEPART(YEAR, sr.ReturnDate), + DATEPART(MONTH, sr.ReturnDate), + rr.ReasonCode, + rr.ReasonDescription, + c.CustomerName, + c.CustomerType, + sc.ChannelName, + i.ItemCode, + i.ItemName, + srd.Disposition; +GO + +-- ============================================= +-- REPORT 9: Sales Quote Conversion Analysis +-- ============================================= + +CREATE OR ALTER VIEW vw_Sales_QuoteConversion AS +SELECT + sq.QuoteNumber, + sq.Status AS QuoteStatus, + c.CustomerName, + c.CustomerType, + sc.ChannelName, + sr.FirstName + ' ' + sr.LastName AS SalesRep, + st.TerritoryName, + sq.QuoteDate, + sq.ExpirationDate, + DATEDIFF(DAY, sq.QuoteDate, sq.ExpirationDate) AS DaysToExpire, + sq.TotalAmount AS QuoteAmount, + CASE + WHEN sq.Status = 'Accepted' AND sq.ConvertedToOrderID IS NOT NULL THEN 'Converted' + WHEN sq.Status = 'Accepted' AND sq.ConvertedToOrderID IS NULL THEN 'Accepted - Pending' + WHEN sq.Status = 'Declined' THEN 'Lost' + WHEN sq.Status = 'Expired' THEN 'Expired' + ELSE 'Open' + END AS ConversionStatus, + so.OrderNumber AS ConvertedOrderNumber, + so.TotalAmount AS OrderAmount, + sq.TotalAmount - ISNULL(so.TotalAmount, 0) AS ValueVariance, + DATEDIFF(DAY, sq.QuoteDate, so.OrderDate) AS DaysToConvert +FROM SalesQuote sq +INNER JOIN Customer c ON sq.CustomerID = c.CustomerID +LEFT JOIN SalesChannel sc ON sq.SalesChannelID = sc.SalesChannelID +LEFT JOIN SalesRep sr ON sq.SalesRepID = sr.SalesRepID +LEFT JOIN SalesTerritory st ON sr.TerritoryID = st.TerritoryID +LEFT JOIN SalesOrder so ON sq.ConvertedToOrderID = so.SalesOrderID; +GO + +-- ============================================= +-- REPORT 10: Discount Analysis Report +-- ============================================= + +CREATE OR ALTER VIEW vw_Sales_DiscountAnalysis AS +SELECT + DATEPART(YEAR, so.OrderDate) AS Year, + DATEPART(MONTH, so.OrderDate) AS Month, + sc.ChannelName, + c.CustomerType, + COUNT(DISTINCT so.SalesOrderID) AS OrderCount, + SUM(so.Subtotal) AS GrossSales, + SUM(so.DiscountAmount) AS TotalDiscounts, + SUM(so.NetAmount) AS NetSales, + CAST(SUM(so.DiscountAmount) * 100.0 / NULLIF(SUM(so.Subtotal), 0) AS DECIMAL(5,2)) AS DiscountPercent, + AVG(so.DiscountAmount) AS AvgDiscountPerOrder, + -- By discount level + SUM(CASE WHEN so.DiscountAmount = 0 THEN 1 ELSE 0 END) AS NoDiscountOrders, + SUM(CASE WHEN so.DiscountAmount > 0 AND so.DiscountAmount <= 100 THEN 1 ELSE 0 END) AS LowDiscountOrders, + SUM(CASE WHEN so.DiscountAmount > 100 AND so.DiscountAmount <= 500 THEN 1 ELSE 0 END) AS MediumDiscountOrders, + SUM(CASE WHEN so.DiscountAmount > 500 THEN 1 ELSE 0 END) AS HighDiscountOrders, + -- Margin impact + SUM(so.NetAmount) - SUM(sod.Quantity * i.StandardCost) AS GrossProfit, + CAST((SUM(so.NetAmount) - SUM(sod.Quantity * i.StandardCost)) * 100.0 / + NULLIF(SUM(so.NetAmount), 0) AS DECIMAL(5,2)) AS GrossMarginPercent +FROM SalesOrder so +INNER JOIN SalesChannel sc ON so.SalesChannelID = sc.SalesChannelID +INNER JOIN Customer c ON so.CustomerID = c.CustomerID +LEFT JOIN SalesOrderDetail sod ON so.SalesOrderID = sod.SalesOrderID +LEFT JOIN Items i ON sod.ItemID = i.ItemID +GROUP BY + DATEPART(YEAR, so.OrderDate), + DATEPART(MONTH, so.OrderDate), + sc.ChannelName, + c.CustomerType; +GO + +-- ============================================= +-- REPORT 11: Top Selling Products Report +-- ============================================= + +CREATE OR ALTER VIEW vw_Sales_TopProducts AS +WITH ProductSales AS ( + SELECT + i.ItemCode, + i.ItemName, + sc.ChannelName, + DATEPART(YEAR, so.OrderDate) AS Year, + DATEPART(MONTH, so.OrderDate) AS Month, + SUM(sod.Quantity) AS UnitsSold, + SUM(sod.NetAmount) AS Revenue, + SUM(sod.NetAmount - (sod.Quantity * i.StandardCost)) AS GrossProfit, + COUNT(DISTINCT so.CustomerID) AS UniqueCustomers + FROM Items i + INNER JOIN ItemType it ON i.ItemTypeID = it.ItemTypeID + INNER JOIN SalesOrderDetail sod ON i.ItemID = sod.ItemID + INNER JOIN SalesOrder so ON sod.SalesOrderID = so.SalesOrderID + INNER JOIN SalesChannel sc ON so.SalesChannelID = sc.SalesChannelID + WHERE it.TypeCode = 'FG' + GROUP BY + i.ItemCode, + i.ItemName, + sc.ChannelName, + DATEPART(YEAR, so.OrderDate), + DATEPART(MONTH, so.OrderDate) +) +SELECT + *, + RANK() OVER (PARTITION BY ChannelName, Year, Month ORDER BY UnitsSold DESC) AS UnitRank, + RANK() OVER (PARTITION BY ChannelName, Year, Month ORDER BY Revenue DESC) AS RevenueRank, + RANK() OVER (PARTITION BY ChannelName, Year, Month ORDER BY GrossProfit DESC) AS ProfitRank +FROM ProductSales; +GO + +-- ============================================= +-- REPORT 12: Sales by Territory Report +-- ============================================= + +CREATE OR ALTER VIEW vw_Sales_ByTerritory AS +SELECT + st.TerritoryCode, + st.TerritoryName, + st.Region, + COUNT(DISTINCT sr.SalesRepID) AS SalesReps, + COUNT(DISTINCT c.CustomerID) AS TotalCustomers, + COUNT(DISTINCT so.SalesOrderID) AS TotalOrders, + SUM(so.Subtotal) AS GrossSales, + SUM(so.DiscountAmount) AS Discounts, + SUM(so.NetAmount) AS NetSales, + AVG(so.NetAmount) AS AvgOrderValue, + SUM(so.NetAmount) / NULLIF(COUNT(DISTINCT sr.SalesRepID), 0) AS SalesPerRep, + SUM(so.NetAmount) / NULLIF(COUNT(DISTINCT c.CustomerID), 0) AS SalesPerCustomer, + -- Top products in territory + (SELECT TOP 1 i.ItemName + FROM SalesOrder so2 + INNER JOIN SalesOrderDetail sod ON so2.SalesOrderID = sod.SalesOrderID + INNER JOIN Items i ON sod.ItemID = i.ItemID + INNER JOIN Customer c2 ON so2.CustomerID = c2.CustomerID + WHERE c2.TerritoryID = st.TerritoryID + GROUP BY i.ItemName + ORDER BY SUM(sod.Quantity) DESC) AS TopProduct +FROM SalesTerritory st +LEFT JOIN SalesRep sr ON st.TerritoryID = sr.TerritoryID +LEFT JOIN Customer c ON st.TerritoryID = c.TerritoryID +LEFT JOIN SalesOrder so ON c.CustomerID = so.CustomerID +WHERE st.IsActive = 1 +GROUP BY + st.TerritoryCode, + st.TerritoryName, + st.Region, + st.TerritoryID; +GO + +-- ============================================= +-- REPORT 13: Channel Profitability Analysis +-- ============================================= + +CREATE OR ALTER VIEW vw_Sales_ChannelProfitability AS +WITH ChannelMetrics AS ( + SELECT + sc.ChannelCode, + sc.ChannelName, + COUNT(DISTINCT so.SalesOrderID) AS OrderCount, + SUM(sod.Quantity) AS TotalUnits, + SUM(so.Subtotal) AS GrossSales, + SUM(so.DiscountAmount) AS Discounts, + SUM(so.NetAmount) AS NetSales, + SUM(so.ShippingAmount) AS ShippingRevenue, + SUM(sod.Quantity * i.StandardCost) AS COGS, + SUM(so.NetAmount - (sod.Quantity * i.StandardCost)) AS GrossProfit, + AVG(so.NetAmount) AS AvgOrderValue + FROM SalesChannel sc + LEFT JOIN SalesOrder so ON sc.SalesChannelID = so.SalesChannelID + LEFT JOIN SalesOrderDetail sod ON so.SalesOrderID = sod.SalesOrderID + LEFT JOIN Items i ON sod.ItemID = i.ItemID + GROUP BY sc.ChannelCode, sc.ChannelName +) +SELECT + ChannelCode, + ChannelName, + OrderCount, + TotalUnits, + GrossSales, + Discounts, + NetSales, + ShippingRevenue, + COGS, + GrossProfit, + AvgOrderValue, + CAST(GrossProfit * 100.0 / NULLIF(NetSales, 0) AS DECIMAL(5,2)) AS GrossMarginPercent, + CAST(Discounts * 100.0 / NULLIF(GrossSales, 0) AS DECIMAL(5,2)) AS DiscountPercent, + GrossProfit / NULLIF(OrderCount, 0) AS ProfitPerOrder, + GrossProfit / NULLIF(TotalUnits, 0) AS ProfitPerUnit, + RANK() OVER (ORDER BY GrossProfit DESC) AS ProfitabilityRank +FROM ChannelMetrics; +GO + +-- ============================================= +-- REPORT 14: Customer Lifetime Value +-- ============================================= + +CREATE OR ALTER VIEW vw_Sales_CustomerLifetimeValue AS +WITH CustomerValue AS ( + SELECT + c.CustomerID, + c.CustomerCode, + c.CustomerName, + c.CustomerType, + sr.FirstName + ' ' + sr.LastName AS SalesRep, + MIN(so.OrderDate) AS FirstPurchaseDate, + MAX(so.OrderDate) AS LastPurchaseDate, + DATEDIFF(MONTH, MIN(so.OrderDate), MAX(so.OrderDate)) + 1 AS CustomerLifetimeMonths, + COUNT(DISTINCT so.SalesOrderID) AS TotalOrders, + SUM(so.NetAmount) AS TotalRevenue, + SUM(so.NetAmount - ISNULL(sod.Quantity * i.StandardCost, 0)) AS TotalProfit, + AVG(so.NetAmount) AS AvgOrderValue, + SUM(so.NetAmount) / NULLIF(DATEDIFF(MONTH, MIN(so.OrderDate), MAX(so.OrderDate)) + 1, 0) AS AvgMonthlyRevenue + FROM Customer c + LEFT JOIN SalesOrder so ON c.CustomerID = so.CustomerID + LEFT JOIN SalesOrderDetail sod ON so.SalesOrderID = sod.SalesOrderID + LEFT JOIN Items i ON sod.ItemID = i.ItemID + LEFT JOIN SalesRep sr ON c.SalesRepID = sr.SalesRepID + GROUP BY + c.CustomerID, c.CustomerCode, c.CustomerName, c.CustomerType, + sr.FirstName, sr.LastName +) +SELECT + *, + CASE + WHEN TotalRevenue >= 20000 THEN 'Platinum' + WHEN TotalRevenue >= 10000 THEN 'Gold' + WHEN TotalRevenue >= 5000 THEN 'Silver' + WHEN TotalRevenue >= 1000 THEN 'Bronze' + ELSE 'Standard' + END AS CustomerTier, + DATEDIFF(DAY, LastPurchaseDate, GETDATE()) AS DaysSinceLastPurchase, + CASE + WHEN DATEDIFF(DAY, LastPurchaseDate, GETDATE()) <= 30 THEN 'Highly Active' + WHEN DATEDIFF(DAY, LastPurchaseDate, GETDATE()) <= 90 THEN 'Active' + WHEN DATEDIFF(DAY, LastPurchaseDate, GETDATE()) <= 180 THEN 'At Risk' + ELSE 'Churned' + END AS ActivityStatus, + -- Projected annual value + AvgMonthlyRevenue * 12 AS ProjectedAnnualRevenue, + RANK() OVER (ORDER BY TotalRevenue DESC) AS ValueRank +FROM CustomerValue +WHERE TotalOrders > 0; +GO + +-- ============================================= +-- REPORT 15: Sales Growth Analysis +-- ============================================= + +CREATE OR ALTER VIEW vw_Sales_GrowthAnalysis AS +WITH MonthlyGrowth AS ( + SELECT + DATEPART(YEAR, OrderDate) AS Year, + DATEPART(MONTH, OrderDate) AS Month, + sc.ChannelName, + COUNT(DISTINCT SalesOrderID) AS Orders, + COUNT(DISTINCT CustomerID) AS Customers, + SUM(NetAmount) AS Revenue + FROM SalesOrder so + INNER JOIN SalesChannel sc ON so.SalesChannelID = sc.SalesChannelID + GROUP BY + DATEPART(YEAR, OrderDate), + DATEPART(MONTH, OrderDate), + sc.ChannelName +) +SELECT + Year, + Month, + ChannelName, + Orders, + Customers, + Revenue, + -- Growth metrics + LAG(Revenue) OVER (PARTITION BY ChannelName ORDER BY Year, Month) AS PriorMonthRevenue, + Revenue - LAG(Revenue) OVER (PARTITION BY ChannelName ORDER BY Year, Month) AS RevenueGrowth, + CAST((Revenue - LAG(Revenue) OVER (PARTITION BY ChannelName ORDER BY Year, Month)) * 100.0 / + NULLIF(LAG(Revenue) OVER (PARTITION BY ChannelName ORDER BY Year, Month), 0) AS DECIMAL(5,2)) AS GrowthPercent, + LAG(Customers) OVER (PARTITION BY ChannelName ORDER BY Year, Month) AS PriorMonthCustomers, + Customers - LAG(Customers) OVER (PARTITION BY ChannelName ORDER BY Year, Month) AS CustomerGrowth, + -- Cumulative + SUM(Revenue) OVER (PARTITION BY ChannelName ORDER BY Year, Month) AS CumulativeRevenue, + -- Moving average + AVG(Revenue) OVER (PARTITION BY ChannelName ORDER BY Year, Month + ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS ThreeMonthAvg +FROM MonthlyGrowth; +GO + +-- ============================================= +-- REPORT 16: Order Size Distribution +-- ============================================= + +CREATE OR ALTER VIEW vw_Sales_OrderSizeDistribution AS +WITH OrderBuckets AS ( + SELECT + so.SalesOrderID, + sc.ChannelName, + c.CustomerType, + so.NetAmount, + COUNT(DISTINCT sod.SODetailID) AS LineItems, + SUM(sod.Quantity) AS TotalUnits, + CASE + WHEN so.NetAmount < 500 THEN 'Small (< $500)' + WHEN so.NetAmount < 1500 THEN 'Medium ($500-$1,499)' + WHEN so.NetAmount < 5000 THEN 'Large ($1,500-$4,999)' + ELSE 'Enterprise (>= $5,000)' + END AS OrderSizeBucket, + CASE + WHEN COUNT(DISTINCT sod.SODetailID) = 1 THEN 'Single Item' + WHEN COUNT(DISTINCT sod.SODetailID) BETWEEN 2 AND 3 THEN 'Small Basket' + WHEN COUNT(DISTINCT sod.SODetailID) BETWEEN 4 AND 6 THEN 'Medium Basket' + ELSE 'Large Basket' + END AS BasketSize + FROM SalesOrder so + INNER JOIN SalesChannel sc ON so.SalesChannelID = sc.SalesChannelID + INNER JOIN Customer c ON so.CustomerID = c.CustomerID + LEFT JOIN SalesOrderDetail sod ON so.SalesOrderID = sod.SalesOrderID + GROUP BY + so.SalesOrderID, + sc.ChannelName, + c.CustomerType, + so.NetAmount +) +SELECT + ChannelName, + CustomerType, + OrderSizeBucket, + BasketSize, + COUNT(*) AS OrderCount, + SUM(NetAmount) AS TotalRevenue, + AVG(NetAmount) AS AvgOrderValue, + AVG(TotalUnits) AS AvgUnitsPerOrder, + AVG(LineItems) AS AvgLineItems, + CAST(COUNT(*) * 100.0 / SUM(COUNT(*)) OVER (PARTITION BY ChannelName) AS DECIMAL(5,2)) AS PercentOfChannelOrders +FROM OrderBuckets +GROUP BY + ChannelName, + CustomerType, + OrderSizeBucket, + BasketSize; +GO + +-- ============================================= +-- REPORT 17: Product Mix Analysis +-- ============================================= + +CREATE OR ALTER VIEW vw_Sales_ProductMixAnalysis AS +WITH ProductMix AS ( + SELECT + so.SalesOrderID, + so.OrderNumber, + sc.ChannelName, + c.CustomerType, + STRING_AGG(i.ItemCode, ', ') WITHIN GROUP (ORDER BY i.ItemCode) AS ProductMix, + COUNT(DISTINCT i.ItemID) AS UniqueProducts, + SUM(sod.Quantity) AS TotalUnits, + SUM(sod.NetAmount) AS OrderValue + FROM SalesOrder so + INNER JOIN SalesChannel sc ON so.SalesChannelID = sc.SalesChannelID + INNER JOIN Customer c ON so.CustomerID = c.CustomerID + INNER JOIN SalesOrderDetail sod ON so.SalesOrderID = sod.SalesOrderID + INNER JOIN Items i ON sod.ItemID = i.ItemID + GROUP BY + so.SalesOrderID, + so.OrderNumber, + sc.ChannelName, + c.CustomerType +) +SELECT + ChannelName, + CustomerType, + ProductMix, + COUNT(*) AS OrderCount, + SUM(OrderValue) AS TotalRevenue, + AVG(OrderValue) AS AvgOrderValue, + AVG(TotalUnits) AS AvgUnits, + RANK() OVER (PARTITION BY ChannelName ORDER BY COUNT(*) DESC) AS PopularityRank +FROM ProductMix +GROUP BY + ChannelName, + CustomerType, + ProductMix; +GO + +-- ============================================= +-- REPORT 18: Day of Week / Time-Based Analysis +-- ============================================= + +CREATE OR ALTER VIEW vw_Sales_TimeBasedAnalysis AS +SELECT + DATENAME(WEEKDAY, so.OrderDate) AS DayOfWeek, + DATEPART(WEEKDAY, so.OrderDate) AS DayNumber, + DATEPART(HOUR, so.CreatedDate) AS HourOfDay, + CASE + WHEN DATEPART(HOUR, so.CreatedDate) BETWEEN 6 AND 11 THEN 'Morning (6-11)' + WHEN DATEPART(HOUR, so.CreatedDate) BETWEEN 12 AND 17 THEN 'Afternoon (12-17)' + WHEN DATEPART(HOUR, so.CreatedDate) BETWEEN 18 AND 21 THEN 'Evening (18-21)' + ELSE 'Night (22-5)' + END AS TimeOfDay, + sc.ChannelName, + COUNT(DISTINCT so.SalesOrderID) AS OrderCount, + SUM(so.NetAmount) AS TotalRevenue, + AVG(so.NetAmount) AS AvgOrderValue, + COUNT(DISTINCT so.CustomerID) AS UniqueCustomers +FROM SalesOrder so +INNER JOIN SalesChannel sc ON so.SalesChannelID = sc.SalesChannelID +GROUP BY + DATENAME(WEEKDAY, so.OrderDate), + DATEPART(WEEKDAY, so.OrderDate), + DATEPART(HOUR, so.CreatedDate), + CASE + WHEN DATEPART(HOUR, so.CreatedDate) BETWEEN 6 AND 11 THEN 'Morning (6-11)' + WHEN DATEPART(HOUR, so.CreatedDate) BETWEEN 12 AND 17 THEN 'Afternoon (12-17)' + WHEN DATEPART(HOUR, so.CreatedDate) BETWEEN 18 AND 21 THEN 'Evening (18-21)' + ELSE 'Night (22-5)' + END, + sc.ChannelName; +GO + +-- ============================================= +-- REPORT 19: Sales Pipeline (Quotes to Orders) +-- ============================================= + +CREATE OR ALTER VIEW vw_Sales_Pipeline AS +WITH PipelineMetrics AS ( + SELECT + 'Quotes' AS Stage, + 1 AS StageOrder, + COUNT(*) AS Count, + SUM(TotalAmount) AS Value + FROM SalesQuote + WHERE Status NOT IN ('Expired', 'Declined') + + UNION ALL + + SELECT + 'Quotes - Accepted' AS Stage, + 2 AS StageOrder, + COUNT(*) AS Count, + SUM(TotalAmount) AS Value + FROM SalesQuote + WHERE Status = 'Accepted' + + UNION ALL + + SELECT + 'Orders - Confirmed' AS Stage, + 3 AS StageOrder, + COUNT(*) AS Count, + SUM(NetAmount) AS Value + FROM SalesOrder + WHERE Status = 'Confirmed' + + UNION ALL + + SELECT + 'Orders - In Production' AS Stage, + 4 AS StageOrder, + COUNT(*) AS Count, + SUM(NetAmount) AS Value + FROM SalesOrder + WHERE Status = 'InProduction' + + UNION ALL + + SELECT + 'Orders - Shipped' AS Stage, + 5 AS StageOrder, + COUNT(*) AS Count, + SUM(NetAmount) AS Value + FROM SalesOrder + WHERE Status = 'Shipped' + + UNION ALL + + SELECT + 'Orders - Delivered' AS Stage, + 6 AS StageOrder, + COUNT(*) AS Count, + SUM(NetAmount) AS Value + FROM SalesOrder + WHERE Status = 'Delivered' +) +SELECT + Stage, + StageOrder, + Count, + Value, + LAG(Count) OVER (ORDER BY StageOrder) AS PriorStageCount, + LAG(Value) OVER (ORDER BY StageOrder) AS PriorStageValue, + CAST(Count * 100.0 / NULLIF(LAG(Count) OVER (ORDER BY StageOrder), 0) AS DECIMAL(5,2)) AS ConversionRate, + CAST(Value * 100.0 / NULLIF(LAG(Value) OVER (ORDER BY StageOrder), 0) AS DECIMAL(5,2)) AS ValueRetentionRate +FROM PipelineMetrics; +GO + +-- ============================================= +-- REPORT 20: Customer Segmentation RFM Analysis +-- (Recency, Frequency, Monetary) +-- ============================================= + +CREATE OR ALTER VIEW vw_Sales_CustomerSegmentation AS +WITH RFMScores AS ( + SELECT + c.CustomerID, + c.CustomerCode, + c.CustomerName, + c.CustomerType, + DATEDIFF(DAY, MAX(so.OrderDate), GETDATE()) AS Recency, + COUNT(DISTINCT so.SalesOrderID) AS Frequency, + SUM(so.NetAmount) AS Monetary, + NTILE(5) OVER (ORDER BY DATEDIFF(DAY, MAX(so.OrderDate), GETDATE())) AS R_Score, + NTILE(5) OVER (ORDER BY COUNT(DISTINCT so.SalesOrderID) DESC) AS F_Score, + NTILE(5) OVER (ORDER BY SUM(so.NetAmount) DESC) AS M_Score + FROM Customer c + LEFT JOIN SalesOrder so ON c.CustomerID = so.CustomerID + WHERE so.Status = 'Delivered' + GROUP BY c.CustomerID, c.CustomerCode, c.CustomerName, c.CustomerType +) +SELECT + *, + (R_Score + F_Score + M_Score) / 3.0 AS RFM_Score, + CASE + WHEN R_Score >= 4 AND F_Score >= 4 AND M_Score >= 4 THEN 'Champions' + WHEN R_Score >= 3 AND F_Score >= 3 AND M_Score >= 3 THEN 'Loyal Customers' + WHEN R_Score >= 4 AND F_Score <= 2 THEN 'New Customers' + WHEN R_Score <= 2 AND F_Score >= 3 THEN 'At Risk' + WHEN R_Score <= 2 AND F_Score <= 2 THEN 'Lost' + WHEN M_Score >= 4 THEN 'Big Spenders' + ELSE 'Others' + END AS CustomerSegment, + CASE + WHEN R_Score >= 4 AND F_Score >= 4 AND M_Score >= 4 THEN 'Maintain relationship, offer loyalty rewards' + WHEN R_Score >= 3 AND F_Score >= 3 AND M_Score >= 3 THEN 'Upsell higher value products' + WHEN R_Score >= 4 AND F_Score <= 2 THEN 'Build relationship, increase frequency' + WHEN R_Score <= 2 AND F_Score >= 3 THEN 'Win back campaign, special offers' + WHEN R_Score <= 2 AND F_Score <= 2 THEN 'Reactivation campaign' + WHEN M_Score >= 4 THEN 'Focus on satisfaction and retention' + ELSE 'Increase engagement' + END AS RecommendedAction +FROM RFMScores; +GO + +PRINT 'All 20 sales operations reports created successfully!'; +PRINT ''; +PRINT 'Available Sales Reports:'; +PRINT '1. vw_Sales_ByChannel - Sales Performance by Channel'; +PRINT '2. vw_Sales_StorePerformance - Store Performance Report'; +PRINT '3. vw_Sales_RepPerformance - Sales Representative Performance'; +PRINT '4. vw_Sales_CustomerAnalysis - Customer Sales Analysis'; +PRINT '5. vw_Sales_ProductPerformance - Product Sales Performance'; +PRINT '6. vw_Sales_TrendAnalysis - Sales Trend Analysis'; +PRINT '7. vw_Sales_OrderValueAnalysis - Average Order Value Analysis'; +PRINT '8. vw_Sales_ReturnsAnalysis - Sales Returns Analysis'; +PRINT '9. vw_Sales_QuoteConversion - Sales Quote Conversion Analysis'; +PRINT '10. vw_Sales_DiscountAnalysis - Discount Analysis Report'; +PRINT '11. vw_Sales_TopProducts - Top Selling Products Report'; +PRINT '12. vw_Sales_ByTerritory - Sales by Territory Report'; +PRINT '13. vw_Sales_ChannelProfitability - Channel Profitability Analysis'; +PRINT '14. vw_Sales_CustomerLifetimeValue - Customer Lifetime Value'; +PRINT '15. vw_Sales_GrowthAnalysis - Sales Growth Analysis'; +PRINT '16. vw_Sales_OrderSizeDistribution - Order Size Distribution'; +PRINT '17. vw_Sales_ProductMixAnalysis - Product Mix Analysis'; +PRINT '18. vw_Sales_TimeBasedAnalysis - Day of Week / Time-Based Analysis'; +PRINT '19. vw_Sales_Pipeline - Sales Pipeline (Quotes to Orders)'; +PRINT '20. vw_Sales_CustomerSegmentation - Customer Segmentation RFM Analysis'; +GO diff --git a/samples/databases/futon-manufacturing/08-sales-sample-queries.sql b/samples/databases/futon-manufacturing/08-sales-sample-queries.sql new file mode 100644 index 0000000000..ac95016710 --- /dev/null +++ b/samples/databases/futon-manufacturing/08-sales-sample-queries.sql @@ -0,0 +1,593 @@ +-- ============================================= +-- Sample Sales Operations Queries +-- Futon Manufacturing Database +-- ============================================= + +USE FutonManufacturing; +GO + +PRINT '============================================='; +PRINT 'SAMPLE SALES OPERATIONS QUERIES'; +PRINT '============================================='; +PRINT ''; + +-- ============================================= +-- 1. SALES BY CHANNEL +-- ============================================= + +PRINT '1. Sales Performance by Channel - Current Month'; +PRINT '---------------------------------------------------------------------'; +SELECT + ChannelName, + Year, + Month, + OrderCount, + UniqueCustomers, + CAST(GrossSales AS DECIMAL(18,2)) AS GrossSales, + CAST(TotalDiscounts AS DECIMAL(18,2)) AS Discounts, + CAST(NetSales AS DECIMAL(18,2)) AS NetSales, + CAST(AvgOrderValue AS DECIMAL(18,2)) AS AvgOrderValue, + AvgDiscountPercent AS [Discount %] +FROM vw_Sales_ByChannel +WHERE Year = YEAR(GETDATE()) AND Month = MONTH(GETDATE()) +ORDER BY NetSales DESC; +GO + +PRINT ''; +PRINT '2. Channel Performance Comparison - Last 3 Months'; +PRINT '---------------------------------------------------------------------'; +SELECT + ChannelName, + SUM(OrderCount) AS TotalOrders, + SUM(UniqueCustomers) AS TotalCustomers, + CAST(SUM(NetSales) AS DECIMAL(18,2)) AS TotalSales, + CAST(AVG(AvgOrderValue) AS DECIMAL(18,2)) AS AvgOrderValue +FROM vw_Sales_ByChannel +WHERE DATEFROMPARTS(Year, Month, 1) >= DATEADD(MONTH, -3, DATEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), 1)) +GROUP BY ChannelName +ORDER BY TotalSales DESC; +GO + +-- ============================================= +-- 2. STORE PERFORMANCE +-- ============================================= + +PRINT ''; +PRINT '3. Top Performing Stores by Sales'; +PRINT '---------------------------------------------------------------------'; +SELECT + StoreCode, + StoreName, + City, + State, + Manager, + TotalOrders, + CAST(NetSales AS DECIMAL(18,2)) AS NetSales, + CAST(AvgOrderValue AS DECIMAL(18,2)) AS AvgOrderValue, + CAST(AvgDailySales AS DECIMAL(18,2)) AS AvgDailySales, + CompletionRate AS [Completion %] +FROM vw_Sales_StorePerformance +WHERE TotalOrders > 0 +ORDER BY NetSales DESC; +GO + +-- ============================================= +-- 3. SALES REP PERFORMANCE +-- ============================================= + +PRINT ''; +PRINT '4. Sales Rep Leaderboard'; +PRINT '---------------------------------------------------------------------'; +SELECT + SalesRepName, + TerritoryName, + Region, + TotalOrders, + UniqueCustomers, + CAST(NetSales AS DECIMAL(18,2)) AS NetSales, + CAST(AvgOrderValue AS DECIMAL(18,2)) AS AvgOrderValue, + QuotesCreated, + QuotesAccepted, + QuoteWinRate AS [Win Rate %], + SalesRank +FROM vw_Sales_RepPerformance +ORDER BY SalesRank; +GO + +-- ============================================= +-- 4. CUSTOMER ANALYSIS +-- ============================================= + +PRINT ''; +PRINT '5. Top 10 Customers by Total Sales'; +PRINT '---------------------------------------------------------------------'; +SELECT TOP 10 + CustomerCode, + CustomerName, + CustomerType, + City, + State, + TotalOrders, + CAST(TotalSales AS DECIMAL(18,2)) AS TotalSales, + CAST(AvgOrderValue AS DECIMAL(18,2)) AS AvgOrderValue, + CustomerSegment, + CustomerStatus, + DaysSinceLastOrder +FROM vw_Sales_CustomerAnalysis +ORDER BY TotalSales DESC; +GO + +PRINT ''; +PRINT '6. At-Risk Customers (Inactive or Dormant)'; +PRINT '---------------------------------------------------------------------'; +SELECT + CustomerName, + CustomerType, + TotalOrders, + CAST(TotalSales AS DECIMAL(18,2)) AS TotalSales, + LastOrderDate, + DaysSinceLastOrder, + CustomerStatus, + SalesRep +FROM vw_Sales_CustomerAnalysis +WHERE CustomerStatus IN ('Inactive', 'Dormant') +ORDER BY TotalSales DESC; +GO + +-- ============================================= +-- 5. PRODUCT PERFORMANCE +-- ============================================= + +PRINT ''; +PRINT '7. Top Selling Products - All Time'; +PRINT '---------------------------------------------------------------------'; +SELECT + ItemCode, + ItemName, + OrderCount, + TotalUnitsSold, + CAST(TotalRevenue AS DECIMAL(18,2)) AS Revenue, + CAST(AvgSellingPrice AS DECIMAL(18,2)) AS AvgPrice, + CAST(TotalGrossProfit AS DECIMAL(18,2)) AS GrossProfit, + GrossMarginPercent AS [Margin %], + UnitSalesRank, + RevenueRank +FROM vw_Sales_ProductPerformance +ORDER BY TotalUnitsSold DESC; +GO + +PRINT ''; +PRINT '8. Product Performance by Channel'; +PRINT '---------------------------------------------------------------------'; +SELECT + ItemName, + RetailUnits, + OnlineUnits, + WholesaleUnits, + TotalUnitsSold, + CAST(TotalRevenue AS DECIMAL(18,2)) AS Revenue +FROM vw_Sales_ProductPerformance +ORDER BY TotalUnitsSold DESC; +GO + +-- ============================================= +-- 6. SALES TRENDS +-- ============================================= + +PRINT ''; +PRINT '9. Monthly Sales Trend'; +PRINT '---------------------------------------------------------------------'; +SELECT + Year, + Month, + OrderCount, + UniqueCustomers, + CAST(NetSales AS DECIMAL(18,2)) AS NetSales, + CAST(AvgOrderValue AS DECIMAL(18,2)) AS AvgOrderValue, + CAST(PriorMonthSales AS DECIMAL(18,2)) AS PriorMonthSales, + CAST(MoMChange AS DECIMAL(18,2)) AS MoMChange, + MoMChangePercent AS [MoM %], + CAST(ThreeMonthAvg AS DECIMAL(18,2)) AS [3-Month Avg] +FROM vw_Sales_TrendAnalysis +ORDER BY Year DESC, Month DESC; +GO + +-- ============================================= +-- 7. RETURNS ANALYSIS +-- ============================================= + +PRINT ''; +PRINT '10. Sales Returns Summary by Reason'; +PRINT '---------------------------------------------------------------------'; +SELECT + ReasonDescription, + COUNT(DISTINCT ReturnID) AS ReturnCount, + CAST(SUM(TotalRefunds) AS DECIMAL(18,2)) AS TotalRefunds, + CAST(AVG(AvgRefundAmount) AS DECIMAL(18,2)) AS AvgRefundAmount, + STRING_AGG(ItemName, ', ') AS ProductsReturned +FROM vw_Sales_ReturnsAnalysis +GROUP BY ReasonDescription +ORDER BY SUM(TotalRefunds) DESC; +GO + +PRINT ''; +PRINT '11. Returns by Product'; +PRINT '---------------------------------------------------------------------'; +SELECT + ItemName, + SUM(UnitsReturned) AS TotalReturned, + CAST(SUM(TotalRefunds) AS DECIMAL(18,2)) AS RefundAmount, + STRING_AGG(DISTINCT ReasonDescription, ', ') AS ReturnReasons +FROM vw_Sales_ReturnsAnalysis +GROUP BY ItemName +ORDER BY SUM(UnitsReturned) DESC; +GO + +-- ============================================= +-- 8. QUOTE CONVERSION +-- ============================================= + +PRINT ''; +PRINT '12. Sales Quote Conversion Rates'; +PRINT '---------------------------------------------------------------------'; +SELECT + QuoteStatus, + ConversionStatus, + COUNT(*) AS QuoteCount, + CAST(AVG(QuoteAmount) AS DECIMAL(18,2)) AS AvgQuoteAmount, + CAST(AVG(DaysToConvert) AS DECIMAL(10,1)) AS AvgDaysToConvert +FROM vw_Sales_QuoteConversion +GROUP BY QuoteStatus, ConversionStatus +ORDER BY QuoteCount DESC; +GO + +PRINT ''; +PRINT '13. Open Quotes Requiring Follow-Up'; +PRINT '---------------------------------------------------------------------'; +SELECT + QuoteNumber, + CustomerName, + SalesRep, + QuoteDate, + ExpirationDate, + DATEDIFF(DAY, GETDATE(), ExpirationDate) AS DaysUntilExpiration, + CAST(QuoteAmount AS DECIMAL(18,2)) AS QuoteAmount, + QuoteStatus +FROM vw_Sales_QuoteConversion +WHERE QuoteStatus IN ('Draft', 'Sent') + AND ExpirationDate >= GETDATE() +ORDER BY ExpirationDate; +GO + +-- ============================================= +-- 9. DISCOUNT ANALYSIS +-- ============================================= + +PRINT ''; +PRINT '14. Discount Impact by Channel'; +PRINT '---------------------------------------------------------------------'; +SELECT + ChannelName, + OrderCount, + CAST(GrossSales AS DECIMAL(18,2)) AS GrossSales, + CAST(TotalDiscounts AS DECIMAL(18,2)) AS TotalDiscounts, + DiscountPercent AS [Discount %], + CAST(GrossProfit AS DECIMAL(18,2)) AS GrossProfit, + GrossMarginPercent AS [Margin %], + NoDiscountOrders, + LowDiscountOrders, + MediumDiscountOrders, + HighDiscountOrders +FROM vw_Sales_DiscountAnalysis +WHERE Year = YEAR(GETDATE()) +GROUP BY ChannelName, OrderCount, GrossSales, TotalDiscounts, DiscountPercent, + GrossProfit, GrossMarginPercent, NoDiscountOrders, LowDiscountOrders, + MediumDiscountOrders, HighDiscountOrders +ORDER BY DiscountPercent DESC; +GO + +-- ============================================= +-- 10. TOP PRODUCTS +-- ============================================= + +PRINT ''; +PRINT '15. Top 5 Products per Channel - Current Month'; +PRINT '---------------------------------------------------------------------'; +SELECT + ChannelName, + ItemName, + UnitsSold, + CAST(Revenue AS DECIMAL(18,2)) AS Revenue, + CAST(GrossProfit AS DECIMAL(18,2)) AS GrossProfit, + UnitRank +FROM vw_Sales_TopProducts +WHERE Year = YEAR(GETDATE()) + AND Month = MONTH(GETDATE()) + AND UnitRank <= 5 +ORDER BY ChannelName, UnitRank; +GO + +-- ============================================= +-- 11. TERRITORY ANALYSIS +-- ============================================= + +PRINT ''; +PRINT '16. Territory Performance Summary'; +PRINT '---------------------------------------------------------------------'; +SELECT + TerritoryName, + Region, + SalesReps, + TotalCustomers, + TotalOrders, + CAST(NetSales AS DECIMAL(18,2)) AS NetSales, + CAST(SalesPerRep AS DECIMAL(18,2)) AS SalesPerRep, + CAST(SalesPerCustomer AS DECIMAL(18,2)) AS SalesPerCustomer, + TopProduct +FROM vw_Sales_ByTerritory +ORDER BY NetSales DESC; +GO + +-- ============================================= +-- 12. CHANNEL PROFITABILITY +-- ============================================= + +PRINT ''; +PRINT '17. Channel Profitability Comparison'; +PRINT '---------------------------------------------------------------------'; +SELECT + ChannelName, + OrderCount, + TotalUnits, + CAST(GrossSales AS DECIMAL(18,2)) AS GrossSales, + CAST(Discounts AS DECIMAL(18,2)) AS Discounts, + CAST(NetSales AS DECIMAL(18,2)) AS NetSales, + CAST(COGS AS DECIMAL(18,2)) AS COGS, + CAST(GrossProfit AS DECIMAL(18,2)) AS GrossProfit, + GrossMarginPercent AS [Margin %], + CAST(ProfitPerOrder AS DECIMAL(18,2)) AS ProfitPerOrder, + ProfitabilityRank +FROM vw_Sales_ChannelProfitability +ORDER BY ProfitabilityRank; +GO + +-- ============================================= +-- 13. CUSTOMER LIFETIME VALUE +-- ============================================= + +PRINT ''; +PRINT '18. Top 10 Customers by Lifetime Value'; +PRINT '---------------------------------------------------------------------'; +SELECT TOP 10 + CustomerCode, + CustomerName, + CustomerType, + TotalOrders, + CAST(TotalRevenue AS DECIMAL(18,2)) AS TotalRevenue, + CAST(TotalProfit AS DECIMAL(18,2)) AS TotalProfit, + CustomerLifetimeMonths, + CAST(AvgMonthlyRevenue AS DECIMAL(18,2)) AS AvgMonthlyRevenue, + CustomerTier, + ActivityStatus, + ValueRank +FROM vw_Sales_CustomerLifetimeValue +ORDER BY ValueRank; +GO + +-- ============================================= +-- 14. GROWTH ANALYSIS +-- ============================================= + +PRINT ''; +PRINT '19. Sales Growth by Channel - Last 6 Months'; +PRINT '---------------------------------------------------------------------'; +SELECT + Year, + Month, + ChannelName, + Orders, + Customers, + CAST(Revenue AS DECIMAL(18,2)) AS Revenue, + CAST(PriorMonthRevenue AS DECIMAL(18,2)) AS PriorMonthRevenue, + CAST(RevenueGrowth AS DECIMAL(18,2)) AS Growth, + GrowthPercent AS [Growth %], + CAST(ThreeMonthAvg AS DECIMAL(18,2)) AS [3-Mo Avg] +FROM vw_Sales_GrowthAnalysis +WHERE DATEFROMPARTS(Year, Month, 1) >= DATEADD(MONTH, -6, DATEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), 1)) +ORDER BY Year DESC, Month DESC, ChannelName; +GO + +-- ============================================= +-- 15. ORDER SIZE DISTRIBUTION +-- ============================================= + +PRINT ''; +PRINT '20. Order Size Distribution by Channel'; +PRINT '---------------------------------------------------------------------'; +SELECT + ChannelName, + OrderSizeBucket, + OrderCount, + CAST(TotalRevenue AS DECIMAL(18,2)) AS Revenue, + CAST(AvgOrderValue AS DECIMAL(18,2)) AS AvgOrderValue, + CAST(AvgUnitsPerOrder AS DECIMAL(10,1)) AS AvgUnits, + PercentOfChannelOrders AS [% of Orders] +FROM vw_Sales_OrderSizeDistribution +GROUP BY ChannelName, OrderSizeBucket, OrderCount, TotalRevenue, + AvgOrderValue, AvgUnitsPerOrder, PercentOfChannelOrders +ORDER BY ChannelName, OrderSizeBucket; +GO + +-- ============================================= +-- 16. TIME-BASED ANALYSIS +-- ============================================= + +PRINT ''; +PRINT '21. Sales by Day of Week'; +PRINT '---------------------------------------------------------------------'; +SELECT + DayOfWeek, + SUM(OrderCount) AS TotalOrders, + CAST(SUM(TotalRevenue) AS DECIMAL(18,2)) AS TotalRevenue, + CAST(AVG(AvgOrderValue) AS DECIMAL(18,2)) AS AvgOrderValue, + SUM(UniqueCustomers) AS TotalCustomers +FROM vw_Sales_TimeBasedAnalysis +GROUP BY DayOfWeek, DayNumber +ORDER BY DayNumber; +GO + +PRINT ''; +PRINT '22. Sales by Time of Day'; +PRINT '---------------------------------------------------------------------'; +SELECT + TimeOfDay, + SUM(OrderCount) AS TotalOrders, + CAST(SUM(TotalRevenue) AS DECIMAL(18,2)) AS TotalRevenue, + CAST(AVG(AvgOrderValue) AS DECIMAL(18,2)) AS AvgOrderValue +FROM vw_Sales_TimeBasedAnalysis +GROUP BY TimeOfDay +ORDER BY TotalOrders DESC; +GO + +-- ============================================= +-- 17. SALES PIPELINE +-- ============================================= + +PRINT ''; +PRINT '23. Sales Pipeline Funnel'; +PRINT '---------------------------------------------------------------------'; +SELECT + Stage, + Count, + CAST(Value AS DECIMAL(18,2)) AS Value, + PriorStageCount, + CAST(PriorStageValue AS DECIMAL(18,2)) AS PriorStageValue, + ConversionRate AS [Conversion %], + ValueRetentionRate AS [Value Retention %] +FROM vw_Sales_Pipeline +ORDER BY StageOrder; +GO + +-- ============================================= +-- 18. CUSTOMER SEGMENTATION +-- ============================================= + +PRINT ''; +PRINT '24. Customer Segmentation - RFM Analysis'; +PRINT '---------------------------------------------------------------------'; +SELECT + CustomerSegment, + COUNT(*) AS CustomerCount, + CAST(AVG(Monetary) AS DECIMAL(18,2)) AS AvgSpend, + CAST(AVG(Frequency) AS DECIMAL(10,1)) AS AvgOrders, + CAST(AVG(Recency) AS DECIMAL(10,1)) AS AvgDaysSinceOrder, + CAST(SUM(Monetary) AS DECIMAL(18,2)) AS TotalRevenue +FROM vw_Sales_CustomerSegmentation +GROUP BY CustomerSegment +ORDER BY TotalRevenue DESC; +GO + +PRINT ''; +PRINT '25. Champions and At-Risk Customers'; +PRINT '---------------------------------------------------------------------'; +SELECT + CustomerName, + CustomerType, + Frequency AS Orders, + CAST(Monetary AS DECIMAL(18,2)) AS TotalSpend, + Recency AS DaysSinceLastOrder, + CustomerSegment, + RecommendedAction +FROM vw_Sales_CustomerSegmentation +WHERE CustomerSegment IN ('Champions', 'At Risk', 'Lost') +ORDER BY CustomerSegment, Monetary DESC; +GO + +-- ============================================= +-- 19. ADVANCED ANALYTICS +-- ============================================= + +PRINT ''; +PRINT '26. Cross-Sell Opportunities - Popular Product Combinations'; +PRINT '---------------------------------------------------------------------'; +SELECT TOP 10 + ProductMix, + OrderCount, + CAST(TotalRevenue AS DECIMAL(18,2)) AS Revenue, + ChannelName, + PopularityRank +FROM vw_Sales_ProductMixAnalysis +WHERE UniqueProducts > 1 +ORDER BY OrderCount DESC; +GO + +PRINT ''; +PRINT '27. Sales KPI Dashboard - Current Month vs Prior Month'; +PRINT '---------------------------------------------------------------------'; +WITH CurrentMonth AS ( + SELECT + SUM(OrderCount) AS Orders, + SUM(UniqueCustomers) AS Customers, + SUM(NetSales) AS Revenue + FROM vw_Sales_ByChannel + WHERE Year = YEAR(GETDATE()) AND Month = MONTH(GETDATE()) +), +PriorMonth AS ( + SELECT + SUM(OrderCount) AS Orders, + SUM(UniqueCustomers) AS Customers, + SUM(NetSales) AS Revenue + FROM vw_Sales_ByChannel + WHERE Year = YEAR(DATEADD(MONTH, -1, GETDATE())) + AND Month = MONTH(DATEADD(MONTH, -1, GETDATE())) +) +SELECT + 'Orders' AS Metric, + cm.Orders AS CurrentMonth, + pm.Orders AS PriorMonth, + cm.Orders - pm.Orders AS Change, + CAST((cm.Orders - pm.Orders) * 100.0 / NULLIF(pm.Orders, 0) AS DECIMAL(5,2)) AS [Change %] +FROM CurrentMonth cm, PriorMonth pm + +UNION ALL + +SELECT + 'Customers', + cm.Customers, + pm.Customers, + cm.Customers - pm.Customers, + CAST((cm.Customers - pm.Customers) * 100.0 / NULLIF(pm.Customers, 0) AS DECIMAL(5,2)) +FROM CurrentMonth cm, PriorMonth pm + +UNION ALL + +SELECT + 'Revenue', + CAST(cm.Revenue AS INT), + CAST(pm.Revenue AS INT), + CAST(cm.Revenue - pm.Revenue AS INT), + CAST((cm.Revenue - pm.Revenue) * 100.0 / NULLIF(pm.Revenue, 0) AS DECIMAL(5,2)) +FROM CurrentMonth cm, PriorMonth pm; +GO + +PRINT ''; +PRINT '28. Channel Performance Summary - All Time'; +PRINT '---------------------------------------------------------------------'; +SELECT + ChannelName, + SUM(OrderCount) AS TotalOrders, + SUM(UniqueCustomers) AS TotalCustomers, + CAST(SUM(NetSales) AS DECIMAL(18,2)) AS TotalRevenue, + CAST(AVG(AvgOrderValue) AS DECIMAL(18,2)) AS AvgOrderValue, + CAST(AVG(AvgDiscountPercent) AS DECIMAL(5,2)) AS [Avg Discount %] +FROM vw_Sales_ByChannel +GROUP BY ChannelName +ORDER BY TotalRevenue DESC; +GO + +PRINT ''; +PRINT '============================================='; +PRINT 'Sales operations sample queries completed!'; +PRINT 'Use these as templates for your sales analysis.'; +PRINT '============================================='; +GO diff --git a/samples/databases/futon-manufacturing/README.md b/samples/databases/futon-manufacturing/README.md index 4a5a4565e5..6e9c3b3938 100644 --- a/samples/databases/futon-manufacturing/README.md +++ b/samples/databases/futon-manufacturing/README.md @@ -13,8 +13,9 @@ This database manages the complete manufacturing lifecycle for a futon manufactu - **Production Management**: Work orders, production completions, and work center capacity tracking - **Quality Control**: Inspection tracking for incoming, in-process, and final products - **Purchasing**: Purchase orders and supplier management -- **Sales**: Customer orders and fulfillment tracking +- **Sales Operations**: Multi-channel sales (Retail, Online, Wholesale) with complete order lifecycle - **20 Manufacturing Reports**: Comprehensive reporting views for operational insights +- **20 Sales Operations Reports**: Complete sales analytics and performance metrics ## Database Structure @@ -41,6 +42,16 @@ This database manages the complete manufacturing lifecycle for a futon manufactu - `SalesOrder` / `SalesOrderDetail` - Sales - `QualityInspection` - Quality control records +#### Sales Operations Tables +- `SalesChannel` - Sales channels (Retail, Online, Wholesale) +- `Store` - Retail store locations +- `SalesTerritory` - Geographic sales territories +- `SalesRep` - Sales representatives +- `SalesReturn` / `SalesReturnDetail` - Product returns and refunds +- `SalesQuote` / `SalesQuoteDetail` - Sales quotations +- `Promotion` - Promotional campaigns +- `PriceList` / `PriceListDetail` - Channel-specific pricing + ## Product Hierarchy The database includes three levels of products: @@ -75,8 +86,20 @@ Run the SQL scripts in order: -- 3. Create manufacturing reports :r 03-manufacturing-reports.sql --- 4. (Optional) Run sample queries +-- 4. (Optional) Run manufacturing sample queries :r 04-sample-queries.sql + +-- 5. Enhance schema for sales operations +:r 05-sales-schema-enhancements.sql + +-- 6. Insert sales sample data +:r 06-sales-sample-data.sql + +-- 7. Create sales operations reports +:r 07-sales-reports.sql + +-- 8. (Optional) Run sales sample queries +:r 08-sales-sample-queries.sql ``` ## Manufacturing Reports @@ -275,6 +298,203 @@ GROUP BY Year, Month, ItemName ORDER BY Year, Month, ItemName; ``` +## Sales Operations Reports + +### 1. Sales Performance by Channel (`vw_Sales_ByChannel`) +Analyze sales across Retail, Online, and Wholesale channels with trends. + +```sql +-- Monthly sales by channel +SELECT * FROM vw_Sales_ByChannel +WHERE Year = 2024 +ORDER BY Year, Month, NetSales DESC; +``` + +### 2. Store Performance Report (`vw_Sales_StorePerformance`) +Track individual retail store performance metrics. + +```sql +-- Top performing stores +SELECT * FROM vw_Sales_StorePerformance +ORDER BY NetSales DESC; +``` + +### 3. Sales Representative Performance (`vw_Sales_RepPerformance`) +Evaluate sales rep performance, territories, and quote conversion. + +```sql +-- Sales rep leaderboard +SELECT * FROM vw_Sales_RepPerformance +ORDER BY SalesRank; +``` + +### 4. Customer Sales Analysis (`vw_Sales_CustomerAnalysis`) +Comprehensive customer metrics with segmentation and status. + +```sql +-- High-value customers +SELECT * FROM vw_Sales_CustomerAnalysis +WHERE CustomerSegment IN ('VIP', 'Regular') +ORDER BY TotalSales DESC; +``` + +### 5. Product Sales Performance (`vw_Sales_ProductPerformance`) +Product-level sales metrics by channel with profitability. + +```sql +-- Best selling products +SELECT * FROM vw_Sales_ProductPerformance +ORDER BY TotalUnitsSold DESC; +``` + +### 6. Sales Trend Analysis (`vw_Sales_TrendAnalysis`) +Month-over-month and year-over-year growth analysis. + +```sql +-- Recent trends with growth rates +SELECT * FROM vw_Sales_TrendAnalysis +ORDER BY Year DESC, Month DESC; +``` + +### 7. Average Order Value Analysis (`vw_Sales_OrderValueAnalysis`) +Order size distribution and metrics by channel and customer type. + +```sql +-- AOV by channel +SELECT ChannelName, AvgNetAmount, OrderCount +FROM vw_Sales_OrderValueAnalysis +GROUP BY ChannelName, AvgNetAmount, OrderCount; +``` + +### 8. Sales Returns Analysis (`vw_Sales_ReturnsAnalysis`) +Track returns by reason, product, and channel. + +```sql +-- Top return reasons +SELECT ReasonDescription, SUM(TotalRefunds) AS Refunds +FROM vw_Sales_ReturnsAnalysis +GROUP BY ReasonDescription +ORDER BY Refunds DESC; +``` + +### 9. Sales Quote Conversion Analysis (`vw_Sales_QuoteConversion`) +Monitor quote-to-order conversion rates and pipeline. + +```sql +-- Quote conversion rates +SELECT ConversionStatus, COUNT(*) AS Quotes, AVG(QuoteAmount) AS AvgValue +FROM vw_Sales_QuoteConversion +GROUP BY ConversionStatus; +``` + +### 10. Discount Analysis Report (`vw_Sales_DiscountAnalysis`) +Analyze discount impact on margins and profitability. + +```sql +-- Discount effectiveness by channel +SELECT * FROM vw_Sales_DiscountAnalysis +ORDER BY Year DESC, Month DESC; +``` + +### 11. Top Selling Products Report (`vw_Sales_TopProducts`) +Ranked product performance by channel and time period. + +```sql +-- Top 10 products this month +SELECT * FROM vw_Sales_TopProducts +WHERE Year = YEAR(GETDATE()) AND Month = MONTH(GETDATE()) + AND UnitRank <= 10 +ORDER BY ChannelName, UnitRank; +``` + +### 12. Sales by Territory Report (`vw_Sales_ByTerritory`) +Geographic territory performance and sales rep efficiency. + +```sql +-- Territory comparison +SELECT * FROM vw_Sales_ByTerritory +ORDER BY NetSales DESC; +``` + +### 13. Channel Profitability Analysis (`vw_Sales_ChannelProfitability`) +Full profitability analysis including COGS and margins by channel. + +```sql +-- Most profitable channels +SELECT * FROM vw_Sales_ChannelProfitability +ORDER BY GrossProfit DESC; +``` + +### 14. Customer Lifetime Value (`vw_Sales_CustomerLifetimeValue`) +Calculate CLV with customer tiers and activity status. + +```sql +-- Top customers by lifetime value +SELECT * FROM vw_Sales_CustomerLifetimeValue +WHERE CustomerTier IN ('Platinum', 'Gold') +ORDER BY TotalRevenue DESC; +``` + +### 15. Sales Growth Analysis (`vw_Sales_GrowthAnalysis`) +Track revenue and customer growth by channel over time. + +```sql +-- Recent growth trends +SELECT * FROM vw_Sales_GrowthAnalysis +WHERE Year >= YEAR(DATEADD(MONTH, -6, GETDATE())) +ORDER BY Year DESC, Month DESC; +``` + +### 16. Order Size Distribution (`vw_Sales_OrderSizeDistribution`) +Analyze order patterns and basket sizes. + +```sql +-- Order size breakdown +SELECT * FROM vw_Sales_OrderSizeDistribution +ORDER BY ChannelName, OrderSizeBucket; +``` + +### 17. Product Mix Analysis (`vw_Sales_ProductMixAnalysis`) +Identify popular product combinations and cross-sell opportunities. + +```sql +-- Most common product combinations +SELECT * FROM vw_Sales_ProductMixAnalysis +WHERE UniqueProducts > 1 +ORDER BY OrderCount DESC; +``` + +### 18. Day of Week / Time-Based Analysis (`vw_Sales_TimeBasedAnalysis`) +Understand sales patterns by day of week and time of day. + +```sql +-- Sales by day of week +SELECT DayOfWeek, SUM(OrderCount) AS Orders, SUM(TotalRevenue) AS Revenue +FROM vw_Sales_TimeBasedAnalysis +GROUP BY DayOfWeek, DayNumber +ORDER BY DayNumber; +``` + +### 19. Sales Pipeline (`vw_Sales_Pipeline`) +Track conversion rates from quotes through delivery. + +```sql +-- Pipeline funnel analysis +SELECT * FROM vw_Sales_Pipeline +ORDER BY StageOrder; +``` + +### 20. Customer Segmentation RFM Analysis (`vw_Sales_CustomerSegmentation`) +RFM (Recency, Frequency, Monetary) segmentation with actionable recommendations. + +```sql +-- Customer segments with recommended actions +SELECT CustomerSegment, COUNT(*) AS Customers, SUM(Monetary) AS TotalValue +FROM vw_Sales_CustomerSegmentation +GROUP BY CustomerSegment +ORDER BY TotalValue DESC; +``` + ## Sample Data The database includes sample data for: @@ -282,10 +502,16 @@ The database includes sample data for: - 15 Components (5 pillow types, 5 mattress types, 5 frame types) - 6 Finished futon products - 5 Suppliers with pricing -- 8 Customers +- 8 Customers with various types (Retail, Wholesale, Online) - 3 Warehouses - 5 Work centers - Initial inventory levels +- 7 Retail stores across multiple cities +- 6 Sales territories with regions +- 8 Sales representatives +- 15 Sales orders across all channels (Retail, Online, Wholesale) +- Sales returns and quotations +- Promotions and price lists by channel ## Use Cases @@ -364,4 +590,5 @@ Created as part of SQL Server Samples repository for demonstrating manufacturing ## Version History -- 1.0.0 - Initial release with complete schema, sample data, and 20 reports +- 2.0.0 - Added sales operations with 20 sales reports, multi-channel support, returns, quotes, and territories +- 1.0.0 - Initial release with complete schema, sample data, and 20 manufacturing reports