ANI

SQL vs Pandas vs AI Agents: Which Solves the Most Analytics Problems?

# Introduction

We have given three similar interview questions from StrataScratch in SQL, Pandasand a Claude agent. Every piece of code is run against the same dataset, and each time number is the average over 500 runs. The agent's responses are exactly what Claude produces in response to written information, rather than a hypothetical example of what the agent might produce.

The comparison applies to all eight dimensions: speed, accuracy, definition, error correction, scalability, flexibility, risk of omission, and readiness for production. The three questions take the difficulty levels of easy, medium, and hard. The more complex the query, the more significant differences between SQL, Pandas, and agents become apparent.

# How We Ran This Comparison

The three questions come from the StrataScratch interview bank and cover easy, medium, and hard difficulty levels. SQL continued SQLite in memory, timed over 500 runs, the median is taken. Pandas worked on the same dataset Python 3.12, and over 500 runs. Claude's agent claude-sonnet-4-6called Anthropic API.

SQL vs Pandas vs AI Agents

Each query has its own schema-based information that includes table names, column names, and a few sample rows. The system command below remains the same for all three calls. Agent response times are measured from the time a request is sent to the first token received.

# Simple Retrieval: All Three Agree

In the first interview question from Meta, users are asked to find every user who has done at least one scroll_up event and return unique user IDs. The data resides in a single table called facebook_web_log.

// The data

Here it is facebook_web_log the table.

User ID time stamp action
0 2019-04-25 13:30:15 page_load
0 2019-04-25 13:30:18 page_load
0 2019-04-25 13:30:40 scroll_down
0 2019-04-25 13:30:45 scroll_up
0 2019-04-25 13:30:40 exit_page

// SQL Coding Solution (0.002 ms)

SELECT DISTINCT user_id
FROM facebook_web_log
WHERE action = 'scroll_up';

// Pandas Coding Solution (0.40 ms)

import pandas as pd
result = (
    facebook_web_log[facebook_web_log['action'] == 'scroll_up']
    .drop_duplicates(subset="user_id")[['user_id']]
)

// Agent Prompt

Table: facebook_web_log (user_id INTEGER, action TEXT, timestamp TEXT)
Sample rows:
(1, 'scroll_up',   '2019-01-01 00:00:00')
(2, 'scroll_down', '2019-01-01 00:01:00')
(3, 'like',        '2019-01-01 00:03:00')
(2, 'scroll_up',   '2019-01-01 00:04:00')
Question: Find all users who performed at least one scroll_up event.
Return distinct user IDs.

// Agent output (2 seconds)

SELECT DISTINCT user_id
FROM facebook_web_log
WHERE action = 'scroll_up';

Output: All three return users 1 and 2.

In the single filter problem, the agent is exactly the same as SQL. The only real danger in this difficulty is naming the columns. Without the schema at the prompt, action may return as event_type or event_namereturning nothing and making no mistake.

# Multi-Step Integration: When Schema Grounding Matters

The second question is about product feature completion. The app tracks how far each user gets through a set of product features, where each feature has a fixed number of steps.

The task is to calculate the average completion percentage of each feature for all users, where the user's completion is their highest step reached divided by the number of steps for that feature, times 100. Users who never started a feature were counted as 0% completion.

Two tables feed this: facebook_product_features:

attribute_identity n_steps
0 5
1 7
2 3

again facebook_product_features_realizations.

attribute_identity User ID step_reached time stamp
0 0 1 2019-03-11 17:15:00
0 0 2 2019-03-11 17:22:00
0 0 3 2019-03-11 17:25:00
0 0 4 2019-03-11 17:27:00
1 1 3 2019-04-05 13:00:07

// SQL Coding Solution (0.007 ms)

WITH max_step AS (
    SELECT
        feature_id,
        user_id,
        MAX(step_reached) AS max_step_reached
    FROM facebook_product_features_realizations
    GROUP BY feature_id, user_id
),
calc_per_feature AS (
    SELECT
        feats.feature_id,
        n_steps,
        max_step_reached,
        COALESCE(max_step_reached, 0) * 1.0 / n_steps AS share_of_completion
    FROM facebook_product_features feats
    LEFT OUTER JOIN max_step
        ON feats.feature_id = max_step.feature_id
)
SELECT
    feature_id,
    AVG(share_of_completion) * 100 AS avg_share_of_completion
FROM calc_per_feature
GROUP BY feature_id;

// Pandas Coding Solution (2.05 ms)

import pandas as pd
# max step per user per feature
max_step = (
    facebook_product_features_realizations
    .groupby(['feature_id', 'user_id'])['step_reached']
    .max()
    .reset_index()
)

# join to features, fill users who never started with 0
df = pd.merge(
    facebook_product_features,
    max_step,
    how='outer',
    on='feature_id'
).fillna(0)

# completion % per user-feature row
df['share_of_completion'] = (df['step_reached'] / df['n_steps']) * 100

# average per feature
result = (
    df.groupby('feature_id')['share_of_completion']
    .mean()
    .to_frame('avg_share_of_completion')
    .reset_index()
)

// Agent Prompt

Tables:
- facebook_product_features (feature_id INTEGER, n_steps INTEGER)
- facebook_product_features_realizations
  (feature_id INTEGER, user_id INTEGER, step_reached INTEGER, timestamp TEXT)
Question: For each feature, calculate the average completion percentage
across all users. A user's completion = max(step_reached) / n_steps * 100.
Users who never started count as 0% completion.
Return: feature_id, avg_share_of_completion.

// Agent output (3 seconds)

WITH user_max_steps AS (
    SELECT feature_id, user_id, MAX(step_reached) AS max_step
    FROM facebook_product_features_realizations
    GROUP BY feature_id, user_id
)
SELECT
    f.feature_id,
    ROUND(AVG(COALESCE(ums.max_step, 0) * 100.0 / f.n_steps), 2) AS avg_share_of_completion
FROM facebook_product_features f
LEFT JOIN user_max_steps ums ON f.feature_id = ums.feature_id
GROUP BY f.feature_id
ORDER BY f.feature_id;

Output: All three return the same numbers.

attribute_identity completion_share_rate
0 80
2 0
1 76.19

The agent got it here because the information said: “Users who have never started count as 0% completion. That expression is loaded. Without it, the agent writes an inner join – which drops non-starters – and the whole average goes up. That failure is silent. The numbers come back clean, and they are wrong. You will need to know the expected output to catch it.

# Multiple Tables and Window Concept: All Three Are Good, One is Too Slow

The third question covers Meta's data center energy consumption across the three regions. Each region has its own table: fb_eu_energy, fb_na_energyagain fb_asia_energy.

The function is to sum, the total usage by date, and produce two columns obtained: the active cumulative total and that total as a percentage of the total amount, rounded to the total amount.

// The data

Each state table has the same shape.

fb_eu_energy:

recorded_date use
2020-01-01 400
2020-01-02 350
2020-01-03 500
2020-01-04 500
2020-01-07 600

fb_na_energy:

recorded_date use
2020-01-01 250
2020-01-02 375
2020-01-03 600
2020-01-06 500
2020-01-07 250

fb_asia_energy:

recorded_date use
2020-01-01 400
2020-01-02 400
2020-01-04 675
2020-01-05 1200
2020-01-06 750
2020-01-07 400

// SQL Coding Solution (0.010 ms)

WITH total_energy AS (
    SELECT recorded_date, consumption FROM fb_eu_energy
    UNION ALL
    SELECT recorded_date, consumption FROM fb_asia_energy
    UNION ALL
    SELECT recorded_date, consumption FROM fb_na_energy
),
energy_by_date AS (
    SELECT
        recorded_date,
        SUM(consumption) AS total_energy
    FROM total_energy
    GROUP BY recorded_date
    ORDER BY recorded_date ASC
)
SELECT
    recorded_date,
    SUM(total_energy) OVER (
        ORDER BY recorded_date ASC
    ) AS cumulative_total_energy,
    ROUND(
        SUM(total_energy) OVER (ORDER BY recorded_date ASC) * 100.0
        / (SELECT SUM(total_energy) FROM energy_by_date),
        0
    ) AS percentage_of_total_energy
FROM energy_by_date;

// Pandas Coding Solution (1.84 ms)

import pandas as pd
merged_df = pd.concat([fb_eu_energy, fb_asia_energy, fb_na_energy])

energy_by_date = (
    merged_df.groupby('recorded_date', as_index=False)['consumption']
    .sum()
    .sort_values('recorded_date')
)

energy_by_date['cumulative_total_energy'] = energy_by_date['consumption'].cumsum()
energy_by_date['percentage_of_total_energy'] = round(
    energy_by_date['cumulative_total_energy'] * 100 / energy_by_date['consumption'].sum()
)

energy_by_date['recorded_date'] = pd.to_datetime(
    energy_by_date['recorded_date']
).dt.strftime('%Y-%m-%d')

result = energy_by_date[
    ['recorded_date', 'cumulative_total_energy', 'percentage_of_total_energy']
]

// Agent Prompt

Tables:
- fb_eu_energy   (recorded_date TEXT, consumption INTEGER)
- fb_na_energy   (recorded_date TEXT, consumption INTEGER)
- fb_asia_energy (recorded_date TEXT, consumption INTEGER)
Question: Combine all three tables. Sum consumption by date. Output:
- recorded_date
- cumulative_total_energy (running sum across dates, ordered by date)
- percentage_of_total_energy (running cumulative / grand total * 100,
  rounded to the nearest whole number)

// Agent output (4 seconds)

WITH all_energy AS (
    SELECT recorded_date, consumption FROM fb_eu_energy
    UNION ALL
    SELECT recorded_date, consumption FROM fb_na_energy
    UNION ALL
    SELECT recorded_date, consumption FROM fb_asia_energy
),
daily_totals AS (
    SELECT recorded_date, SUM(consumption) AS daily_total
    FROM all_energy
    GROUP BY recorded_date
)
SELECT
    recorded_date,
    SUM(daily_total) OVER (ORDER BY recorded_date) AS cumulative_total_energy,
    ROUND(
        SUM(daily_total) OVER (ORDER BY recorded_date) * 100.0
        / SUM(daily_total) OVER (),
        0
    ) AS percentage_of_total_energy
FROM daily_totals
ORDER BY recorded_date;

Output: All three return the same table.

recorded_date cumulative_total_energy percent_of_total_power
2020-01-01 1050 13
2020-01-02 2175 27
2020-01-03 3275 40
2020-01-04 4450 55
2020-01-05 5650 69
2020-01-06 6900 85
2020-01-07 8150 100

The agent used SUM(daily_total) OVER () (window function with no ORDER BY) as a denominator instead of a scalar subquery in a SQL reference solution. Both methods work. The output is exactly the same.

# Three Comparisons

SQL vs Pandas vs AI Agents

// Speed

At this data scale, SQL ran at 0.002-0.010 ms, Pandas at 0.4-2.1 ms. The agent added 2-4 seconds of large language model (LLM) timeout before any SQL started.

The agent generates the code first; that generation time is the end of each query cycle. At warehouse scale, the gap closes to zero once the code is generated; SQL benefits further because it runs inside the database engine, and Pandas hits memory around 10 million rows and needs. Apache Spark or Timber beyond that.

// Accuracy and Risk of Hallucinations

SQL and Pandas are deterministic. The same code on the same data gives the same answer every time. With schema-based instructions, Claude got all three queries right, but each call produced different SQL names (different common table names (CTE), different column aliases, different but similar methods). Without a schema, the risk of hallucinations increases rapidly.

// Explanation and debugging

An SQL query is read in one block. A bad join situation appears in the text. Pandas requires Python fluently, but you can check it out DataFrame at each step. Agents explain their reasoning in English, and then display a code that you may or may not display. If the generated SQL is incorrect, you trace the error through the model's logic chain rather than reading the query you wrote.

// Flexibility and productivity readiness

Pandas is the clearest choice for custom transformations, branching, and iterative feature engineering. SQL handles logical setup cleanly and gets verbose for procedure work. Agents respond to requests in plain English, with very little consistency when the schemas are complex or ambiguous. For deployment, SQL is the most proven option for analytics; Pandas are experimentally reliable; and agents are trusted today with low-cost inquiries or when your output is reviewed before it starts.

# What Agent Results Really Show

With schema-based information, Claude got all three correct: Easy, Medium, and Hard. The SQL agent for the complex query used a different window operation pattern than the reference solution and still returned the correct table.

Two factors limit that finding. First, reproducibility: each API call can return different SQL for the same query. The concept is the same, but the team that reviews the queries generated by the agent needs to validate the output instead of hoping that the correct implementation will be the same as the next one. Second, it depends on the schema: the above commands include table and column names, as well as sample rows. Remove those, and the agent is guessing.

On easy difficulty, wrong guesses produce a null result. On Hard Difficulty, a wrong guess produces an unerringly wrong result.

A working pattern is: provide the full schema, invoke the SQL, then run and validate the output before it goes downstream.

# The conclusion

SQL, Pandas, and Claude each received three analytical queries when used correctly. The difference is in speed (0.01 ms vs 4 seconds), reproduction, and what happens when you drop the context.

SQL equates to structured retrieval and logic based on millisecond usage and deterministic output. Pandas equates to customized changes and a step-by-step notebook running on nearly 10 million lines. The agent suits the questions of the first draft and the interim evaluation, with a complete program in the notification and the person who reviews the output.

SQL vs Pandas vs AI Agents

The agent got a tough question through SUM() OVER() instead of a scalar subquery, which is a valid option that the SQL index solution did not take. That's the honest version of this comparison: an agent can generate correct, intelligent SQL. It just adds a delay, it varies between runs, and it depends entirely on what you put in the notification.

Nate Rosidi he is a data scientist and product strategist. He is also an adjunct professor of statistics, and the founder of StrataScratch, a platform that helps data scientists prepare for their interviews with real interview questions from top companies. Nate writes about the latest trends in the job market, provides interview advice, shares data science projects, and covers all things SQL.

Source link

Related Articles

Leave a Reply

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

Back to top button