Showing posts with label sql. Show all posts
Showing posts with label sql. Show all posts

January 13, 2026

Mastering Advanced SQL Interview Questions

A Practical Guide for Freshers & Experienced Engineers

SQL interviews are not about memorizing syntax — they test data thinking, edge-case handling, and real-world querying skills.

This blog covers frequently asked SQL interview problems, explained step-by-step with:

  • clear intent

  • correct SQL

  • beginner-friendly explanations

  • advanced variations for experienced candidates

You can revisit this blog anytime — it’s written for long-term learning.


1️⃣ Delete Duplicate Records While Keeping One

📌 Problem

A table contains duplicate rows. You need to delete duplicates but keep one record per group.

Assume a table:

Employees(id, email)

✅ Solution Using ROW_NUMBER() (Best Practice)

DELETE FROM Employees
WHERE id IN (
    SELECT id
    FROM (
        SELECT id,
               ROW_NUMBER() OVER (PARTITION BY email ORDER BY id) AS rn
        FROM Employees
    ) t
    WHERE rn > 1
);

🧠 Explanation

  • PARTITION BY email groups duplicates

  • ROW_NUMBER() assigns 1, 2, 3…

  • Keep rn = 1, delete the rest

💡 Interview Tip

Always preview with SELECT before DELETE.


2️⃣ Find Employees Who Worked on All Projects

Tables:

Employees(emp_id)
EmployeeProjects(emp_id, project_id)
Projects(project_id)

✅ Solution Using GROUP BY + HAVING

SELECT emp_id
FROM EmployeeProjects
GROUP BY emp_id
HAVING COUNT(DISTINCT project_id) =
       (SELECT COUNT(*) FROM Projects);

🧠 Explanation

  • Count projects per employee

  • Compare with total project count

💡 Interview Tip

This pattern = worked on all” / “matched all → remember it.


3️⃣ Customers With Most Orders but Lowest Total Spend (Last Month)

Table:

Orders(order_id, customer_id, amount, order_date)

✅ Step 1: Aggregate Last Month Data

WITH last_month_orders AS (
    SELECT customer_id,
           COUNT(*) AS order_count,
           SUM(amount) AS total_amount
    FROM Orders
    WHERE order_date >= DATE_TRUNC('month', CURRENT_DATE - INTERVAL '1 month')
      AND order_date < DATE_TRUNC('month', CURRENT_DATE)
    GROUP BY customer_id
)
SELECT *
FROM last_month_orders
ORDER BY order_count DESC, total_amount ASC;

🧠 Explanation

  • Highest orders → order_count DESC

  • Lowest spend → total_amount ASC

💡 Interview Tip

Ordering by multiple business conditions is very common.


4️⃣ Products With Sales Higher Than Average Monthly Sales

Tables:

Sales(product_id, sale_amount, sale_date)
Products(product_id, product_name)

✅ Using Subquery + JOIN

SELECT p.product_id, p.product_name
FROM Products p
JOIN (
    SELECT product_id,
           AVG(sale_amount) AS avg_sales
    FROM Sales
    GROUP BY product_id
) ps ON p.product_id = ps.product_id
WHERE ps.avg_sales >
      (SELECT AVG(sale_amount) FROM Sales);

🧠 Explanation

  • Inner query → avg per product

  • Subquery → global avg

  • Compare both

💡 Interview Tip

Interviewers love compare against average questions.


5️⃣ Students in Top 10% of Their Class (Window Functions)

Table:

Students(student_id, class_id, marks)

✅ Using PERCENT_RANK()

SELECT student_id, class_id, marks
FROM (
    SELECT student_id,
           class_id,
           marks,
           PERCENT_RANK() OVER (PARTITION BY class_id ORDER BY marks DESC) AS pr
    FROM Students
) t
WHERE pr <= 0.10;

🧠 Explanation

  • PERCENT_RANK() gives percentile

  • <= 0.10 → top 10%

💡 Interview Tip

For rank-based questions, always think window functions.


6️⃣ Suppliers With Products Cheaper Than Category Average

(Correlated Subquery + JOIN)

Tables:

Suppliers(supplier_id, name)
Products(product_id, supplier_id, category_id, price)

✅ Solution

SELECT DISTINCT s.supplier_id, s.name
FROM Suppliers s
JOIN Products p ON s.supplier_id = p.supplier_id
WHERE p.price <
      (
        SELECT AVG(p2.price)
        FROM Products p2
        WHERE p2.category_id = p.category_id
      );

🧠 Explanation

  • Subquery recalculates avg per category

  • Compares product price with category avg

💡 Interview Tip

This is a classic correlated subquery example.


7️⃣ Customers and Their Total Order Amount

(Include Customers With No Orders)

Tables:

Orders(order_id, customer_id, amount)
Customers(customer_id, name)

✅ Correct Solution Using LEFT JOIN

SELECT c.customer_id,
       c.name,
       COALESCE(SUM(o.amount), 0) AS total_order_amount
FROM Customers c
LEFT JOIN Orders o
       ON c.customer_id = o.customer_id
GROUP BY c.customer_id, c.name;

🧠 Explanation

  • LEFT JOIN keeps all customers

  • COALESCE converts NULL to 0

💡 Interview Tip

If they say include even if no records exist, think LEFT JOIN.


🧠 Key SQL Patterns to Remember

Problem TypePattern
Delete duplicatesROW_NUMBER()
Worked on all itemsGROUP BY + HAVING
Top N per groupRANK() / DENSE_RANK()
Compare with averageSubquery
Percentile / top %PERCENT_RANK()
Include missing dataLEFT JOIN

🎯 What Interviewers Really Look For

✔ Correct joins
✔ Proper grouping
✔ No missing edge cases
✔ Business logic clarity
✔ Clean, readable SQL

Not just syntax.


📌 Final Advice for Long-Term SQL Mastery

  • Always start with SELECT, then DELETE/UPDATE

  • Think in sets, not rows

  • Ask clarifying questions (> vs >=, date ranges)

  • Practice explaining why, not just how


January 21, 2025

SQL Audit Trail: Enhancing Database Accountability

 

SQL Audit Trail: Enhancing Database Accountability

In today's data-driven world, maintaining a robust audit trail for your database operations is critical for ensuring data integrity, accountability, and compliance. While MongoDB offers a dedicated Audit Trail feature, SQL databases also provide powerful mechanisms to track and log database activities. Let’s explore SQL audit trails, their implementation in Spring Boot, managing timestamps, and a comparison of their benefits with alternatives.


What is an SQL Audit Trail?

An SQL audit trail is a record of events or changes made to the database. It logs information such as:

  • Who performed the operation.

  • What changes were made.

  • When the operation occurred.

  • How the operation was performed.

These logs help organizations meet regulatory requirements, debug issues, and monitor suspicious activities.


Benefits of SQL Audit Trails

  1. Data Integrity: Track unauthorized changes and ensure data reliability.

  2. Compliance: Meet regulatory requirements such as GDPR, SOX, or HIPAA.

  3. Security: Monitor potential threats and unauthorized access.

  4. Debugging: Simplify the troubleshooting of application issues.

  5. Operational Insights: Gain visibility into database usage and trends.


Implementing SQL Audit Trail in Spring Boot

Spring Boot provides an efficient way to manage audit trails using JPA's @EntityListeners and auditing annotations. Below is an example implementation:

  1. Enable JPA Auditing:

In your Spring Boot application, enable JPA auditing by adding the @EnableJpaAuditing annotation in the main class or a configuration class:

@Configuration
@EnableJpaAuditing
public class JpaConfig {
}
  1. Create an Auditable Entity:

Use annotations like @CreatedDate and @LastModifiedDate to automatically manage created and modified timestamps. Prefer using Instant for these fields to ensure compatibility with UTC-based timestamps and make the implementation more future-proof.

import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.*;
import java.time.LocalDateTime;

@Entity
@EntityListeners(AuditingEntityListener.class)
public class AuditableEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @CreatedDate
    @Column(updatable = false, nullable = false)
    private LocalDateTime createdDate;

    @LastModifiedDate
    @Column(nullable = false)
    private Loc sLocalDateTime
  tModifiedDate;

    // Additional fields
}
  1. Customize Audit Fields:

If you want to track the user performing the operation, add fields like createdBy and modifiedBy and use a custom AuditorAware implementation. Consider using String for usernames or UUID for user IDs to ensure scalability and maintain consistency across distributed systems:

import org.springframework.data.domain.AuditorAware;
import java.util.Optional;

public class AuditorAwareImpl implements AuditorAware<String> {
    @Override
    public Optional<String> getCurrentAuditor() {
        // Return the username or ID of the currently authenticated user
        return Optional.of("admin");
    }
}
  1. Register the AuditorAware Bean:

@Configuration
public class AuditConfig {

    @Bean
    public AuditorAware<String> auditorProvider() {
        return new AuditorAwareImpl();
    }
}

Managing Created and Modified Timestamps

  1. Automatic Updates: Using JPA auditing annotations ensures that the createdDate and lastModifiedDate fields are automatically populated.

  2. Manual Updates: For custom logic, you can manually update these fields in your entity lifecycle methods (e.g., @PrePersist or @PreUpdate).

@PrePersist
protected void onCreate() {
    this.createdDate = LocalDateTime.now();
}

@PreUpdate
protected void onUpdate() {
    this.lastModifiedDate = LocalDateTime.now();
}

Comparison: SQL vs. MongoDB Audit Trails

FeatureSQL Audit TrailMongoDB Audit Trail
Ease of SetupRequires custom implementationBuilt-in feature in Enterprise Edition
FlexibilityHigh with JPA and custom queriesModerate with pre-configured options
Performance ImpactMinimal with proper indexingDepends on logging granularity
Regulatory SupportMeets most compliance needsIdeal for NoSQL use cases
ScalabilityGood for relational databasesExcellent for distributed systems

Important Considerations

  1. Performance Overhead:

    • Audit logging can slightly impact performance, especially for high-frequency operations. Use indexing and log only necessary fields to minimize overhead.

  2. Storage Requirements:

    • Maintain a separate table for audit logs to avoid bloating your main tables. Structure this table to include fields such as operation type (e.g., INSERT, UPDATE, DELETE), table name, timestamp, user performing the operation, and detailed change descriptions. This design helps in efficient querying and ensures a clear understanding of database activities.

  3. Access Control:

    • Restrict access to audit logs to authorized users only.

  4. Retention Policy:

    • Implement a retention policy to manage old audit records effectively. Use scheduled batch jobs to archive or purge outdated records periodically, or database triggers to handle data retention in real-time. This ensures optimized storage usage while maintaining relevant audit logs.


Final Thoughts

Implementing an SQL audit trail in Spring Boot is a powerful way to enhance database security, ensure accountability, and meet compliance standards. Using Instant instead of LocalDateTime for timestamps ensures timezone consistency and aligns with UTC standards, making the implementation future-proof. This choice is especially beneficial in distributed systems or applications with global users, as it eliminates ambiguity related to time zones. By leveraging JPA auditing features, you can seamlessly integrate audit trails into your application while maintaining flexibility and performance. When compared to MongoDB's built-in audit trail, SQL provides a highly customizable solution tailored to relational database needs.

For organizations aiming to strengthen their data governance, setting up an audit trail is an indispensable step. Start exploring audit implementations today to protect your data and ensure peace of mind.