Introduction

In SQL, analyzing date-based data is one of the most common requirements.
In this post, we’ll explore two practical SQL examples:

  1. Extracting the year from a date in both MySQL and SQL Server (MSSQL).
  2. Using the LAG() window function to track monthly changes in customer orders.

Both examples include sample tables, inserts, and complete queries you can run directly in your SQL environment.

🧩 Query 1 — Extract Year from a Date

When dealing with orders, invoices, or events, you’ll often need to extract just the year from a date field. SQL provides built-in functions for this purpose.

🧱 Create Table and Sample Data

CREATE TABLE orders (
    order_id INT,
    customer_name VARCHAR(50),
    order_date DATE
);

INSERT INTO orders VALUES
(1, 'Alice', '2023-05-14'),
(2, 'Bob',   '2024-02-21'),
(3, 'Carol', '2025-09-10');

✅ MySQL Query

SELECT 
    order_id,
    customer_name,
    order_date,
    EXTRACT(YEAR FROM order_date) AS order_year
FROM orders;

Alternate:

SELECT YEAR(order_date) AS order_year FROM orders;

✅ SQL Server (MSSQL) Query

SELECT 
    order_id,
    customer_name,
    order_date,
    YEAR(order_date) AS order_year
FROM orders;

🧠 Output

order_idcustomer_nameorder_dateorder_year
1Alice2023-05-142023
2Bob2024-02-212024
3Carol2025-09-102025

💡 Explanation

  • EXTRACT(YEAR FROM order_date) → Works in MySQL.
  • YEAR(order_date) → Works in both MySQL and SQL Server.
  • These functions are extremely useful for grouping or filtering data by year.

📊 Query 2 — Analyze Monthly Customer Order Trends Using LAG()

When analyzing customer data, it’s common to check whether the number of orders per month has increased or decreased compared to the previous month.
The LAG() function helps achieve this by referencing the previous row’s value in a window.

🧱 Create Table and Insert Data

CREATE TABLE orders (
    order_id INT,
    customer_id INT,
    order_date DATE
);

INSERT INTO orders VALUES
(1, 101, '2024-01-10'),
(2, 101, '2024-01-25'),
(3, 101, '2024-02-15'),
(4, 101, '2024-03-10'),
(5, 102, '2024-01-12'),
(6, 102, '2024-03-08'),
(7, 103, '2024-02-20');

✅ MySQL Query

WITH monthly_counts AS (
  SELECT 
      customer_id,
      DATE_FORMAT(order_date, '%Y-%m-01') AS month_start,
      COUNT(*) AS cnt
  FROM orders
  GROUP BY customer_id, month_start
),
increase_check AS (
  SELECT 
      customer_id,
      month_start,
      cnt,
      LAG(cnt) OVER (PARTITION BY customer_id ORDER BY month_start) AS prev_cnt
  FROM monthly_counts
)
SELECT 
    customer_id,
    month_start,
    cnt,
    prev_cnt,
    cnt - COALESCE(prev_cnt, 0) AS change_in_orders
FROM increase_check
ORDER BY customer_id, month_start;

✅ SQL Server (MSSQL) Query

WITH monthly_counts AS (
  SELECT 
      customer_id,
      DATEADD(MONTH, DATEDIFF(MONTH, 0, order_date), 0) AS month_start,
      COUNT(*) AS cnt
  FROM orders
  GROUP BY customer_id, DATEADD(MONTH, DATEDIFF(MONTH, 0, order_date), 0)
),
increase_check AS (
  SELECT 
      customer_id,
      month_start,
      cnt,
      LAG(cnt) OVER (PARTITION BY customer_id ORDER BY month_start) AS prev_cnt
  FROM monthly_counts
)
SELECT 
    customer_id,
    month_start,
    cnt,
    prev_cnt,
    cnt - COALESCE(prev_cnt, 0) AS change_in_orders
FROM increase_check
ORDER BY customer_id, month_start;

🧠 Output

customer_idmonth_startcntprev_cntchange_in_orders
1012024-01-012NULL2
1012024-02-0112-1
1012024-03-01110
1022024-01-011NULL1
1022024-03-01110
1032024-02-011NULL1

💡 Explanation

  • LAG(cnt) fetches the previous month’s order count for each customer.
  • COALESCE(prev_cnt, 0) replaces NULL with 0 for the first month.
  • cnt - prev_cnt calculates the change in order count.
  • The result shows how a customer’s activity evolved month over month.

🎯 Summary

ConceptFunctionUse Case
Extract yearEXTRACT(YEAR) / YEAR()Get the year from a date
Monthly trendLAG()Compare current and previous months
GroupingGROUP BYAggregate monthly counts
Handling nullsCOALESCE()Replace missing previous values

🚀 Key Takeaways

  • YEAR() works across multiple databases and is simple for reporting.
  • LAG() is one of the most powerful window functions for time-based analytics.
  • Combining these techniques helps you uncover yearly and monthly trends in data efficiently.

SQL Query to Find Employees Who Achieved 80% or More of Their Target

Introduction

In business scenarios, it’s common to measure performance based on target vs. actual numbers.
For example, sales teams often have a monthly sales target, and you might want to find out who achieved at least 80% of that target.

In this article, we’ll build a SQL example step-by-step to identify such employees.

🧱 Create Table and Insert Data

Let’s start with a simple dataset.

CREATE TABLE employee_sales (
    emp_id INT,
    emp_name VARCHAR(50),
    target_amount DECIMAL(10,2),
    achieved_amount DECIMAL(10,2)
);

INSERT INTO employee_sales VALUES
(1, 'Alice', 10000, 9500),
(2, 'Bob',   12000, 8000),
(3, 'Carol', 15000, 10000),
(4, 'David', 20000, 16000),
(5, 'Emma',  18000, 13000);

✅ SQL Query — Employees Who Achieved at Least 80% of Their Target

💡 Using CASE WHEN and Simple Arithmetic

SELECT 
    emp_id,
    emp_name,
    target_amount,
    achieved_amount,
    ROUND((achieved_amount / target_amount) * 100, 2) AS achievement_percent,
    CASE 
        WHEN (achieved_amount / target_amount) >= 0.8 THEN 'Achieved 80% or More'
        ELSE 'Below 80%'
    END AS performance_status
FROM employee_sales;

🧠 Output

emp_idemp_nametarget_amountachieved_amountachievement_percentperformance_status
1Alice10000950095.00Achieved 80% or More
2Bob12000800066.67Below 80%
3Carol150001000066.67Below 80%
4David200001600080.00Achieved 80% or More
5Emma180001300072.22Below 80%

🧩 Explanation

ClausePurpose
ROUND((achieved_amount / target_amount) * 100, 2)Calculates achievement % rounded to two decimals
CASE WHEN ... THEN ... ELSE ... ENDCategorizes each employee’s performance
>= 0.8Checks if 80% target is met or exceeded

This query helps you instantly see who’s performing well and who needs improvement.

🧮 Optional — Filter Only High Performers

If you want to list only those who achieved at least 80%, add a WHERE clause:

SELECT 
    emp_id,
    emp_name,
    target_amount,
    achieved_amount,
    ROUND((achieved_amount / target_amount) * 100, 2) AS achievement_percent
FROM employee_sales
WHERE (achieved_amount / target_amount) >= 0.8;

🧠 Filtered Output

emp_idemp_nametarget_amountachieved_amountachievement_percent
1Alice10000950095.00
4David200001600080.00

🎯 Summary

ConceptFunctionDescription
Percentage Calculation(achieved / target) * 100Computes performance percentage
CASE WHENConditional logicClassifies employees
ROUND()Rounds decimalsKeeps result clean
WHEREFilter conditionShows only 80% achievers

🚀 Key Takeaways

  • Use simple math and CASE WHEN for performance analysis.
  • Works on all major SQL engines — MySQL, PostgreSQL, SQL Server, and Oracle.
  • Can be easily extended for monthly or team-wise analysis.

Calculating last 3 months, summing sales vs target, and comparing percentages

Here’s your single combined SQL query that calculates employees who achieved ≥ 80% of their total target over the last 3 months, assuming month is stored in YYYY-MM format. (Databricks SQL)

Final Single Query (MySQL / Databricks SQL Compatible)

Table data

CREATE TABLE sales (
    sale_id INT,
    empid INT,
    amount DECIMAL(10,2),
    date DATE
);

CREATE TABLE target (
    empid INT,
    month STRING,
    tgt_amount DECIMAL(10,2)
);

INSERT INTO sales (sale_id, empid, amount, date) VALUES
(1, 101, 1200.00, '2025-08-10'),
(2, 101, 1500.00, '2025-09-05'),
(3, 101, 1000.00, '2025-10-01'),
(4, 102, 800.00,  '2025-08-12'),
(5, 102, 700.00,  '2025-09-07'),
(6, 102, 1000.00, '2025-10-03'),
(7, 103, 500.00,  '2025-08-10'),
(8, 103, 400.00,  '2025-09-10'),
(9, 103, 300.00,  '2025-10-01');

INSERT INTO target (empid, month, tgt_amount) VALUES
(101, '2025-08', 3000.00),
(101, '2025-09', 3200.00),
(101, '2025-10', 3500.00),
(102, '2025-08', 2000.00),
(102, '2025-09', 2500.00),
(102, '2025-10', 2700.00),
(103, '2025-08', 1000.00),
(103, '2025-09', 1200.00),
(103, '2025-10', 1300.00);
WITH last_3_months AS (
    SELECT DISTINCT month
    FROM target
    ORDER BY month DESC
    LIMIT 3
),
emp_sales AS (
    SELECT 
        s.empid, 
        SUM(s.amount) AS total_sales
    FROM sales s
    JOIN last_3_months l3 
      ON DATE_FORMAT(s.date, 'yyyy-MM') = l3.month
    GROUP BY s.empid
),
emp_targets AS (
    SELECT 
        t.empid, 
        SUM(t.tgt_amount) AS total_target
    FROM target t
    JOIN last_3_months l3 
      ON t.month = l3.month
    GROUP BY t.empid
)
SELECT 
    s.empid,
    s.total_sales,
    t.total_target,
    ROUND((s.total_sales / t.total_target) * 100, 2) AS achievement_percent
FROM emp_sales s
JOIN emp_targets t 
  ON s.empid = t.empid
WHERE s.total_sales >= 0.8 * t.total_target
ORDER BY achievement_percent DESC;

💡 Explanation

StepDescription
last_3_monthsFinds the latest 3 distinct months from the target table.
emp_salesSums employee sales for those 3 months.
emp_targetsSums targets for those same 3 months.
Final SELECTJoins the two results and filters employees who met ≥ 80% of the target.

🧪 Example Data

Table: target

empidmonthtgt_amount
1012025-081000
1012025-091200
1012025-10800
1022025-081500
1022025-091300
1022025-101700

Table: sales

empiddateamount
1012025-08-15900
1012025-09-121100
1012025-10-05700
1022025-08-201600
1022025-09-101400
1022025-10-221900

✅ Output

empidtotal_salestotal_targetachievement_percent
10249004500108.89
1012700300090.00

Both employees are ≥ 80% achievers 🎯