-- UK Data Services Complete Database Schema -- Version: 2.0 (With Blog Integration) -- Generated: 2025-06-08 -- -- Complete database schema including original tables and new blog functionality /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!50503 SET NAMES utf8mb4 */; /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; /*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; -- -- Current Database: `ukdataservices` -- CREATE DATABASE /*!32312 IF NOT EXISTS*/ `ukdataservices` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci */ /*!80016 DEFAULT ENCRYPTION='N' */; USE `ukdataservices`; -- Set charset and collation SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- -- ORIGINAL CORE TABLES -- -- Contact Form Submissions CREATE TABLE IF NOT EXISTS `contact_submissions` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `name` VARCHAR(100) NOT NULL, `email` VARCHAR(100) NOT NULL, `company` VARCHAR(100) DEFAULT NULL, `service` VARCHAR(50) DEFAULT NULL, `source_article_id` INT(11) DEFAULT NULL, `source_page` VARCHAR(255) DEFAULT NULL, `message` TEXT NOT NULL, `ip_address` VARCHAR(45) DEFAULT NULL, `user_agent` TEXT DEFAULT NULL, `submitted_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, `status` ENUM('new', 'contacted', 'converted', 'closed') DEFAULT 'new', `notes` TEXT DEFAULT NULL, PRIMARY KEY (`id`), INDEX `idx_email` (`email`), INDEX `idx_submitted_at` (`submitted_at`), INDEX `idx_status` (`status`), INDEX `idx_contact_source_article` (`source_article_id`), INDEX `idx_contact_source_page` (`source_page`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Quote Requests CREATE TABLE IF NOT EXISTS `quote_requests` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `company_name` VARCHAR(100) NOT NULL, `first_name` VARCHAR(50) NOT NULL, `last_name` VARCHAR(50) NOT NULL, `email` VARCHAR(100) NOT NULL, `phone` VARCHAR(20) DEFAULT NULL, `company_size` VARCHAR(20) DEFAULT NULL, `services_needed` JSON DEFAULT NULL, `project_details` TEXT DEFAULT NULL, `budget` VARCHAR(20) DEFAULT NULL, `timeline` VARCHAR(20) DEFAULT NULL, `source_article_id` INT(11) DEFAULT NULL, `source_page` VARCHAR(255) DEFAULT NULL, `ip_address` VARCHAR(45) DEFAULT NULL, `submitted_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, `status` ENUM('new', 'reviewing', 'quoted', 'accepted', 'declined') DEFAULT 'new', `quote_amount` DECIMAL(10,2) DEFAULT NULL, `notes` TEXT DEFAULT NULL, PRIMARY KEY (`id`), INDEX `idx_email` (`email`), INDEX `idx_submitted_at` (`submitted_at`), INDEX `idx_status` (`status`), INDEX `idx_quote_source_article` (`source_article_id`), INDEX `idx_quote_source_page` (`source_page`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Site Analytics (basic tracking) CREATE TABLE IF NOT EXISTS `site_analytics` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `page_url` VARCHAR(255) NOT NULL, `referrer` VARCHAR(255) DEFAULT NULL, `user_agent` TEXT DEFAULT NULL, `ip_address` VARCHAR(45) DEFAULT NULL, `session_id` VARCHAR(255) DEFAULT NULL, `visit_time` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, `page_load_time` INT DEFAULT NULL, `country` VARCHAR(2) DEFAULT NULL, `city` VARCHAR(100) DEFAULT NULL, PRIMARY KEY (`id`), INDEX `idx_page_url` (`page_url`), INDEX `idx_visit_time` (`visit_time`), INDEX `idx_session_id` (`session_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Error Logs CREATE TABLE IF NOT EXISTS `error_logs` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `error_type` VARCHAR(50) NOT NULL, `error_message` TEXT NOT NULL, `file_path` VARCHAR(255) DEFAULT NULL, `line_number` INT DEFAULT NULL, `stack_trace` TEXT DEFAULT NULL, `user_agent` TEXT DEFAULT NULL, `ip_address` VARCHAR(45) DEFAULT NULL, `occurred_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), INDEX `idx_error_type` (`error_type`), INDEX `idx_occurred_at` (`occurred_at`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Newsletter Subscriptions CREATE TABLE IF NOT EXISTS `newsletter_subscriptions` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `email` VARCHAR(100) NOT NULL UNIQUE, `name` VARCHAR(100) DEFAULT NULL, `company` VARCHAR(100) DEFAULT NULL, `interests` JSON DEFAULT NULL, `subscribed_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, `confirmed_at` TIMESTAMP NULL DEFAULT NULL, `unsubscribed_at` TIMESTAMP NULL DEFAULT NULL, `status` ENUM('pending', 'confirmed', 'unsubscribed') DEFAULT 'pending', `confirmation_token` VARCHAR(255) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `unique_email` (`email`), INDEX `idx_status` (`status`), INDEX `idx_subscribed_at` (`subscribed_at`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- FAQ Search Tracking CREATE TABLE IF NOT EXISTS `faq_searches` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `search_term` VARCHAR(255) NOT NULL, `results_found` INT DEFAULT 0, `ip_address` VARCHAR(45) DEFAULT NULL, `searched_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), INDEX `idx_search_term` (`search_term`), INDEX `idx_searched_at` (`searched_at`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- User Sessions (for analytics) CREATE TABLE IF NOT EXISTS `user_sessions` ( `session_id` VARCHAR(255) NOT NULL, `ip_address` VARCHAR(45) DEFAULT NULL, `user_agent` TEXT DEFAULT NULL, `started_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, `last_activity` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `pages_viewed` INT DEFAULT 1, `referrer` VARCHAR(255) DEFAULT NULL, `country` VARCHAR(2) DEFAULT NULL, `is_bot` BOOLEAN DEFAULT FALSE, PRIMARY KEY (`session_id`), INDEX `idx_started_at` (`started_at`), INDEX `idx_last_activity` (`last_activity`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Service Worker Cache Log CREATE TABLE IF NOT EXISTS `sw_cache_log` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `event_type` VARCHAR(50) NOT NULL, `resource_url` VARCHAR(255) DEFAULT NULL, `cache_status` VARCHAR(20) DEFAULT NULL, `response_time` INT DEFAULT NULL, `timestamp` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, `user_agent` TEXT DEFAULT NULL, PRIMARY KEY (`id`), INDEX `idx_event_type` (`event_type`), INDEX `idx_timestamp` (`timestamp`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- -- BLOG SYSTEM TABLES -- -- Blog Categories Table CREATE TABLE IF NOT EXISTS `blog_categories` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `slug` VARCHAR(100) NOT NULL UNIQUE, `name` VARCHAR(100) NOT NULL, `description` TEXT DEFAULT NULL, `meta_title` VARCHAR(160) DEFAULT NULL, `meta_description` VARCHAR(320) DEFAULT NULL, `is_active` BOOLEAN DEFAULT TRUE, `sort_order` INT DEFAULT 0, `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `unique_slug` (`slug`), INDEX `idx_is_active` (`is_active`), INDEX `idx_sort_order` (`sort_order`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Blog Articles Table CREATE TABLE IF NOT EXISTS `blog_articles` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `slug` VARCHAR(150) NOT NULL UNIQUE, `title` VARCHAR(200) NOT NULL, `subtitle` VARCHAR(300) DEFAULT NULL, `excerpt` TEXT DEFAULT NULL, `content` LONGTEXT NOT NULL, `featured_image` VARCHAR(255) DEFAULT NULL, `category_id` INT(11) NOT NULL, `author_name` VARCHAR(100) DEFAULT 'UK Data Services Team', `author_title` VARCHAR(100) DEFAULT NULL, `meta_title` VARCHAR(160) DEFAULT NULL, `meta_description` VARCHAR(320) DEFAULT NULL, `meta_keywords` VARCHAR(500) DEFAULT NULL, `reading_time_minutes` INT DEFAULT 5, `word_count` INT DEFAULT 0, `is_published` BOOLEAN DEFAULT FALSE, `is_featured` BOOLEAN DEFAULT FALSE, `published_at` TIMESTAMP NULL DEFAULT NULL, `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `unique_slug` (`slug`), FOREIGN KEY (`category_id`) REFERENCES `blog_categories`(`id`) ON DELETE CASCADE, INDEX `idx_is_published` (`is_published`), INDEX `idx_is_featured` (`is_featured`), INDEX `idx_published_at` (`published_at`), INDEX `idx_category_id` (`category_id`), FULLTEXT KEY `search_content` (`title`, `excerpt`, `content`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Blog Tags Table CREATE TABLE IF NOT EXISTS `blog_tags` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `slug` VARCHAR(100) NOT NULL UNIQUE, `name` VARCHAR(100) NOT NULL, `description` TEXT DEFAULT NULL, `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `unique_slug` (`slug`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Blog Article Tags (Many-to-Many) CREATE TABLE IF NOT EXISTS `blog_article_tags` ( `article_id` INT(11) NOT NULL, `tag_id` INT(11) NOT NULL, `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`article_id`, `tag_id`), FOREIGN KEY (`article_id`) REFERENCES `blog_articles`(`id`) ON DELETE CASCADE, FOREIGN KEY (`tag_id`) REFERENCES `blog_tags`(`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Blog Comments Table CREATE TABLE IF NOT EXISTS `blog_comments` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `article_id` INT(11) NOT NULL, `author_name` VARCHAR(100) NOT NULL, `author_email` VARCHAR(100) NOT NULL, `author_website` VARCHAR(255) DEFAULT NULL, `content` TEXT NOT NULL, `ip_address` VARCHAR(45) DEFAULT NULL, `user_agent` TEXT DEFAULT NULL, `is_approved` BOOLEAN DEFAULT FALSE, `parent_id` INT(11) DEFAULT NULL, `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), FOREIGN KEY (`article_id`) REFERENCES `blog_articles`(`id`) ON DELETE CASCADE, FOREIGN KEY (`parent_id`) REFERENCES `blog_comments`(`id`) ON DELETE CASCADE, INDEX `idx_article_id` (`article_id`), INDEX `idx_is_approved` (`is_approved`), INDEX `idx_created_at` (`created_at`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Blog Analytics Table CREATE TABLE IF NOT EXISTS `blog_analytics` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `article_id` INT(11) DEFAULT NULL, `category_id` INT(11) DEFAULT NULL, `page_type` ENUM('article', 'category', 'index', 'search') NOT NULL, `page_url` VARCHAR(255) NOT NULL, `referrer` VARCHAR(255) DEFAULT NULL, `search_term` VARCHAR(255) DEFAULT NULL, `reading_time_seconds` INT DEFAULT NULL, `scroll_percentage` INT DEFAULT NULL, `ip_address` VARCHAR(45) DEFAULT NULL, `user_agent` TEXT DEFAULT NULL, `session_id` VARCHAR(255) DEFAULT NULL, `visited_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), FOREIGN KEY (`article_id`) REFERENCES `blog_articles`(`id`) ON DELETE SET NULL, FOREIGN KEY (`category_id`) REFERENCES `blog_categories`(`id`) ON DELETE SET NULL, INDEX `idx_article_id` (`article_id`), INDEX `idx_page_type` (`page_type`), INDEX `idx_visited_at` (`visited_at`), INDEX `idx_session_id` (`session_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Blog Newsletter Subscriptions (specific to blog) CREATE TABLE IF NOT EXISTS `blog_subscriptions` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `email` VARCHAR(100) NOT NULL, `categories` JSON DEFAULT NULL, `frequency` ENUM('immediate', 'daily', 'weekly', 'monthly') DEFAULT 'weekly', `subscribed_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, `confirmed_at` TIMESTAMP NULL DEFAULT NULL, `last_sent_at` TIMESTAMP NULL DEFAULT NULL, `status` ENUM('pending', 'confirmed', 'unsubscribed') DEFAULT 'pending', `confirmation_token` VARCHAR(255) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `unique_email` (`email`), INDEX `idx_status` (`status`), INDEX `idx_frequency` (`frequency`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Add foreign keys for source tracking ALTER TABLE `contact_submissions` ADD FOREIGN KEY `fk_source_article` (`source_article_id`) REFERENCES `blog_articles`(`id`) ON DELETE SET NULL; ALTER TABLE `quote_requests` ADD FOREIGN KEY `fk_quote_source_article` (`source_article_id`) REFERENCES `blog_articles`(`id`) ON DELETE SET NULL; -- -- DEFAULT DATA -- -- Insert default blog categories INSERT IGNORE INTO `blog_categories` (`slug`, `name`, `description`, `meta_title`, `meta_description`, `sort_order`) VALUES ('web-scraping', 'Web Scraping', 'Expert guides on web scraping techniques, tools, and best practices for professional data extraction.', 'Web Scraping Articles & Guides | UK Data Services', 'Expert web scraping tutorials, techniques, and best practices from UK data professionals.', 1), ('data-analytics', 'Data Analytics', 'Business intelligence insights, data analysis methodologies, and advanced analytics techniques.', 'Data Analytics Articles & Insights | UK Data Services', 'Expert data analytics guides, business intelligence insights, and data science tutorials from UK professionals.', 2), ('business-intelligence', 'Business Intelligence', 'Strategic business intelligence solutions, automation strategies, and data-driven decision making.', 'Business Intelligence Insights | UK Data Services', 'Expert insights on business intelligence, data automation, and strategic data solutions.', 3); -- Insert default blog tags INSERT IGNORE INTO `blog_tags` (`slug`, `name`, `description`) VALUES ('uk-compliance', 'UK Compliance', 'UK-specific legal and regulatory compliance topics'), ('gdpr', 'GDPR', 'General Data Protection Regulation compliance and best practices'), ('automation', 'Automation', 'Data automation strategies and implementation'), ('roi-measurement', 'ROI Measurement', 'Return on investment calculation and measurement techniques'), ('web-scraping-tools', 'Web Scraping Tools', 'Tools and technologies for web scraping'), ('javascript', 'JavaScript', 'JavaScript-related web scraping and development topics'), ('python', 'Python', 'Python programming for data extraction and analysis'), ('competitive-intelligence', 'Competitive Intelligence', 'Competitive analysis and market intelligence'), ('data-quality', 'Data Quality', 'Data validation, cleaning, and quality assurance'), ('uk-business', 'UK Business', 'UK-specific business topics and strategies'); -- Insert current blog articles INSERT IGNORE INTO `blog_articles` (`slug`, `title`, `subtitle`, `excerpt`, `category_id`, `author_name`, `author_title`, `meta_title`, `meta_description`, `reading_time_minutes`, `is_published`, `is_featured`, `published_at`) VALUES ( 'web-scraping-compliance-uk-guide', 'Web Scraping Compliance in the UK: Legal Framework and Best Practices', 'Navigate the complex legal landscape of UK data protection laws and ensure your web scraping activities remain fully compliant.', 'Comprehensive guide to UK web scraping compliance covering GDPR, legal frameworks, and best practices for professional data extraction.', 1, 'UK Data Services Legal Team', 'Legal and Compliance Specialists', 'UK Web Scraping Compliance Guide: Legal Framework & Best Practices', 'Navigate UK web scraping laws with our comprehensive compliance guide. GDPR, legal frameworks, and best practices for professional data extraction.', 12, TRUE, TRUE, '2025-06-08 09:00:00' ), ( 'javascript-heavy-sites-scraping', 'Advanced Techniques for Scraping JavaScript-Heavy Websites', 'Master the challenges of extracting data from dynamic websites using modern browser automation and rendering techniques.', 'Learn advanced techniques for scraping modern JavaScript-heavy websites using browser automation, headless browsers, and dynamic content extraction.', 1, 'UK Data Services Technical Team', 'Web Scraping Specialists', 'Scraping JavaScript Websites: Advanced Techniques & Tools', 'Master JavaScript website scraping with advanced techniques, browser automation, and dynamic content extraction strategies.', 8, TRUE, FALSE, '2025-06-01 10:00:00' ), ( 'competitive-intelligence-roi-metrics', 'Measuring ROI from Competitive Intelligence Programmes', 'Learn how to quantify the business value of competitive intelligence initiatives and demonstrate measurable returns.', 'Comprehensive guide to measuring ROI from competitive intelligence programmes with proven frameworks, metrics, and calculation methods.', 2, 'UK Data Services Analytics Team', 'Business Intelligence Specialists', 'Measuring ROI from Competitive Intelligence: UK Business Guide', 'Learn how to quantify competitive intelligence ROI with proven frameworks, metrics, and calculation methods for UK businesses.', 15, TRUE, TRUE, '2025-06-05 09:00:00' ), ( 'data-automation-strategies-uk-businesses', 'Data Automation Strategies for UK Businesses: A Complete Implementation Guide', 'Transform your operations with intelligent automation that reduces costs by up to 40% while improving accuracy and decision-making speed.', 'Discover proven data automation strategies that UK businesses use to reduce costs by 40% and improve decision-making with complete implementation frameworks.', 3, 'UK Data Services Team', 'Business Intelligence Specialists', 'Data Automation Strategies for UK Businesses: Complete Guide', 'Discover proven data automation strategies that UK businesses use to reduce costs by 40% and improve decision-making. Complete guide with implementation frameworks.', 12, TRUE, TRUE, '2025-06-08 09:00:00' ); -- Create article-tag relationships INSERT IGNORE INTO `blog_article_tags` (`article_id`, `tag_id`) SELECT a.id, t.id FROM `blog_articles` a, `blog_tags` t WHERE (a.slug = 'web-scraping-compliance-uk-guide' AND t.slug IN ('uk-compliance', 'gdpr', 'web-scraping-tools', 'uk-business')) OR (a.slug = 'javascript-heavy-sites-scraping' AND t.slug IN ('javascript', 'web-scraping-tools', 'python')) OR (a.slug = 'competitive-intelligence-roi-metrics' AND t.slug IN ('competitive-intelligence', 'roi-measurement', 'uk-business')) OR (a.slug = 'data-automation-strategies-uk-businesses' AND t.slug IN ('automation', 'roi-measurement', 'uk-business')); -- Insert default data for testing INSERT IGNORE INTO `contact_submissions` (`name`, `email`, `company`, `service`, `message`, `status`) VALUES ('Test User', 'test@example.com', 'Test Company', 'data-cleaning', 'This is a test submission', 'new'); -- -- VIEWS FOR ANALYTICS -- -- Blog Analytics Views CREATE OR REPLACE VIEW `blog_popular_articles` AS SELECT a.id, a.slug, a.title, a.published_at, c.name as category_name, COUNT(ba.id) as total_views, COUNT(DISTINCT ba.session_id) as unique_visitors, AVG(ba.reading_time_seconds) as avg_reading_time, AVG(ba.scroll_percentage) as avg_scroll_percentage FROM blog_articles a LEFT JOIN blog_categories c ON a.category_id = c.id LEFT JOIN blog_analytics ba ON a.id = ba.article_id WHERE a.is_published = TRUE GROUP BY a.id, a.slug, a.title, a.published_at, c.name ORDER BY total_views DESC; CREATE OR REPLACE VIEW `blog_category_stats` AS SELECT c.id, c.slug, c.name, COUNT(a.id) as total_articles, COUNT(CASE WHEN a.is_published = TRUE THEN 1 END) as published_articles, COUNT(CASE WHEN a.is_featured = TRUE THEN 1 END) as featured_articles, COUNT(ba.id) as total_views, MAX(a.published_at) as latest_article_date FROM blog_categories c LEFT JOIN blog_articles a ON c.id = a.category_id LEFT JOIN blog_analytics ba ON c.id = ba.category_id GROUP BY c.id, c.slug, c.name ORDER BY c.sort_order; -- Daily Contact Stats View CREATE OR REPLACE VIEW `daily_contact_stats` AS SELECT DATE(submitted_at) as date, COUNT(*) as total_submissions, COUNT(DISTINCT email) as unique_contacts, SUM(CASE WHEN status = 'converted' THEN 1 ELSE 0 END) as conversions FROM contact_submissions WHERE submitted_at >= DATE_SUB(CURRENT_DATE, INTERVAL 30 DAY) GROUP BY DATE(submitted_at) ORDER BY date DESC; -- Popular Services View CREATE OR REPLACE VIEW `popular_services` AS SELECT service, COUNT(*) as request_count, COUNT(DISTINCT email) as unique_requesters FROM contact_submissions WHERE service IS NOT NULL AND submitted_at >= DATE_SUB(CURRENT_DATE, INTERVAL 90 DAY) GROUP BY service ORDER BY request_count DESC; -- -- STORED PROCEDURES -- -- Monthly Stats Procedure DELIMITER // CREATE PROCEDURE GetMonthlyStats(IN target_month DATE) BEGIN SELECT 'Contact Submissions' as metric, COUNT(*) as value FROM contact_submissions WHERE YEAR(submitted_at) = YEAR(target_month) AND MONTH(submitted_at) = MONTH(target_month) UNION ALL SELECT 'Quote Requests' as metric, COUNT(*) as value FROM quote_requests WHERE YEAR(submitted_at) = YEAR(target_month) AND MONTH(submitted_at) = MONTH(target_month) UNION ALL SELECT 'Page Views' as metric, COUNT(*) as value FROM site_analytics WHERE YEAR(visit_time) = YEAR(target_month) AND MONTH(visit_time) = MONTH(target_month); END // DELIMITER ; -- Blog Monthly Stats Procedure DELIMITER // CREATE PROCEDURE GetBlogMonthlyStats(IN target_month DATE) BEGIN SELECT 'Total Articles Published' as metric, COUNT(*) as value FROM blog_articles WHERE is_published = TRUE AND YEAR(published_at) = YEAR(target_month) AND MONTH(published_at) = MONTH(target_month) UNION ALL SELECT 'Total Blog Views' as metric, COUNT(*) as value FROM blog_analytics WHERE YEAR(visited_at) = YEAR(target_month) AND MONTH(visited_at) = MONTH(target_month) UNION ALL SELECT 'Unique Blog Visitors' as metric, COUNT(DISTINCT session_id) as value FROM blog_analytics WHERE YEAR(visited_at) = YEAR(target_month) AND MONTH(visited_at) = MONTH(target_month) UNION ALL SELECT 'Blog Newsletter Subscriptions' as metric, COUNT(*) as value FROM blog_subscriptions WHERE status = 'confirmed' AND YEAR(confirmed_at) = YEAR(target_month) AND MONTH(confirmed_at) = MONTH(target_month); END // DELIMITER ; SET FOREIGN_KEY_CHECKS = 1; /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; -- Dump completed on 2025-06-08 (Blog Integration Version)