20 SQL Interview Questions for Data Engineers: Real Problems, Step-by-Step Solutions, and the Thinking Process Behind Each Answer

20 SQL Interview Questions for Data Engineers: Real Problems, Step-by-Step Solutions, and the Thinking Process Behind Each Answer

You have learned every SQL concept — joins, window functions, subqueries, CTEs, GROUP BY, MERGE, indexes, transactions. But knowing the concepts and solving interview problems under pressure are two different skills.

The gap is not knowledge — it is PATTERN RECOGNITION. Interviewers do not ask “explain ROW_NUMBER.” They ask “find the second highest salary per department.” You need to instantly recognize: “This is a top-N-per-group problem → window function → ROW_NUMBER with PARTITION BY.”

This post gives you 20 real interview problems, organized from basic to advanced. For each one, I show the thinking process FIRST (how to recognize the pattern), then the solution, then common follow-up questions the interviewer might ask. Practice these, and you will recognize 90% of SQL interview patterns on sight.

The Sample Database

All questions use this database. Run the CREATE + INSERT statements to practice along:

CREATE TABLE employees (
    emp_id INT PRIMARY KEY,
    name VARCHAR(50),
    department VARCHAR(50),
    salary DECIMAL(10,2),
    manager_id INT NULL,
    hire_date DATE
);

INSERT INTO employees VALUES
(1, 'Naveen', 'Engineering', 105000, NULL, '2022-01-15'),
(2, 'Shrey', 'Engineering', 95000, 1, '2023-03-20'),
(3, 'Vrushab', 'Engineering', 92000, 1, '2023-06-10'),
(4, 'Vishnu', 'Analytics', 91000, NULL, '2023-09-01'),
(5, 'Ravi', 'Analytics', 85000, 4, '2024-01-05'),
(6, 'Priya', 'Analytics', 85000, 4, '2023-07-15'),
(7, 'Anita', 'Sales', 78000, NULL, '2024-03-15'),
(8, 'Deepak', 'Sales', 82000, 7, '2024-05-01'),
(9, 'Kavya', 'Sales', 78000, 7, '2024-02-10'),
(10, 'Manoj', 'Sales', 75000, 7, '2023-11-20');

CREATE TABLE orders (
    order_id INT PRIMARY KEY,
    customer_id INT,
    product VARCHAR(50),
    amount DECIMAL(10,2),
    order_date DATE
);

INSERT INTO orders VALUES
(101, 1, 'Laptop', 999.99, '2025-01-15'),
(102, 2, 'Mouse', 29.99, '2025-01-20'),
(103, 1, 'Keyboard', 79.99, '2025-02-10'),
(104, 3, 'Monitor', 399.99, '2025-02-15'),
(105, 1, 'Laptop', 999.99, '2025-03-01'),
(106, 4, 'Laptop', 999.99, '2025-03-10'),
(107, 2, 'Webcam', 59.99, '2025-03-15'),
(108, 5, 'Laptop', 999.99, '2025-04-01'),
(109, 3, 'Keyboard', 79.99, '2025-04-10'),
(110, 1, 'Mouse', 29.99, '2025-04-20'),
(111, 6, 'Monitor', 399.99, '2025-05-01'),
(112, 2, 'Laptop', 999.99, '2025-05-10');

CREATE TABLE customers (
    customer_id INT PRIMARY KEY,
    name VARCHAR(50),
    city VARCHAR(50),
    signup_date DATE
);

INSERT INTO customers VALUES
(1, 'Alice', 'Toronto', '2024-01-01'),
(2, 'Bob', 'Mumbai', '2024-03-15'),
(3, 'Carol', 'Toronto', '2024-06-01'),
(4, 'David', 'Delhi', '2024-09-10'),
(5, 'Eve', 'Toronto', '2025-01-01'),
(6, 'Frank', 'Mumbai', '2025-02-15'),
(7, 'Grace', 'Vancouver', '2025-03-01');

Table of Contents

  • Q1: Second Highest Salary (Classic)
  • Q2: Nth Highest Salary Per Department
  • Q3: Employees Earning More Than Their Manager
  • Q4: Duplicate Detection
  • Q5: Consecutive Days with Orders
  • Q6: Customers Who Never Ordered
  • Q7: Department with Highest Average Salary
  • Q8: Running Total
  • Q9: Year-over-Year Growth
  • Q10: Top 3 Products by Revenue
  • Q11: Employees Hired in the Same Month
  • Q12: Find Gaps in Sequential IDs
  • Q13: Customers Who Ordered Every Month
  • Q14: Percentage of Total
  • Q15: Self-Join: Find Pairs
  • Q16: Delete Duplicates (Keep One)
  • Q17: Moving Average
  • Q18: Rank Without Gaps vs With Gaps
  • Q19: Pivot Monthly Revenue by Product
  • Q20: Complex Multi-CTE Business Question
  • Pattern Recognition Cheat Sheet
  • Final Tips for SQL Interviews

Q1: Second Highest Salary (Classic)

Question: Find the second highest salary in the company.

Think: “Second highest → need ranking → but just one value, not per group.”

-- Solution 1: Subquery with MAX
SELECT MAX(salary) AS second_highest
FROM employees
WHERE salary < (SELECT MAX(salary) FROM employees);
-- Logic: Find the max salary that is LESS than the overall max

-- Solution 2: DENSE_RANK (more flexible)
SELECT salary AS second_highest
FROM (
    SELECT salary, DENSE_RANK() OVER (ORDER BY salary DESC) AS rnk
    FROM employees
) ranked
WHERE rnk = 2;

-- Solution 3: OFFSET/FETCH (simplest)
SELECT DISTINCT salary AS second_highest
FROM employees
ORDER BY salary DESC
OFFSET 1 ROW FETCH NEXT 1 ROW ONLY;

Why DENSE_RANK and not ROW_NUMBER? If two employees share the highest salary, ROW_NUMBER would assign ranks 1 and 2 to them, making the next salary rank 3. DENSE_RANK correctly handles ties.

Follow-up: “What if there is no second highest (all salaries are the same)?” — The subquery approach returns NULL. DENSE_RANK returns no rows. Handle with COALESCE or an outer query.

Q2: Nth Highest Salary Per Department

Question: Find the 2nd highest salary IN EACH department.

Think: “Per department + ranking → PARTITION BY + DENSE_RANK.”

SELECT department, name, salary
FROM (
    SELECT department, name, salary,
        DENSE_RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS rnk
    FROM employees
) ranked
WHERE rnk = 2;
department name salary
Analytics Priya 85000
Analytics Ravi 85000
Engineering Shrey 95000
Sales Anita 78000
Sales Kavya 78000

Priya and Ravi tie at rank 2 in Analytics. DENSE_RANK correctly returns both.

Pattern: Any “Nth per group” question → DENSE_RANK + PARTITION BY.

Q3: Employees Earning More Than Their Manager

Question: Find employees who earn more than their manager.

Think: “Compare employee to manager → self-join on manager_id.”

SELECT e.name AS employee, e.salary AS emp_salary,
       m.name AS manager, m.salary AS mgr_salary
FROM employees e
JOIN employees m ON e.manager_id = m.emp_id
WHERE e.salary > m.salary;

Pattern: Any “compare row to a related row in the same table” → self-join.

Follow-up: “What if you also want employees with no manager?” — Use LEFT JOIN and handle NULLs.

Q4: Duplicate Detection

Question: Find customers who placed more than one order for the same product.

Think: “Same customer + same product more than once → GROUP BY + HAVING COUNT > 1.”

SELECT customer_id, product, COUNT(*) AS order_count
FROM orders
GROUP BY customer_id, product
HAVING COUNT(*) > 1
ORDER BY order_count DESC;
customer_id product order_count
1 Laptop 2
1 Mouse 2
3 Keyboard 2

Pattern: “Find duplicates” → GROUP BY the columns that define uniqueness + HAVING COUNT(*) > 1.

Follow-up: “Show the actual duplicate rows with all columns.”

SELECT o.*
FROM orders o
JOIN (
    SELECT customer_id, product
    FROM orders GROUP BY customer_id, product HAVING COUNT(*) > 1
) dupes ON o.customer_id = dupes.customer_id AND o.product = dupes.product
ORDER BY o.customer_id, o.product, o.order_date;

Q5: Consecutive Days with Orders

Question: Find customers who placed orders on 2 or more consecutive days.

Think: “Consecutive → need to compare current row with previous row → LAG.”

WITH order_with_prev AS (
    SELECT customer_id, order_date,
        LAG(order_date) OVER (PARTITION BY customer_id ORDER BY order_date) AS prev_order_date
    FROM orders
)
SELECT DISTINCT customer_id
FROM order_with_prev
WHERE DATEDIFF(DAY, prev_order_date, order_date) = 1;

Pattern: “Consecutive” or “next/previous” → LAG or LEAD window functions.

Q6: Customers Who Never Ordered

Question: Find customers who have never placed an order.

Think: “In customers but NOT in orders → anti-join → LEFT JOIN IS NULL or NOT EXISTS.”

-- Solution 1: LEFT JOIN + IS NULL (most readable)
SELECT c.name, c.city
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
WHERE o.order_id IS NULL;

-- Solution 2: NOT EXISTS (often faster on large tables)
SELECT c.name, c.city
FROM customers c
WHERE NOT EXISTS (
    SELECT 1 FROM orders o WHERE o.customer_id = c.customer_id
);

-- Solution 3: NOT IN (avoid if NULLs possible in subquery)
SELECT name, city FROM customers
WHERE customer_id NOT IN (SELECT DISTINCT customer_id FROM orders);

Result: Grace (customer_id = 7) — signed up but never ordered.

Pattern: “Never did X” or “without any Y” → LEFT JOIN IS NULL or NOT EXISTS. Always prefer NOT EXISTS over NOT IN (NULL-safe).

Q7: Department with Highest Average Salary

Question: Find the department with the highest average salary.

Think: “Aggregate per department → rank the aggregates → top 1.”

-- Solution 1: TOP 1
SELECT TOP 1 department, ROUND(AVG(salary), 0) AS avg_salary
FROM employees
GROUP BY department
ORDER BY avg_salary DESC;

-- Solution 2: CTE with RANK (handles ties)
WITH dept_avg AS (
    SELECT department, AVG(salary) AS avg_salary,
        RANK() OVER (ORDER BY AVG(salary) DESC) AS rnk
    FROM employees
    GROUP BY department
)
SELECT department, ROUND(avg_salary, 0) AS avg_salary
FROM dept_avg WHERE rnk = 1;

Follow-up: “What if two departments tie?” — TOP 1 returns only one. RANK returns both tied departments.

Q8: Running Total

Question: Calculate a running total of order amounts per customer, ordered by date.

Think: “Running total → SUM as a window function with ROWS frame.”

SELECT customer_id, order_date, product, amount,
    SUM(amount) OVER (
        PARTITION BY customer_id
        ORDER BY order_date
        ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
    ) AS running_total
FROM orders
ORDER BY customer_id, order_date;
customer_id order_date product amount running_total
1 2025-01-15 Laptop 999.99 999.99
1 2025-02-10 Keyboard 79.99 1079.98
1 2025-03-01 Laptop 999.99 2079.97
1 2025-04-20 Mouse 29.99 2109.96

Pattern: “Running total” or “cumulative sum” → SUM() OVER (ORDER BY … ROWS UNBOUNDED PRECEDING).

Q9: Year-over-Year Growth

Question: Calculate the month-over-month revenue growth percentage.

Think: “Compare this month with previous month → LAG on monthly aggregation.”

WITH monthly_revenue AS (
    SELECT FORMAT(order_date, 'yyyy-MM') AS month,
           SUM(amount) AS revenue
    FROM orders
    GROUP BY FORMAT(order_date, 'yyyy-MM')
),
with_prev AS (
    SELECT month, revenue,
        LAG(revenue) OVER (ORDER BY month) AS prev_revenue
    FROM monthly_revenue
)
SELECT month, revenue, prev_revenue,
    CASE WHEN prev_revenue IS NOT NULL AND prev_revenue != 0
         THEN ROUND((revenue - prev_revenue) / prev_revenue * 100, 1)
         ELSE NULL
    END AS growth_pct
FROM with_prev
ORDER BY month;

Pattern: “Growth” or “compare with previous period” → aggregate first, then LAG.

Q10: Top 3 Products by Revenue

Question: Find the top 3 products by total revenue.

Think: “Aggregate by product → rank → top 3.”

SELECT TOP 3 product,
    SUM(amount) AS total_revenue,
    COUNT(*) AS order_count
FROM orders
GROUP BY product
ORDER BY total_revenue DESC;
product total_revenue order_count
Laptop 3999.96 4
Monitor 799.98 2
Keyboard 159.98 2

Follow-up: “Top 3 per city?” → Add PARTITION BY city with DENSE_RANK.

Q11: Employees Hired in the Same Month

Question: Find pairs of employees who were hired in the same month and year.

Think: “Pairs in the same table → self-join. Same month → YEAR and MONTH match.”

SELECT e1.name AS employee_1, e2.name AS employee_2,
    FORMAT(e1.hire_date, 'yyyy-MM') AS hire_month
FROM employees e1
JOIN employees e2 ON YEAR(e1.hire_date) = YEAR(e2.hire_date)
                  AND MONTH(e1.hire_date) = MONTH(e2.hire_date)
                  AND e1.emp_id < e2.emp_id    -- Avoid duplicates (A,B) and (B,A)
ORDER BY hire_month;

Why e1.emp_id < e2.emp_id? Without it, you get both (Naveen, Shrey) AND (Shrey, Naveen). The less-than condition keeps only one pair.

Pattern: “Find pairs” → self-join with < to avoid duplicates.

Q12: Find Gaps in Sequential IDs

Question: Find missing order IDs in the sequence (gaps where IDs were skipped or deleted).

Think: “Gaps → compare each ID to the next → LEAD.”

WITH with_next AS (
    SELECT order_id,
        LEAD(order_id) OVER (ORDER BY order_id) AS next_order_id
    FROM orders
)
SELECT order_id AS gap_after,
       next_order_id AS gap_before,
       next_order_id - order_id - 1 AS missing_count
FROM with_next
WHERE next_order_id - order_id > 1;

Pattern: “Gaps” or “missing values” → LEAD to find the next value, subtract to find the gap.

Q13: Customers Who Ordered Every Month

Question: Find customers who placed at least one order in every month of 2025 (Jan-May).

Think: “Every month → count distinct months per customer → compare with total months.”

SELECT c.name, COUNT(DISTINCT FORMAT(o.order_date, 'yyyy-MM')) AS months_ordered
FROM customers c
JOIN orders o ON c.customer_id = o.customer_id
WHERE o.order_date >= '2025-01-01' AND o.order_date < '2026-01-01'
GROUP BY c.customer_id, c.name
HAVING COUNT(DISTINCT FORMAT(o.order_date, 'yyyy-MM')) = (
    SELECT COUNT(DISTINCT FORMAT(order_date, 'yyyy-MM'))
    FROM orders
    WHERE order_date >= '2025-01-01' AND order_date < '2026-01-01'
);

Pattern: “Every X” or “all of” → count distinct occurrences per entity and compare with the total distinct count.

Q14: Percentage of Total

Question: Show each employee’s salary as a percentage of their department’s total salary.

Think: “Individual vs group total → window function SUM without ORDER BY.”

SELECT name, department, salary,
    SUM(salary) OVER (PARTITION BY department) AS dept_total,
    ROUND(salary * 100.0 / SUM(salary) OVER (PARTITION BY department), 1) AS pct_of_dept
FROM employees
ORDER BY department, salary DESC;

Pattern: “Percentage of total” or “ratio to group” → SUM() OVER (PARTITION BY group) as the denominator.

Q15: Self-Join: Find Pairs with Salary Difference < 5000

Question: Find all pairs of employees in the same department whose salary difference is less than 5000.

Think: “Pairs + same department + condition → self-join.”

SELECT e1.name AS employee_1, e2.name AS employee_2,
    e1.department,
    ABS(e1.salary - e2.salary) AS salary_diff
FROM employees e1
JOIN employees e2 ON e1.department = e2.department
                  AND e1.emp_id < e2.emp_id
WHERE ABS(e1.salary - e2.salary) < 5000
ORDER BY e1.department, salary_diff;

Q16: Delete Duplicates (Keep One)

Question: Delete duplicate rows from a table, keeping only the row with the lowest ID.

Think: “Identify duplicates with ROW_NUMBER → delete where row_num > 1.”

-- Step 1: Identify duplicates (preview first!)
SELECT *, ROW_NUMBER() OVER (
    PARTITION BY customer_id, product
    ORDER BY order_id ASC
) AS rn
FROM orders;
-- rn = 1 is the original, rn > 1 are duplicates

-- Step 2: Delete duplicates
WITH duplicates AS (
    SELECT order_id, ROW_NUMBER() OVER (
        PARTITION BY customer_id, product
        ORDER BY order_id ASC
    ) AS rn
    FROM orders
)
DELETE FROM duplicates WHERE rn > 1;

Pattern: “Delete duplicates keeping one” → ROW_NUMBER partitioned by duplicate columns, DELETE where rn > 1. Always preview with SELECT first.

Q17: Moving Average

Question: Calculate a 3-order moving average of order amounts per customer.

Think: “Moving average → AVG with ROWS BETWEEN frame.”

SELECT customer_id, order_date, amount,
    ROUND(AVG(amount) OVER (
        PARTITION BY customer_id
        ORDER BY order_date
        ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
    ), 2) AS moving_avg_3
FROM orders
ORDER BY customer_id, order_date;

Pattern: “Moving average” or “rolling average” → AVG() OVER (ROWS BETWEEN N PRECEDING AND CURRENT ROW).

Q18: Rank Without Gaps vs With Gaps

Question: Rank employees by salary within each department. Show ROW_NUMBER, RANK, and DENSE_RANK side by side.

Think: “Compare ranking functions → show all three.”

SELECT department, name, salary,
    ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS row_num,
    RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS rnk,
    DENSE_RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS dense_rnk
FROM employees
ORDER BY department, salary DESC;
department name salary row_num rnk dense_rnk
Analytics Vishnu 91000 1 1 1
Analytics Priya 85000 2 2 2
Analytics Ravi 85000 3 2 2
Sales Deepak 82000 1 1 1
Sales Anita 78000 2 2 2
Sales Kavya 78000 3 2 2
Sales Manoj 75000 4 4 3

Notice Manoj: ROW_NUMBER=4, RANK=4 (gap after ties), DENSE_RANK=3 (no gap).

Interviewer follow-up: “Which would you use for deduplication?” → ROW_NUMBER (unique per row). “For competition ranking?” → RANK (gaps). “For counting distinct salary levels?” → DENSE_RANK (no gaps).

Q19: Pivot Monthly Revenue by Product

Question: Show monthly revenue with products as columns.

Think: “Rows to columns → PIVOT or CASE WHEN.”

SELECT FORMAT(order_date, 'yyyy-MM') AS month,
    SUM(CASE WHEN product = 'Laptop' THEN amount ELSE 0 END) AS Laptop,
    SUM(CASE WHEN product = 'Monitor' THEN amount ELSE 0 END) AS Monitor,
    SUM(CASE WHEN product = 'Keyboard' THEN amount ELSE 0 END) AS Keyboard,
    SUM(CASE WHEN product = 'Mouse' THEN amount ELSE 0 END) AS Mouse,
    SUM(CASE WHEN product = 'Webcam' THEN amount ELSE 0 END) AS Webcam,
    SUM(amount) AS Total
FROM orders
GROUP BY FORMAT(order_date, 'yyyy-MM')
ORDER BY month;

Pattern: “Pivot” or “rows to columns” → SUM(CASE WHEN column = value THEN amount END) with GROUP BY.

Q20: Complex Multi-CTE Business Question

Question: Find the customers whose total spending is above the average customer spending, show their rank, and what percentage of total company revenue they represent.

Think: “Multiple steps → break into CTEs: customer totals → average → filter → rank → percentage.”

WITH customer_totals AS (
    -- Step 1: Total spending per customer
    SELECT c.customer_id, c.name, c.city,
        SUM(o.amount) AS total_spent,
        COUNT(o.order_id) AS order_count
    FROM customers c
    JOIN orders o ON c.customer_id = o.customer_id
    GROUP BY c.customer_id, c.name, c.city
),
company_stats AS (
    -- Step 2: Company-wide metrics
    SELECT AVG(total_spent) AS avg_spending,
           SUM(total_spent) AS total_revenue
    FROM customer_totals
),
above_avg AS (
    -- Step 3: Filter to above-average customers
    SELECT ct.*,
        RANK() OVER (ORDER BY ct.total_spent DESC) AS spending_rank,
        ROUND(ct.total_spent * 100.0 / cs.total_revenue, 1) AS pct_of_revenue,
        ROUND(cs.avg_spending, 2) AS avg_spending
    FROM customer_totals ct
    CROSS JOIN company_stats cs
    WHERE ct.total_spent > cs.avg_spending
)
SELECT name, city, total_spent, order_count,
    spending_rank, pct_of_revenue, avg_spending
FROM above_avg
ORDER BY spending_rank;

Pattern: Complex business questions → break into CTEs, each solving one piece. Name them clearly. Build step by step.

Pattern Recognition Cheat Sheet

Interview Question Pattern Technique Key Function
“Nth highest” Window + filter DENSE_RANK() OVER (ORDER BY col DESC)
“Top N per group” Window + filter ROW_NUMBER() OVER (PARTITION BY grp ORDER BY col DESC)
“Compare to manager/parent” Self-join JOIN table t2 ON t1.parent_id = t2.id
“Find duplicates” GROUP BY + HAVING HAVING COUNT(*) > 1
“Delete duplicates” ROW_NUMBER + DELETE DELETE WHERE rn > 1
“Never did X” Anti-join LEFT JOIN ... WHERE id IS NULL or NOT EXISTS
“Consecutive days/rows” LAG/LEAD LAG(date) OVER (ORDER BY date)
“Running total” Window SUM SUM() OVER (ORDER BY date ROWS UNBOUNDED PRECEDING)
“Moving average” Window AVG AVG() OVER (ROWS BETWEEN N PRECEDING AND CURRENT ROW)
“Growth / change” LAG on aggregation LAG(metric) OVER (ORDER BY period)
“Percentage of total” Window SUM denominator val / SUM(val) OVER (PARTITION BY grp)
“Find pairs” Self-join with < JOIN table t2 ON t1.id < t2.id
“Find gaps” LEAD LEAD(id) OVER (ORDER BY id) - id > 1
“Every X” COUNT DISTINCT + compare HAVING COUNT(DISTINCT month) = total_months
“Pivot” CASE WHEN in SUM SUM(CASE WHEN col = 'val' THEN amt END)
“Complex multi-step” CTEs WITH step1 AS (...), step2 AS (...) SELECT ...

Final Tips for SQL Interviews

  1. Clarify before coding — ask about edge cases (NULLs, ties, empty results) before writing the query. Interviewers WANT you to ask.

  2. Start with the approach, not the syntax — say “I will use a window function with PARTITION BY department” before writing SQL. Show your thinking.

  3. Write step by step — do not try to write the perfect query in one shot. Start with the inner query, verify it works, then build outward. Use CTEs to make this visible.

  4. Handle NULLs explicitly — mention how your query handles NULLs. “If manager_id is NULL, this LEFT JOIN will include them with NULL manager columns.”

  5. Consider performance — after solving, mention: “For a large table, I would add an index on department and salary.” Shows production awareness.

  6. Know your ranking functions — ROW_NUMBER vs RANK vs DENSE_RANK is asked in 80% of SQL interviews. Know the difference cold.

  7. Practice the self-join — “employees earning more than their manager” is the #1 SQL interview question across all companies. Practice until it is automatic.

  8. Use CTEs over nested subqueries — CTEs are more readable, easier to debug live, and interviewers can follow your logic step by step.

  9. Talk about alternatives — after solving with one approach, mention: “This can also be solved with a correlated subquery, but the window function approach is more efficient.” Shows depth.

  10. Test with edge cases mentally — after writing, walk through: “What if there is only one employee in the department? What if all salaries are the same? What if the table is empty?”

Related posts:SQL Execution Order & WHERE ClausesSQL JoinsSQL Window FunctionsSubqueries & PerformanceCTEs & SubqueriesTop 20 Data Engineering Interview Questions


Naveen Vuppula is a Senior Data Engineering Consultant and app developer based in Ontario, Canada. He writes about Python, SQL, AWS, Azure, and everything data engineering at DriveDataScience.com.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top
Share via
Copy link