TechByteByByte

RAG with Structured Data & Tables

Recognizing when the right answer to 'where should this data live' is a SQL database, not a vector store at all — and handling tables really well when they must live in RAG.

#RAG#AI#Structured Data#SQL#Level 7

Begin with the problem

Tables and databases contain relationships that plain text chunks can damage. Structured-data RAG preserves rows, columns, types, and executable query boundaries.

question → choose specialized retrieval path → collect multimodal/structured evidence → answer

What you will learn

  • Explain RAG with Structured Data & Tables in simple language before using its technical details.
  • Follow the mechanism step by step through a small RAG example.
  • Connect this topic to the modules before and after it.
  • Decide when to use it, when not to use it, and what to measure in production.

Current real-system grounding: Google’s current File Search documentation includes file-based grounding and multimodal retrieval capabilities, with model, file-type, and tool-combination limitations.

The product example proves that the pattern is used in a real system. It does not mean every provider uses the same hidden algorithm, defaults, limits, or pricing.

1. The problem this module solves

Every prior module assumed knowledge belongs in a vector database. This module challenges that assumption directly — some knowledge is really better served by a traditional structured data source, and routing correctly between them is a real, practical architectural decision this course would be incomplete without.


2. The Problem — Not All Knowledge Belongs in a Vector Database

Question: "What was our total sales revenue in Q2?"

This is REALLY a precise, aggregation-style question -- it has
ONE correct, computable answer, derivable from structured records
(a sales database).

Semantic search over TEXT CHUNKS is really the WRONG tool here --
even if you had a document SUMMARIZING Q2 sales in prose, a SQL query
against the actual underlying data is more RELIABLE, more PRECISE,
and really easier to keep CURRENT than maintaining a text summary
document.

3. Text-to-SQL — A Really Different RAG-Adjacent Pattern

Natural Language Question

QUERY GENERATION (an LLM call, translating natural language into
                  SQL)

SQL

Execute against the DATABASE

Result (precise, structured data)

LLM (formats the raw result into a natural-language answer)
"What was our total sales revenue in Q2?"

SELECT SUM(revenue) FROM sales WHERE quarter = 'Q2'

$847,320

"Total sales revenue in Q2 was $847,320."

Notice: this is structurally similar to RAG’s core pattern (retrieve information, then generate a natural-language answer) — but the “retrieval” step is a SQL query against structured data, not a vector similarity search against text chunks (Modules 10-18).


4. The Real Decision Framework

Is the question about a SPECIFIC, PRECISE, computable value (a sum,
count, average, or exact record lookup)?
   YES -> Structured data / SQL is likely the better tool

Is the question about CONCEPTUAL, EXPLANATORY, or POLICY-type
content (what does X mean, why does Y happen, what's our approach
to Z)?
   YES -> Standard RAG (Modules 10-27) is likely the better tool

Does the question REALLY need BOTH (e.g., "summarize our Q2
performance and explain what drove the change")?
   -> HYBRID: structured query for the NUMBERS, RAG retrieval for
      the EXPLANATORY context, combined at generation time

5. Table Retrieval — When Tables Must Live IN a RAG System

Sometimes tabular data really belongs alongside unstructured content (e.g., a table embedded within a policy document, rather than a really separate database). Recall Module 6’s parsing challenge directly:

| Country | Limit  |
|---------|--------|
| India   | ₹5,000 |
| US      | $200   |
| UK      | £150   |

Naively flattening this to plain text for embedding LOSES the
explicit relationship between each country and its specific limit
(exactly Module 6's Section 5 warning).
Better approach: convert EACH ROW into a CLEAR, standalone sentence
                before chunking and embedding -- exactly Module 6's
                "restructure_flattened_table" fix, revisited here in
                the RAG-retrieval context:

"For India, the limit is ₹5,000."
"For the US, the limit is $200."
"For the UK, the limit is £150."

This makes each row independently retrievable and really meaningful — directly connecting Module 6’s parsing-stage fix to this module’s retrieval-stage benefit.


6. A Real Developer Example

TechCorp's finance assistant needs to answer BOTH:

"What was our exact Q2 revenue?" -> STRUCTURED (SQL query against the
                                    finance database) -- a precise,
                                    computable answer

"Why did our Q2 revenue increase compared to Q1?" -> RAG (retrieve
                                                     the actual
                                                     quarterly
                                                     business review
                                                     document
                                                     explaining
                                                     what drove the
                                                     change)

"Summarize our Q2 performance" -> HYBRID: SQL query for the exact
                                  numbers + RAG retrieval for
                                  qualitative context, COMBINED into
                                  one coherent, accurate summary

7. A Simple Agentic AI Connection

An agent equipped with BOTH a SQL query tool and a RAG search tool directly embodies this module’s decision framework in practice — really choosing between precise structured lookups and semantic retrieval based on what a specific sub-question actually requires, exactly the kind of tool-selection reasoning your Generative AI course covered for agents generally.


8. How Is This Used in AI?

🤖 How Is This Used in AI?

Production business intelligence and analytics assistants routinely combine text-to-SQL with standard RAG retrieval — recognizing that precise numerical questions and conceptual/explanatory questions really need different underlying data sources and retrieval mechanisms, rather than forcing everything through a single, uniform pipeline.


9. Real-World Applications

  • Business intelligence assistants combining precise metrics with qualitative explanation
  • Customer support systems needing both exact account data (structured) and policy explanations (unstructured)
  • Any application where both “give me the exact number” and “explain the context” questions really coexist

10. Common Mistakes

Incorrect idea: Forcing precise, computable questions through vector-based RAG.

Why it is incorrect: As shown directly in Section 2, this is really less reliable and harder to keep current than a direct structured query.

Incorrect idea: Naively flattening tables into plain text before embedding.

Why it is incorrect: As shown directly in Section 5 (and Module 6), this really loses important row-level relationships.

Incorrect idea: Assuming every application needs only ONE retrieval mechanism.

Why it is incorrect: As shown directly in Section 6, real applications often really need both structured and unstructured retrieval, routed appropriately per question.


11. Limitations

  • Text-to-SQL generation isn’t perfectly reliable — really complex queries may require careful prompt engineering (your Prompt Engineering course) or validation before execution, especially given the real risk of a malformed or unintended query
  • Combining structured and unstructured retrieval into one coherent answer adds real architectural complexity beyond either approach alone

12. Quick Reference — The Whole Idea in One Diagram

PRECISE, COMPUTABLE question           ->      SQL / structured
(sums, counts, exact records)                data query

CONCEPTUAL, EXPLANATORY question          ->      Standard RAG
(policy, "why," "how")                          (Modules 10-27)

BOTH needed                                  ->      HYBRID: SQL for
                                                    numbers + RAG for
                                                    context, combined

Tables WITHIN unstructured docs                  ->      restructure
                                                        each row into
                                                        a clear
                                                        sentence
                                                        BEFORE
                                                        chunking
                                                        (Module 6)

13. Code — Implementing Query Routing and Table Restructuring

🎯 Target of this example: implement Section 4’s decision framework directly — routing really different question types to the appropriate retrieval mechanism, and applying Section 5’s table restructuring fix to make tabular data properly retrievable.

Example 1 — Simple

def route_query(question: str) -> str:
    """Directly implements Section 4's decision framework -- routing
    based on whether a question signals a PRECISE, computable need
    versus a CONCEPTUAL, explanatory need."""
    structured_signals = ["total", "sum", "average", "count", "revenue", "how many", "exact"]
    question_lower = question.lower()
    if any(signal in question_lower for signal in structured_signals):
        return "structured_data_query"
    return "unstructured_rag_retrieval"

questions = [
    "What was the total sales revenue in Q2?",
    "What is our reimbursement policy for international travel?",
    "How many employees are in the Engineering department?",
]

for q in questions:
    route = route_query(q)
    print(f"'{q}'\n  -> {route}\n")

Expected Output:

'What was the total sales revenue in Q2?'
  -> structured_data_query

'What is our reimbursement policy for international travel?'
  -> unstructured_rag_retrieval

'How many employees are in the Engineering department?'
  -> structured_data_query

What we conclude from this example: really computable questions (“total,” “how many”) correctly route to structured data, while conceptual policy questions correctly route to standard RAG — exactly Section 4’s decision framework, made into a concrete routing function.

Example 2 — Intermediate

def restructure_table_row(headers: list, row_values: list) -> str:
    """Directly implements Section 5's table-restructuring fix --
    converting one table row into a clear, standalone, independently
    retrievable sentence, exactly reversing Module 6's flattening
    problem."""
    return ", ".join(f"{headers[i]}: {row_values[i]}" for i in range(len(headers)))

headers = ["Country", "Limit"]
table_rows = [
    ["India", "₹5,000"],
    ["US", "$200"],
    ["UK", "£150"],
]

restructured_chunks = [restructure_table_row(headers, row) for row in table_rows]
print("Restructured, independently retrievable chunks:")
for chunk in restructured_chunks:
    print(f"  - {chunk}")

Expected Output:

Restructured, independently retrievable chunks:
  - Country: India, Limit: ₹5,000
  - Country: US, Limit: $200
  - Country: UK, Limit: £150

What we conclude from this example: each row is now an independently meaningful, retrievable statement that preserves the exact relationship between country and limit — exactly Section 5’s fix, ready to be chunked (Module 7) and embedded (Module 10) without losing the table’s real structure.

Example 3 — Production Grade

from dataclasses import dataclass
from enum import Enum

class RetrievalRoute(Enum):
    STRUCTURED = "structured_data_query"
    UNSTRUCTURED = "unstructured_rag_retrieval"
    HYBRID = "hybrid_structured_and_unstructured"

@dataclass
class RoutingDecision:
    question: str
    route: RetrievalRoute
    rationale: str

class HybridQueryRouter:
    """A production-style router implementing Section 4's FULL
    framework, INCLUDING the hybrid case -- Section 6's real
    developer example, generalized into reusable routing logic."""

    STRUCTURED_SIGNALS = ["total", "sum", "average", "count", "revenue", "how many", "exact"]
    EXPLANATORY_SIGNALS = ["why", "explain", "how did", "what drove"]

    def route(self, question: str) -> RoutingDecision:
        question_lower = question.lower()
        has_structured_signal = any(s in question_lower for s in self.STRUCTURED_SIGNALS)
        has_explanatory_signal = any(s in question_lower for s in self.EXPLANATORY_SIGNALS)

        if has_structured_signal and has_explanatory_signal:
            return RoutingDecision(
                question=question, route=RetrievalRoute.HYBRID,
                rationale="Needs BOTH precise numbers (SQL) AND explanatory context (RAG).")
        elif has_structured_signal:
            return RoutingDecision(
                question=question, route=RetrievalRoute.STRUCTURED,
                rationale="Precise, computable value needed -- structured query is more reliable.")
        else:
            return RoutingDecision(
                question=question, route=RetrievalRoute.UNSTRUCTURED,
                rationale="Conceptual/explanatory content -- standard RAG retrieval fits.")

router = HybridQueryRouter()

questions = [
    "What was our exact Q2 revenue?",
    "Why did our Q2 revenue increase compared to Q1?",
    "What is our travel reimbursement policy?",
]

for q in questions:
    decision = router.route(q)
    print(f"'{q}'")
    print(f"  Route: {decision.route.value}")
    print(f"  Rationale: {decision.rationale}\n")

Expected Output:

'What was our exact Q2 revenue?'
  Route: structured_data_query
  Rationale: Precise, computable value needed -- structured query is
  more reliable.

'Why did our Q2 revenue increase compared to Q1?'
  Route: hybrid_structured_and_unstructured
  Rationale: Needs BOTH precise numbers (SQL) AND explanatory context
  (RAG).

'What is our travel reimbursement policy?'
  Route: unstructured_rag_retrieval
  Rationale: Conceptual/explanatory content -- standard RAG retrieval
  fits.

What we conclude from this example: the router correctly identifies the second question as really needing BOTH structured and unstructured retrieval (it mentions “revenue” AND asks “why”), routing it to the hybrid path — exactly Section 6’s third real developer example, now implemented as reusable, automated routing logic rather than manual, case-by-case judgment.


14. Interview Questions

Q: Why is a SQL query against a structured database generally more reliable than RAG-based retrieval for answering “what was our total sales revenue in Q2?”

Ans: This question has one correct, computable answer derivable directly from structured records — a SQL aggregation query. Semantic retrieval over text chunks (even a document summarizing Q2 sales) is a really less reliable and harder-to-maintain approach, since it would depend on someone having written and kept current a prose summary, rather than querying the actual underlying data directly and precisely.

Q: Describe the text-to-SQL pattern and explain how it relates structurally to standard RAG.

Ans: Text-to-SQL translates a natural language question into a SQL query using an LLM, executes that query against a structured database, and then uses an LLM again to format the raw structured result into a natural-language answer. This is structurally similar to RAG’s core pattern — retrieve relevant information, then generate a natural- language response — but the “retrieval” step is a precise SQL query against structured data rather than a vector similarity search against text chunks.

Q: Why does naively flattening a table into plain text before embedding lose important information, and what’s the fix?

Ans: Flattening a table by simply reading cell values in sequence loses the explicit relationships between rows and columns — for example, it becomes unclear which specific limit corresponds to which specific country. The fix is restructuring each row into a clear, standalone sentence explicitly stating the relationship (like “Country: India, Limit: ₹5,000”) before chunking and embedding, so each row remains independently meaningful and retrievable without losing its original tabular relationships.

Q: Design a routing strategy for a business intelligence assistant that needs to handle both precise numerical questions and questions that really require both numbers and explanation.

Ans: I’d detect signals in the question indicating a need for precise, computable values (words like “total,” “how many,” “exact”) separately from signals indicating a need for explanatory context (words like “why,” “explain,” “what drove”). If only structured signals are present, route to a SQL query. If only explanatory signals are present, route to standard RAG retrieval. If both signal types are present — like “why did revenue increase” — route to a hybrid approach, executing both a structured query for the precise numbers and a RAG retrieval for qualitative context, then combining both results into one coherent generated answer.


15. What You Should Remember

  • Precise, computable questions really belong in structured data (SQL), not vector-based RAG — verified directly through a routing function correctly distinguishing computable from conceptual questions.
  • Text-to-SQL structurally mirrors RAG’s retrieve-then-generate pattern, just with a SQL query instead of vector search as the retrieval mechanism.
  • Tables should be restructured into clear, standalone sentences before chunking — verified directly by converting a table into independently retrievable, relationship-preserving statements.

16. Quick Practice

For a customer support assistant handling both “what’s my current account balance” and “why was I charged this fee,” design a routing strategy using this module’s framework — which question needs structured data, which needs RAG, and does either really need both?

17. Next Step

Next: Module 31 — Multimodal RAG — closing Level 7: extending retrieval beyond text to PDFs, web content, and code repositories, each with really distinct handling requirements.

Author
TechByteByByte Editorial Team
Reviewed by
TechByteByByte Admin
Published
Last reviewed