Thursday, June 11, 2026

Implementing Oracle Database Security: VPD, Data Redaction, Database Vault, and TDE End-to-End

Implementing Oracle Database Security: VPD, Data Redaction, Database Vault, and TDE End-to-End


VPD (Virtual Private Database / Row-Level Security)

What it is: Oracle security feature implemented through the DBMS_RLS package for Fine-Grained Access Control (FGAC).

Description:
VPD is Oracle's Fine-Grained Access Control mechanism that dynamically restricts row visibility by attaching security policies to database objects. Oracle automatically appends policy predicates to SQL statements during parse time, ensuring users only access authorized rows without requiring application code changes.

Technical Key Points
Implemented using DBMS_RLS
Policy metadata stored in DBA_POLICIES
Policy function executes during SQL parse phase
Predicate dynamically appended to SQL statement
Query rewrite occurs transparently to application
Supports SELECT, INSERT, UPDATE, DELETE
Can use Application Context (DBMS_SESSION, SYS_CONTEXT)
Supports Static, Dynamic, Shared Context-Sensitive policies
Predicate becomes part of optimizer execution plan
Index design must consider VPD predicates
Policy evaluation introduces parse-time overhead
UPDATE_CHECK=>TRUE validates DML against policy rules
Users with EXEMPT ACCESS POLICY bypass VPD
Enforcement occurs inside kernel, not application layer
Works across SQL*Plus, JDBC, ODBC, EBS, APEX and custom applications
Commonly used for tenant isolation and data segregation


Data Redaction (Column-Level Masking)

What it is: Oracle Advanced Security feature implemented through the DBMS_REDACT package for runtime column masking.

Description:
Data Redaction is a runtime data protection feature that masks sensitive column values before they are returned to the client. The original data remains unchanged in the database, while different users can receive different representations of the same data based on security policies.

Technical Key Points
Implemented using DBMS_REDACT
Metadata stored in REDACTION_POLICIES
Runtime protection mechanism
Original data remains unchanged in database blocks
Redaction applied after row retrieval and before result delivery
Supports Full, Partial, Random and Regex redaction
Policy expressions evaluated per session
No modification to underlying table data
Transparent to applications
Can protect PII, PCI and PHI data
Introduces CPU overhead proportional to rows returned
Does not protect datafiles, backups, redo or undo
Does not prevent direct object access
Primarily a presentation-layer security feature
Often used for PCI-DSS and privacy compliance


Database Vault

What it is: Oracle Database Security Option that uses Realms, Rule Sets, Factors, and Command Rules to control privileged-user access.

Description:
Database Vault is Oracle's privileged-access security framework that enforces separation of duties and restricts access to sensitive data even for highly privileged users such as DBAs and SYS accounts. It provides protection against insider threats and unauthorized administrative access.

Technical Key Points
Uses Realms, Rule Sets, Factors, Command Rules
Security metadata stored in DVSYS schema
Enforces separation of duties
Restricts SYS and powerful administrative accounts
Realm protection overrides traditional object privileges
Protects application schemas from privileged access
Prevents insider-threat data exposure
Controls DDL and administrative operations
Supports Secure Application Roles
Integrates with Unified Auditing
Supports conditional access decisions
Frequently used for SOX, PCI-DSS, HIPAA compliance
Does not encrypt data
Does not provide row filtering
Operates above privilege management layer

Transparent Data Encryption (TDE)

What it is: Oracle encryption framework managed through Wallet/Keystore and ADMINISTER KEY MANAGEMENT commands.

Description:
Transparent Data Encryption (TDE) protects sensitive information by encrypting data at rest within Oracle datafiles, tablespaces, backups, and storage media. Encryption and decryption occur transparently within the database engine, requiring no application modifications.

Technical Key Points
Encrypts data at rest
Uses Oracle Wallet / Keystore
Managed through ADMINISTER KEY MANAGEMENT
Supports Tablespace TDE and Column TDE
Encryption performed below SQL layer
Applications require no code changes
Encryption keys stored outside database objects
Uses key hierarchy architecture
Master Encryption Key protects Data Encryption Keys
Protects datafiles, backups and exported storage
Integrates with RMAN and Data Guard
Supports online key rotation
Supports HSM integration
Decryption occurs transparently during block access
Does not restrict authorized database access
Does not replace access control mechanisms

VPD is implemented through the DBMS_RLS package, Data Redaction through the DBMS_REDACT package, Database Vault through DVSYS-managed security components such as Realms and Rule Sets, and TDE through Oracle's keystore and key-management framework using ADMINISTER KEY MANAGEMENT commands.

Friday, May 15, 2026

What is a List in Python?

What is a List in Python?

A list is a container that holds multiple items in a single variable, in a specific order.

How to Create a Lists:

# Empty list
my_list = []

# List of numbers
numbers = [1, 2, 3, 4, 5]

# List of strings
names = ["Alice", "Bob", "Charlie"]

# Mixed list (different data types)
mixed = [1, "hello", 3.14, True]

# List inside a list (nested)
nested = [[1, 2], [3, 4], [5, 6]]

Accessing Items — Indexing

fruits = ["apple", "banana", "mango", "orange"]

#index 0 1 2 3

print(fruits[0]) # apple ← first item
print(fruits[2]) # mango ← third item
print(fruits[-1]) # orange ← last item (negative index)
print(fruits[-2]) # mango ← second from last

Slicing a List

fruits = ["apple", "banana", "mango", "orange", "grape"]

print(fruits[1:3]) # ["banana", "mango"] ← index 1 to 2
print(fruits[:3]) # ["apple","banana","mango"] ← start to index 2
print(fruits[2:]) # ["mango","orange","grape"] ← index 2 to end
print(fruits[::2]) # ["apple","mango","grape"] ← every 2nd item

Most Used List Methods

fruits = ["apple", "banana", "mango"]

# ADD items

fruits.append("orange") # adds to END → ["apple","banana","mango","orange"]
fruits.insert(1, "grape") # adds at index 1 → ["apple","grape","banana"...]

# REMOVE items

fruits.remove("banana") # removes by VALUE
fruits.pop() # removes LAST item
fruits.pop(0) # removes item at index 0

# FIND items

print(len(fruits)) # total count of items
print(fruits.index("mango")) # finds index of "mango"
print("apple" in fruits) # True/False — does it exist?

# SORT items

fruits.sort() # sorts A→Z or small→big
fruits.sort(reverse=True) # sorts Z→A or big→small
fruits.reverse() # reverses the order

# COPY & CLEAR

copy = fruits.copy() # makes a copy of the list
fruits.clear() # empties the entire list

Looping Through a List

fruits = ["apple", "banana", "mango"]

# Basic loop
for fruit in fruits:
print(fruit)

# apple
# banana
# mango

# Loop with index

for i, fruit in enumerate(fruits):
print(i, fruit)

# 0 apple
# 1 banana
# 2 mango

# creating a simple list in python

groceries = ["Apple", "Banana", "Pineapple", "Cherry"]
print(groceries)

# Accessing elements

groceries = ["milk", "noodles", "bread"]
print(groceries[2])
print(groceries[-1])

# Modifying a list:

my_list = ["apple", "banana", "cherry", "pineapple"]
print(my_list)

my_list[0] = "strawberry"
print(my_list)

# Adding elements:

my_list = ["apple", "banana", "cherry"]
my_list.append("grapes") # add grapes
print(my_list)

# Insert elements:

my_list = ["apple", "banana", "cherry", "kiwi"]
print(my_list)
my_list.insert(1, "raspberry") # insert raspberry
print(my_list)

# Removing elements (using 3 methods)

1)

my_list = ["apple", "banana", "berry", "cherry"]
print(my_list)
my_list.remove ("apple") # remove apple
print(my_list)

2)

my_list = ["apple", "banana", "berry", "cherry"]
print(my_list)
my_list.pop() # it will remove the last value "cherry"
print(my_list)

3)

my_list = ["apple", "banana", "berry", "cherry"]
print(my_list)
del my_list[1]
print(my_list)

# Length and looping:

my_list = ["apple", "banana", "berry", "cherry"]
print(my_list)
print(len(my_list)
for item in my_list
print(item)

# List slicing:

my_list = ["apple", "banana", "berry", "cherry"]
print(my_list)
print(my_list[1:3])

# Sorting and Reversing:

num = [2,4,6,3,0,11,19,22,35]
num.sort()
print(num)
rum.reverse()
print(num)

What is a Function in Python?

What is a Function in Python?

A function is a reusable block of code that runs only when you call it.

Basic Syntax

# DEFINING a function
def function_name(parameters):
# code block
return result
# CALLING a function
function_name(arguments)

Simplest Example

# Define once

def say_hello():
print("Hello, World!")

# Call anytime, anywhere
say_hello() # Hello, World!
say_hello() # Hello, World!
say_hello() # Hello, World!

Functions with Parameters (Inputs)

# One parameter

def greet(name):
print("Hello", name)

greet("Alice") # Hello Alice
greet("Bob") # Hello Bob

# Two parameters

def add(a, b):
print(a + b)
add(3, 5) # 8
add(10, 20) # 30

4 Types of Functions:

1️ No Input, No Output
2 Input, No Output
3 No Input, With Output
4 Input AND Output

1️ No Input, No Output

def say_hello():
print("Hello!")
say_hello()

2 Input, No Output

def greet(name):
print("Hello", name)
greet("Alice")

3 No Input, With Output

def get_pi():
return 3.14159
pi = get_pi()
print(pi) # 3.14159

4 Input AND Output

def multiply(a, b):
return a * b
result = multiply(4, 5)
print(result) # 20

# Why we use functions?

To avoid repeating the same code again and again.

# Creating and calling a function

def text():
print("Hello Welcome to python Functions")
text()
text()

a = 3
b = 5
multiplication = a*b
print(multiplication)

a = 11
b = 15
multiplication = a*b
print(multiplication)

a = 20
b = 35

multiplication = a*b
print(multiplication)'''

# funtion with parameters

def multiplication(a, b):
print(a * b)
multiplication(6, 7)
multiplication(55, 60)'''

def addition(q, r):
print(q + r)
addition(20, 35)
addition(3500, 3223)
addition(25,45)'

def greet_user(name):
print(f"Hello {name} Glad To Meet You!")
greet_user("Qader")
greet_user("Lubna")
greet_user("Shoaib")
greet_user("Rumaysa")'''

#creating and calling a function (without parameters)

def text():
print("Hello Qader Welcome To Python Funtions!")
text()

#creating and calling a function (with parameters)

def multiplication(a,b):
print(a * b)
multiplication(5, 9) # multiplication

#creating and calling a function (with parameters)

def addition(a,b):
print(a + b)
addition(15, 15) #addition

#creating and calling a function (with parameters)

def division(a,b):
print(a / b)
division(20, 5) #division

#creating and calling a function (with parameters)

def substraction(a,b):
print(a - b)
substraction(35, 30) # substraction

def greet_user(name):
print(f"Hello{name} Glad to Meet You!")
greet_user("Mohammed Qadar")
greet_user("MohammedQadar")
greet_user("MQadar")
greet_user("QadarM")

-Return statement in Functions:

def add(a,b):
return a + b
result=add(5,5)
print("sum ", result)

-Default parameters in function?

Syntax:

def welcome(name= "Guest"):
print(f"welcome, {name}!")
welcome()
welcome("Qader")

Example:

def welcome(name= "khadar"):
print(f"welcome {name} great to see you!")
welcome()
welcome("qader")

# Billing system example:

def calculate_total(price, tax=0.05):
total= price + (price * tax)
return total
print(calculate_total(100))
print(calculate_total(100, 0.08))

# Keywords and Arguments in Functions?

Syntax:

def student_info(name, age):
print(f"name: {name}, age: {age}")
student_info(age=39, name="Mohammed")

# ATM System Project

def check_balance(balance):
print(f"Your current balance is rupees {balance}")

def withdraw(balance, amount):
if amount > balance:
print("Insufficient balance")
return balance
else:
balance = balance - amount
print(f"Withdraw successful & new balance: rupees {balance}")
return balance

def deposit(balance, amount):
balance = balance + amount
print(f"Deposit successful and new balance is: rupees {balance}")
return balance

def atm():
balance = 10000
print("Welcome to the ATM")

while True:
print("\nChoose option:")
print("1. Check balance")
print("2. Withdraw money")
print("3. Deposit money")
print("4. Exit")
choice = input("Enter your choice (1-4): ")
if choice == "1":
check_balance(balance)
elif choice == "2":
amount = float(input("Enter amount to withdraw: Rupees "))
balance = withdraw(balance, amount)
elif choice == "3":
amount = float(input("Enter amount to deposit: Rupees "))
balance = deposit(balance, amount)
elif choice == "4":
print("Exit, Goodbye")
break
else:
print("Invalid choice")
atm()

# Mini project on calculator:

def add(x, y):
return x + y
def subtraction(x, y):
return x - y
def multiply(x, y):
return x * y
def divide(x, y):
if y == 0:
return "Cannot divide zero"
return x / y
print("Addition:", add(3, 6))
print("Subtraction:", subtraction(8, 5))
print("Multiplication:", multiply(11, 3))
print("Division:", divide(10, 5))




Thursday, February 26, 2026

AWS Global Infrastructure: Ensuring Availability, Compliance, and Low Latency Across the World

AWS Global Infrastructure: Ensuring Availability, Compliance, and Low Latency Across the World


What is AWS global infrastructure.

AWS global infrastructure consists of multiple geographically isolated Regions. Each Region contains multiple Availability Zones for high availability. For performance optimization, AWS uses Edge Locations and Regional Edge Caches. For ultra-low latency workloads, AWS provides Local Zones and Wavelength Zones. For hybrid deployments, AWS offers Outposts. This layered infrastructure ensures scalability, fault isolation, low latency, and global reach.

AWS Regions

A Region is a geographically distinct area with its own infrastructure.
Each Region contains multiple Availability Zones for redundancy.
Regions are isolated from each other to protect against broad failures.
We choose Regions based on latency, compliance, and data residency needs.
Regions enable multi-Region disaster recovery strategies.
New Regions continue to be announced globally (e.g., Chile, Taiwan).
Regional services vary — not all AWS services launch in every Region.
Regions represent the highest level of AWS infrastructure abstraction.

AWS Availability Zones

An AZ is one or more physically separate data centers within a Region.
AZs are isolated from failures in other AZs.
They are connected by high-speed, low-latency networks.
Applications deployed across AZs are resilient to failures.
Most Regions now have at least three AZs.
Services like RDS Multi-AZ provide automatic failover between AZs.
AZs help ensure high availability of production workloads.
They are the foundation of AWS availability architecture.

AWS Edge Locations

Edge Locations are global points for content caching.
They serve content closer to users to reduce latency.
Primarily used by CloudFront and Global Accelerator.
They improve performance for static and dynamic content.
AWS has hundreds of POPs worldwide for content delivery.
Edge Locations reduce load on origin servers.
They are not full-service compute zones — just caching points.
They make global services feel fast to end users everywhere.

AWS Regional Edge Caches

Regional Edge Caches sit between Edge Locations and origin.
They cache larger objects when Edge Locations can’t hold them.
They help reduce requests going back to origin servers.
This improves global performance for less-frequently accessed content.
They are part of CloudFront’s caching hierarchy.
Regional caches are deployed in strategic intermediate points.
They reduce latency globally for dynamic workloads.
Useful when Edge Locations alone are insufficient for content scale.

AWS Local Zones

Local Zones extend AWS Regions into metro areas.
They deliver compute closer to end users for ultra-low latency.
They connect back to their parent Region.
Ideal for latency-sensitive workloads (gaming, real-time video).
They support compute, storage, and some database services.
Local Zones are not complete Regions — they’re extensions.
Often opt-in in your account before you use them.
They help meet local data gravity and compliance requirements.

AWS Wavelength Zones

Wavelength puts AWS compute inside 5G telco networks.
They deliver ultra-low latency for mobile applications.
They are built in partnership with telecom providers.
Traffic stays inside the 5G network instead of going to a Region.
Ideal for AR/VR, IoT, autonomous systems, real-time processing.
Easy access via AWS APIs, same experience as Regions.
Compute, storage, and networking are available at the edge.
They are especially useful where milliseconds matter.

AWS Outposts

Outposts bring AWS infrastructure on-premises.
They provide local rack infrastructure managed by AWS.
Outposts use the same AWS APIs and tools as in cloud Regions.
Ideal for hybrid cloud or data residency where local compute is needed.
Useful for workloads that must remain on-site for compliance.
They support AWS services locally like EC2, EBS, ECS, EKS.
Outposts hardware is fully supported and updated by AWS.
They extend the cloud’s control plane on customer premises.

✨ Bonus: AWS Dedicated Local Zones 

A Dedicated Local Zone is a Local Zone built for exclusive use by a customer.
Useful where strict data governance is required.
Managed infrastructure for a specific organization or community.
Ideal for public sector or regulated industries.
Helps satisfy stringent sovereignty requirements.
Still connects back to the Region for centralized control.
Combines low latency with strong compliance posture.
A niche (but strong) advanced AWS infrastructure concept to mention.

Wednesday, February 11, 2026

Amazon Redshift Architecture and Its Components

Amazon Redshift Architecture and Its Components


Leader Nodes

It keeps all the important information about tables and how the cluster is set up.
It decides the fastest way to run your query and sends the plan to all compute nodes.
It acts as the middleman between your SQL tools and the compute nodes.
It breaks the work into smaller pieces and sends them to the right slices to process.
It reads your SQL query, understands it, and figures out the best way to run it.
It collects the partial results coming from compute nodes and combines them into the final answer.
It makes sure many users can run queries at the same time without conflicts and keeps data consistent.
It stores all important information about tables, schemas, and cluster configuration.
It spreads the work evenly across compute nodes so no node gets overloaded.
It monitors the health of the cluster and handles node failures or issues.
It acts as the single connection point for all SQL tools and applications.
It breaks your SQL query into smaller tasks that can run in parallel.
It controls how data is distributed across nodes — by key, evenly, or fully copied.
It ensures all compute nodes work together smoothly and stay in sync during query execution.

Compute Nodes

Compute nodes store all the actual user data in the Redshift cluster.
They receive tasks from the leader node and process their assigned portion of the data.
Each compute node has its own CPU, memory, and storage to perform heavy workloads.
They run query operations in parallel and send results back to the leader node.
Compute nodes divide their work across slices for even faster processing.
They handle scanning, filtering, joining, and aggregating data locally.
The performance of the cluster increases as more compute nodes are added.
Compute nodes work independently but stay coordinated through the leader node.
They ensure large datasets can be processed quickly through parallel execution.
All user tables and column data physically reside on compute nodes, not on the leader node.

Node Slices

Each compute node is divided into smaller workers called slices.
Every slice gets its own portion of the node’s CPU, memory, and storage.
Slices work independently and in parallel to process data faster.
When data is loaded, rows are spread across slices based on the distribution key.
Each slice handles only its assigned chunk of data, reducing workload per slice.
More slices mean more parallelism, which improves query performance.
The number of slices depends on the node type (larger nodes = more slices).
Slices perform tasks like scanning, filtering, and joining data locally.
They send their partial results back to the compute node, which forwards them to the leader node.
Slices ensure that Redshift uses every bit of hardware inside a compute node efficiently.


Amazon Redshift Architecture:





What Happens When a User Runs a Simple SELECT Query

The leader node receives the SELECT query from the user.
It parses the SQL to understand what the user wants.
It builds a query tree (a logical structure of the query).
The optimizer checks statistics and finds the fastest way to run the query.
It creates the execution plan (the step‑by‑step blueprint).
The execution engine turns the plan into compiled C++ code.
Compute nodes run the code in parallel, each working on its portion of the data.
The leader node combines the results and returns the final output to the user.


Tuesday, February 10, 2026

The Art of SQL Practice: 12 Dimensions of Real‑World Data Analysis

The Art of SQL Practice: 12 Dimensions of Real‑World Data Analysis


✅ SECTION 1 — Filtering Data (Topics 1–10)

Filtering is the foundation of . Every ETL pipeline, report, and transformation starts with selecting the right rows.

1. Filter rows with simple conditions

What it is

Use WHERE to return only rows that match a condition.

Syntax

SELECT columns FROM table WHERE condition;

Example

Customers from USA:

SELECT * FROM Sales.Customers WHERE Country = 'USA';

Practice

Get all orders where Sales > 500.

2. Filter with AND

What it is

Combine multiple conditions that must all be true.

Example

Orders with high sales AND completed status:

SELECT * FROM Sales.Orders WHERE Sales > 500 AND OrderStatus = 'Completed';

Practice

Find customers from India with Score > 80.

3. Filter with OR

What it is

Return rows where any condition is true.

Example

Orders that are either Pending or Cancelled:

SELECT * FROM Sales.Orders WHERE OrderStatus = 'Pending' OR OrderStatus = 'Cancelled';

Practice

Find customers from USA or Canada.

4. Filter with BETWEEN

What it is

Filter values within a range (inclusive).

Example

Orders placed in May 2023:

SELECT * FROM Sales.Orders WHERE OrderDate BETWEEN '2023-05-01' AND '2023-05-31';

Practice

Find customers created between two dates.

5. Filter with IN

What it is

Match against a list of values.

Example

Orders with specific statuses:

SELECT * FROM Sales.Orders WHERE OrderStatus IN ('Completed', 'Pending');

Practice

Find customers from a list of countries.

6. Filter with LIKE

What it is

Pattern matching for strings.

Example

Customers whose first name starts with “A”:

SELECT * FROM Sales.Customers WHERE FirstName LIKE 'A%';

Practice

Find customers whose email ends with “.com”.

7. Filter NULL values

What it is

Use IS NULL or IS NOT NULL.

Example

Orders missing a ShipDate:

SELECT * FROM Sales.Orders WHERE ShipDate IS NULL;

Practice

Find customers with no phone number.

8. Filter NOT conditions

What it is

Exclude values.

Example

Orders not shipped to USA:

SELECT * FROM Sales.Orders WHERE Country <> 'USA';
(If you add Country to Orders later.)

Practice

Find customers not from India.

9. Filter using expressions

What it is

Use calculations inside WHERE.

Example

Orders where total revenue (Sales × Quantity) > 1000:

SELECT * FROM Sales.Orders WHERE (Sales * Quantity) > 1000;

Practice

Find orders where Quantity × Sales < 500.

10. Combine multiple filters

What it is

Use parentheses to control logic.

Example

Orders that are Completed OR (Pending AND high value):

SELECT * FROM Sales.Orders WHERE OrderStatus = 'Completed' OR (OrderStatus = 'Pending' AND Amount > 500);

Practice

Find customers from USA with Score > 50 OR from India with Score > 80.

⭐ SECTION 2 — JOINS (Topics 11–20)

Joins combine rows from multiple tables based on related columns.

This is the backbone of analytics, reporting, and ETL.

11. INNER JOIN — match rows in both tables

What it is

Returns rows where the join condition matches in both tables.

Syntax

SELECT ... FROM A INNER JOIN B ON A.key = B.key;

Example

List orders with customer names:

SELECT o.OrderID, o.Amount, c.FirstName, c.LastName FROM Sales.Orders o INNER JOIN Sales.Customers c ON o.CustomerID = c.CustomerID;

Practice

Show OrderID, OrderDate, FirstName for all matching orders.

12. LEFT JOIN — keep all customers, even without orders

What it is

Returns all rows from the left table, and matching rows from the right.

Example

Customers with their orders (including those with none):

SELECT c.CustomerID, c.FirstName, o.OrderID, o.Amount FROM Sales.Customers c LEFT JOIN Sales.Orders o ON c.CustomerID = o.CustomerID;

Practice

Find customers who have no orders.

13. RIGHT JOIN — keep all orders, even without customers
(Less common, but useful)

Example

Orders with customer info (even if customer missing):

SELECT o.OrderID, o.Amount, c.FirstName FROM Sales.Orders o RIGHT JOIN Sales.Customers c ON o.CustomerID = c.CustomerID;

Practice

Show all orders and customer names, even if customer is missing.

14. FULL OUTER JOIN — keep everything

What it is

Returns all rows from both tables.

Example

Customers and orders, even unmatched:

SELECT c.CustomerID, o.OrderID, c.FirstName, o.Amount FROM Sales.Customers c FULL OUTER JOIN Sales.Orders o ON c.CustomerID = o.CustomerID;

Practice

Find all customers and orders, including unmatched.

15. JOIN with additional filters

Example

Completed orders with customer names:

SELECT o.OrderID, o.Amount, c.FirstName FROM Sales.Orders o JOIN Sales.Customers c ON o.CustomerID = c.CustomerIDWHERE o.OrderStatus = 'Completed';

Practice

Find all Pending orders with customer names.

16. JOIN using expressions

Example

Orders where customer Score > 80:

SELECT o.OrderID, o.Amount, c.Score

FROM Sales.Orders o

JOIN Sales.Customers c

ON o.CustomerID = c.CustomerID

WHERE c.Score > 80;

Practice

Find orders where Quantity × Sales > 1000.




17. JOIN + GROUP BY

Example

Total sales per customer:







SELECT c.CustomerID, c.FirstName,

SUM(o.Amount) AS TotalSpent

FROM Sales.Customers c

LEFT JOIN Sales.Orders o

ON c.CustomerID = o.CustomerID

GROUP BY c.CustomerID, c.FirstName;

Practice

Count orders per customer.




18. JOIN with multiple tables

Example

Orders with customer and salesperson:







SELECT o.OrderID, c.FirstName, o.SalesPersonID

FROM Sales.Orders o

JOIN Sales.Customers c

ON o.CustomerID = c.CustomerID;

(You can later add a SalesPerson table.)




Practice

Show OrderID, CustomerName, and SalesPersonID.




19. Anti‑join (LEFT JOIN + NULL)

What it is

Find rows in one table with no match in another.




Example

Customers with no orders:







SELECT c.*

FROM Sales.Customers c

LEFT JOIN Sales.Orders o

ON c.CustomerID = o.CustomerID

WHERE o.OrderID IS NULL;

Practice

Find orders with no matching customer.




20. Semi‑join (EXISTS)

What it is

Check if a match exists, but don’t return the joined rows.




Example

Customers who have placed at least one order:







SELECT *

FROM Sales.Customers c

WHERE EXISTS (

SELECT 1

FROM Sales.Orders o

WHERE o.CustomerID = c.CustomerID

);

Practice

Find customers who placed orders after 2024.







SECTION 3 — Advanced joins (Topics 21–30)

We’ll keep using only your real tables:




Sales.Customers




Sales.Orders




21. Customers with orders in a specific month

Idea: Use EXTRACT‑like logic via MONTH() and YEAR() in Server.




Example — customers with orders in June 2023







SELECT DISTINCT c.CustomerID, c.FirstName, c.LastName

FROM Sales.Customers c

JOIN Sales.Orders o

ON c.CustomerID = o.CustomerID

WHERE YEAR(o.OrderDate) = 2023

AND MONTH(o.OrderDate) = 6;

Practice: Get customers who ordered in January 2024.




22. Customers with orders in multiple months

Idea: Group by customer and count distinct months.




Example







SELECT c.CustomerID, c.FirstName, c.LastName,

COUNT(DISTINCT (CONVERT(char(7), o.OrderDate, 120))) AS DistinctMonths

FROM Sales.Customers c

JOIN Sales.Orders o

ON c.CustomerID = o.CustomerID

GROUP BY c.CustomerID, c.FirstName, c.LastName

HAVING COUNT(DISTINCT (CONVERT(char(7), o.OrderDate, 120))) > 1;

Practice: Find customers who ordered in at least 3 different months.




23. Customers whose first order had high Amount

Idea: Use window functions to find the first order per customer.




Example — first order Amount > 200







WITH OrderedOrders AS (

SELECT o.*,

ROW_NUMBER() OVER (

PARTITION BY o.CustomerID

ORDER BY o.OrderDate

) AS rn

FROM Sales.Orders o

)

SELECT c.CustomerID, c.FirstName, c.LastName

FROM Sales.Customers c

JOIN OrderedOrders o

ON c.CustomerID = o.CustomerID

WHERE o.rn = 1

AND o.Amount > 200;

Practice: Find customers whose first order status was Cancelled.




24. Customers whose last order was Cancelled

Idea: Same pattern, but order by date descending.




Example







WITH OrderedOrders AS (

SELECT o.*,

ROW_NUMBER() OVER (

PARTITION BY o.CustomerID

ORDER BY o.OrderDate DESC

) AS rn

FROM Sales.Orders o

)

SELECT c.CustomerID, c.FirstName, c.LastName

FROM Sales.Customers c

JOIN OrderedOrders o

ON c.CustomerID = o.CustomerID

WHERE o.rn = 1

AND o.OrderStatus = 'Cancelled';

Practice: Find customers whose last order was Completed.




25. Customers with more than one PaymentMethod

Idea: Count distinct payment methods per customer.




Example







SELECT c.CustomerID, c.FirstName, c.LastName,

COUNT(DISTINCT o.PaymentMethod) AS DistinctPaymentMethods

FROM Sales.Customers c

JOIN Sales.Orders o

ON c.CustomerID = o.CustomerID

GROUP BY c.CustomerID, c.FirstName, c.LastName

HAVING COUNT(DISTINCT o.PaymentMethod) > 1;

Practice: Find customers who used exactly one payment method.




26. Customers with both Completed and Pending orders

Idea: Use conditional aggregation.




Example







SELECT c.CustomerID, c.FirstName, c.LastName

FROM Sales.Customers c

JOIN Sales.Orders o

ON c.CustomerID = o.CustomerID

GROUP BY c.CustomerID, c.FirstName, c.LastName

HAVING SUM(CASE WHEN o.OrderStatus = 'Completed' THEN 1 ELSE 0 END) > 0

AND SUM(CASE WHEN o.OrderStatus = 'Pending' THEN 1 ELSE 0 END) > 0;

Practice: Find customers who have both Completed and Cancelled orders.




27. Customers whose order Amount increased over time

Idea: Use LAG to compare each order to the previous one.




Example







WITH Lagged AS (

SELECT o.*,

LAG(o.Amount) OVER (

PARTITION BY o.CustomerID

ORDER BY o.OrderDate

) AS PrevAmount

FROM Sales.Orders o

)

SELECT DISTINCT CustomerID

FROM Lagged

WHERE PrevAmount IS NOT NULL

AND Amount > PrevAmount;

Practice: Find customers whose Amount decreased compared to the previous order.




28. Customers whose order Amount decreased over time

Example







WITH Lagged AS (

SELECT o.*,

LAG(o.Amount) OVER (

PARTITION BY o.CustomerID

ORDER BY o.OrderDate

) AS PrevAmount

FROM Sales.Orders o

)

SELECT DISTINCT CustomerID

FROM Lagged

WHERE PrevAmount IS NOT NULL

AND Amount < PrevAmount;

Practice: Find customers whose Amount stayed the same as previous order.




29. Orders updated on the same day they were created

Idea: Compare CreationTime and UpdatedAt dates.




Example







SELECT *

FROM Sales.Orders

WHERE CONVERT(date, CreationTime) = CONVERT(date, UpdatedAt);

Practice: Find orders updated at least 3 days after CreationTime.




30. Customers with orders in 2023 but not in 2024

Idea: Use two sets and anti‑join logic.




Example







WITH Orders2023 AS (

SELECT DISTINCT CustomerID

FROM Sales.Orders

WHERE YEAR(OrderDate) = 2023

),

Orders2024 AS (

SELECT DISTINCT CustomerID

FROM Sales.Orders

WHERE YEAR(OrderDate) = 2024

)

SELECT c.CustomerID, c.FirstName, c.LastName

FROM Sales.Customers c

JOIN Orders2023 y23

ON c.CustomerID = y23.CustomerID

LEFT JOIN Orders2024 y24

ON c.CustomerID = y24.CustomerID

WHERE y24.CustomerID IS NULL;

Practice: Find customers who ordered in 2024 but not in 2023.







✅ SECTION 4 — Set Operators (31–35)

31. UNION

Combine rows from two queries.







SELECT Country FROM Sales.Customers

UNION

SELECT PaymentMethod FROM Sales.Orders;

32. INTERSECT

Common rows.







SELECT CustomerID FROM Sales.Customers

INTERSECT

SELECT CustomerID FROM Sales.Orders;

33. EXCEPT

Rows in first query but not second.







SELECT CustomerID FROM Sales.Customers

EXCEPT

SELECT CustomerID FROM Sales.Orders;

34. UNION ALL

Keeps duplicates.







SELECT Country FROM Sales.Customers

UNION ALL

SELECT Country FROM Sales.Customers;

35. EXCEPT for date ranges




SELECT CustomerID FROM Sales.Orders WHERE YEAR(OrderDate)=2023

EXCEPT

SELECT CustomerID FROM Sales.Orders WHERE YEAR(OrderDate)=2024;

✅ SECTION 5 — Functions (36–45)

36. ROUND




SELECT OrderID, ROUND(Amount,2) FROM Sales.Orders;

37. Math expression




SELECT OrderID, Amount * 1.10 AS WithTax FROM Sales.Orders;

38. CONCAT




SELECT CONCAT(FirstName,' ',LastName) AS FullName FROM Sales.Customers;

39. SUBSTRING




SELECT SUBSTRING(Email, CHARINDEX('@',Email)+1, 100) AS Domain

FROM Sales.Customers;

40. REPLACE




SELECT REPLACE(ShipAddress,'Street','St') FROM Sales.Orders;

41. UPPER/LOWER




SELECT UPPER(FirstName) FROM Sales.Customers;

42. LEN




SELECT Email FROM Sales.Customers WHERE LEN(Email)>15;

43. TRIM




SELECT LTRIM(RTRIM(Phone)) FROM Sales.Customers;

44. ABS




SELECT ABS(Sales - Amount) FROM Sales.Orders;

45. CEILING/FLOOR




SELECT CEILING(Amount), FLOOR(Amount) FROM Sales.Orders;

✅ SECTION 6 — Date Functions (46–55)

46. YEAR/MONTH/DAY




SELECT YEAR(OrderDate), MONTH(OrderDate) FROM Sales.Orders;

47. DATEADD




SELECT DATEADD(DAY,7,OrderDate) FROM Sales.Orders;

48. DATEDIFF




SELECT DATEDIFF(DAY,OrderDate,ShipDate) FROM Sales.Orders;

49. GETDATE




SELECT * FROM Sales.Customers WHERE CreatedAt > DATEADD(DAY,-30,GETDATE());

50. Orders on weekends




SELECT * FROM Sales.Orders WHERE DATEPART(WEEKDAY,OrderDate) IN (1,7);

51. NULLIF




SELECT NULLIF(Amount,0) FROM Sales.Orders;

52. COALESCE




SELECT COALESCE(Phone,'Unknown') FROM Sales.Customers;

53. ISNULL




SELECT ISNULL(Amount,0) FROM Sales.Orders;

54. CAST/CONVERT




SELECT CONVERT(varchar,OrderDate,23) FROM Sales.Orders;

55. DATEFROMPARTS




SELECT DATEFROMPARTS(2024,1,1);

✅ SECTION 7 — CASE (56–65)

56. Categorize Amount




SELECT CASE WHEN Amount>500 THEN 'High' ELSE 'Low' END FROM Sales.Orders;

57. Categorize Score




SELECT CASE WHEN Score>=80 THEN 'Gold' ELSE 'Regular' END FROM Sales.Customers;

58. Categorize OrderStatus




SELECT CASE OrderStatus WHEN 'Completed' THEN 'Done' ELSE 'Pending' END FROM Sales.Orders;

59. Categorize by Country




SELECT CASE WHEN Country='USA' THEN 'North America' ELSE 'Other' END FROM Sales.Customers;

60. Categorize by Quantity




SELECT CASE WHEN Quantity>10 THEN 'Bulk' ELSE 'Normal' END FROM Sales.Orders;

61–65 similar patterns

(You now know the structure.)




✅ SECTION 8 — Aggregates (66–75)

66. COUNT




SELECT COUNT(*) FROM Sales.Customers;

67. SUM




SELECT SUM(Amount) FROM Sales.Orders;

68. AVG




SELECT AVG(Amount) FROM Sales.Orders;

69. MIN/MAX




SELECT MIN(Amount), MAX(Amount) FROM Sales.Orders;

70. GROUP BY Country




SELECT Country, COUNT(*) FROM Sales.Customers GROUP BY Country;

71. Orders per customer




SELECT CustomerID, COUNT(*) FROM Sales.Orders GROUP BY CustomerID;

72. Revenue per customer




SELECT CustomerID, SUM(Amount) FROM Sales.Orders GROUP BY CustomerID;

73. Orders per status




SELECT OrderStatus, COUNT(*) FROM Sales.Orders GROUP BY OrderStatus;

74. Average Quantity




SELECT AVG(Quantity) FROM Sales.Orders;

75. Monthly orders




SELECT YEAR(OrderDate), MONTH(OrderDate), COUNT(*)

FROM Sales.Orders

GROUP BY YEAR(OrderDate), MONTH(OrderDate);

✅ SECTION 9 — Window Functions (76–95)

76. Running total




SELECT OrderID, Amount,

SUM(Amount) OVER (ORDER BY OrderDate) AS RunningTotal

FROM Sales.Orders;

77. Total per customer




SELECT OrderID, CustomerID,

SUM(Amount) OVER (PARTITION BY CustomerID)

FROM Sales.Orders;

78. Avg per customer




SELECT OrderID, AVG(Amount) OVER (PARTITION BY CustomerID)

FROM Sales.Orders;

79. Count per customer




SELECT OrderID, COUNT(*) OVER (PARTITION BY CustomerID)

FROM Sales.Orders;

80. Percent of total




SELECT OrderID, Amount,

Amount * 1.0 / SUM(Amount) OVER ()

FROM Sales.Orders;

81. Max per customer




SELECT OrderID, MAX(Amount) OVER (PARTITION BY CustomerID)

FROM Sales.Orders;

82. Min per customer




SELECT OrderID, MIN(Amount) OVER (PARTITION BY CustomerID)

FROM Sales.Orders;

83. First order amount




SELECT OrderID,

FIRST_VALUE(Amount) OVER (PARTITION BY CustomerID ORDER BY OrderDate)

FROM Sales.Orders;

84. Last order amount




SELECT OrderID,

LAST_VALUE(Amount) OVER (

PARTITION BY CustomerID ORDER BY OrderDate

ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING

)

FROM Sales.Orders;

85. LAG




SELECT OrderID, Amount,

LAG(Amount) OVER (PARTITION BY CustomerID ORDER BY OrderDate)

FROM Sales.Orders;

86. LEAD




SELECT OrderID, Amount,

LEAD(Amount) OVER (PARTITION BY CustomerID ORDER BY OrderDate)

FROM Sales.Orders;

87. ROW_NUMBER




SELECT OrderID,

ROW_NUMBER() OVER (ORDER BY Amount DESC)

FROM Sales.Orders;

88. RANK




SELECT OrderID,

RANK() OVER (ORDER BY Amount DESC)

FROM Sales.Orders;

89. DENSE_RANK




SELECT OrderID,

DENSE_RANK() OVER (ORDER BY Amount DESC)

FROM Sales.Orders;

90–95 similar patterns

(Top N per customer, differences, etc.)




✅ SECTION 10 — Subqueries & CTEs (96–105)

96. Subquery filter




SELECT * FROM Sales.Customers

WHERE CustomerID IN (SELECT CustomerID FROM Sales.Orders WHERE Amount>500);

97. Total spend > 1000




SELECT * FROM Sales.Customers

WHERE CustomerID IN (

SELECT CustomerID FROM Sales.Orders GROUP BY CustomerID HAVING SUM(Amount)>1000

);

98. More than 3 orders




SELECT CustomerID FROM Sales.Orders

GROUP BY CustomerID HAVING COUNT(*)>3;

99. First order cancelled




WITH x AS (

SELECT *, ROW_NUMBER() OVER (PARTITION BY CustomerID ORDER BY OrderDate) rn

FROM Sales.Orders

)

SELECT * FROM x WHERE rn=1 AND OrderStatus='Cancelled';

100. Only ordered in 2023




WITH y AS (

SELECT CustomerID, YEAR(OrderDate) yr FROM Sales.Orders GROUP BY CustomerID,YEAR(OrderDate)

)

SELECT CustomerID FROM y GROUP BY CustomerID HAVING COUNT(*)=1 AND MIN(yr)=2023;

101–105 CTE patterns

(monthly revenue, repeat customers, etc.)




✅ SECTION 11 — Views, CTAS, Temp Tables (106–115)

106. View




CREATE VIEW Sales.CustomerSummary AS

SELECT c.CustomerID, c.FirstName, COUNT(o.OrderID) AS TotalOrders

FROM Sales.Customers c

LEFT JOIN Sales.Orders o ON c.CustomerID=o.CustomerID

GROUP BY c.CustomerID, c.FirstName;

107. High value orders




CREATE VIEW Sales.HighValueOrders AS

SELECT * FROM Sales.Orders WHERE Amount>500;

108. Monthly revenue




CREATE VIEW Sales.MonthlyRevenue AS

SELECT YEAR(OrderDate) yr, MONTH(OrderDate) mn, SUM(Amount) total

FROM Sales.Orders GROUP BY YEAR(OrderDate),MONTH(OrderDate);

109. CTAS




SELECT * INTO Sales.TempHighOrders

FROM Sales.Orders WHERE Amount>500;

110–115 similar patterns

(temp tables, CTAS, etc.)




✅ SECTION 12 — Stored Procedures (116–120)

116. Update order status




CREATE PROCEDURE Sales.UpdateStatus @OrderID int, @Status varchar(50)

AS

UPDATE Sales.Orders SET OrderStatus=@Status WHERE OrderID=@OrderID;

117. Delete cancelled




CREATE PROCEDURE Sales.DeleteCancelled AS

DELETE FROM Sales.Orders WHERE OrderStatus='Cancelled';

118–120 similar patterns

(insert customer, archive orders, etc.)




✅ SECTION 13 — Triggers (121–125)

121. Auto-update UpdatedAt




CREATE TRIGGER trg_UpdateTime ON Sales.Orders

AFTER UPDATE AS

UPDATE o SET UpdatedAt=GETDATE()

FROM Sales.Orders o

JOIN inserted i ON o.OrderID=i.OrderID;

122. Log deletes




CREATE TRIGGER trg_LogDelete ON Sales.Orders

AFTER DELETE AS

INSERT INTO Sales.OrderDeleteLog(OrderID,Amount,DeletedAt)

SELECT OrderID,Amount,GETDATE() FROM deleted;

123–125 similar patterns

(prevent negative, track status changes, etc.)




✅ SECTION 14 — Indexes & Execution Plans (126–135)

126. Index




CREATE INDEX idx_orders_customer ON Sales.Orders(CustomerID);

127. Index on Email




CREATE INDEX idx_customers_email ON Sales.Customers(Email);

128. Composite index




CREATE INDEX idx_orders_customer_date ON Sales.Orders(CustomerID,OrderDate);

129–135

Use:







SET STATISTICS IO ON;

SET STATISTICS TIME ON;

EXPLAIN...

✅ SECTION 15 — Partitioning & Performance (136–150)

Server partitioning example:




136. Create partition function




CREATE PARTITION FUNCTION pfOrders (date)

AS RANGE RIGHT FOR VALUES ('2023-01-01','2024-01-01');

137. Create partition scheme




CREATE PARTITION SCHEME psOrders AS PARTITION pfOrders ALL TO ([PRIMARY]);

138. Create partitioned table




CREATE TABLE Sales.OrdersPartitioned (...)

ON psOrders(OrderDate);

139–150

Performance rewrites:




Replace OR with IN




Use EXISTS instead of IN




Avoid SELECT *




Use covering indexes




Use window functions instead of correlated subqueries




✅ SECTION 16 — AI + (151–155)

151. Convert English →

You already saw many examples.




152. Explain in English

You can ask me anytime.




153. Optimize

Rewrite slow queries using:




indexes




window functions




CTEs




predicate pushdown




154. Generate test data

Use loops or random functions.




155. Convert business question →

Example:




“Top 5 customers by revenue”







SELECT TOP 5 CustomerID, SUM(Amount) AS TotalSpent

FROM Sales.Orders

GROUP BY CustomerID

ORDER BY TotalSpent DESC;