Skip to main content

Overview

The present_sql tool parses, validates, and presents SQL queries in a structured format. It’s designed for building alerts, saved queries, and iterative query construction workflows.
This tool does NOT execute queries. It validates and structures them for user review or storage. Use execute_query for running queries.

When to use

Use present_sql when:
  • Creating an alert that will run on a schedule
  • Saving a query for later use
  • Building a query iteratively with user feedback
  • Validating query structure before execution
  • Presenting query details to users for approval

Prerequisites

You must call prepare_gdelt_query BEFORE using this tool to ensure you’re building with correct schemas.

Parameters

query
string
required
SQL query to parse and present. Should be built after calling prepare_gdelt_query.Must include same requirements as execute_query:
  • Date filter (e.g., WHERE day >= today() - INTERVAL 7 DAY)
  • LIMIT clause (maximum 1000)
  • Source URL column (source_url or document_identifier)
SELECT 
    day, 
    actor1_name, 
    event_code, 
    source_url
FROM gdelt_events
WHERE day >= today() - INTERVAL 7 DAY
    AND event_root_code = '14'
LIMIT 100
description
string
required
Natural language description of what this query does.Examples:
  • “Find protests in France over the last 7 days”
  • “Track climate change articles with high negative tone”
  • “Monitor China-Taiwan military events”
This description will be shown to users when displaying the alert or saved query.
query_title
string
Concise title for this query (e.g., ‘Climate Protests in Europe’, ‘US Political Events’).Example: “France Protest Monitor”
A clear title helps users quickly identify the query purpose, especially when managing multiple alerts.

Response

Returns a PresentSqlResult object with detailed query analysis:
sql
string
required
The complete SQL query (echoed back).
description
string
required
The natural language description you provided.
tables
array
required
List of tables referenced in the query.
["gdelt_events", "gdelt_mentions"]
Automatically parsed from the FROM and JOIN clauses.
columns_returned
array
required
List of columns in the SELECT clause.
["day", "actor1_name", "event_code", "source_url"]
Helps users understand what data they’ll receive.
filters_applied
array
required
List of filters from the WHERE clause.
[
  "day >= today() - INTERVAL 7 DAY",
  "event_root_code = '14'",
  "action_geo_country_code = 'FR'"
]
Shows users exactly what filtering logic is being applied.
validation_passed
boolean
required
Whether the query passed all validation checks.true if all requirements met, false if issues found.
validation_message
string
Detailed validation results or error message.Explains what passed/failed and provides guidance for fixes.

Usage examples

# After calling prepare_gdelt_query
present_sql(
    query="""
        SELECT 
            day,
            actor1_name,
            actor2_name,
            event_code,
            goldstein_scale,
            source_url
        FROM gdelt_events
        WHERE day >= today() - INTERVAL 7 DAY
            AND event_root_code = '14'
            AND action_geo_country_code = 'FR'
        ORDER BY day DESC
        LIMIT 100
    """,
    description="Track protests in France over the last 7 days",
    query_title="France Protest Monitor"
)

Query workflow for alerts

1

Prepare query context

Call prepare_gdelt_query to get schemas and codes.
prepare_gdelt_query(
    tables=["gdelt_events"],
    include_cameo_event_codes=True,
    include_fips_country_codes=True
)
2

Build SQL query

Construct your SELECT query with:
  • Appropriate date filter for the alert frequency
  • Required LIMIT clause
  • Source URL column
  • Filters that define what you’re monitoring
SELECT day, actor1_name, event_code, source_url
FROM gdelt_events
WHERE day >= today() - INTERVAL 1 DAY
    AND event_root_code = '14'
LIMIT 200
3

Present and validate

Call present_sql with descriptive information.
result = present_sql(
    query="SELECT...",
    description="Daily protests worldwide",
    query_title="Global Protest Monitor"
)
Query is parsed, validated, and ready for review.
4

Review or iterate

Check validation results:
  • If validation_passed = true → proceed to create alert
  • If validation_passed = false → review validation_message and adjust query

Validation rules

Requirement: Must include date/time filter in WHERE clauseChecked patterns:
  • WHERE day >= today() - INTERVAL X DAY
  • WHERE date_time >= now() - INTERVAL X HOUR
  • WHERE day BETWEEN ... AND ...
Alert-specific guidance:
  • Daily alerts: Use day >= today() - INTERVAL 1 DAY
  • Hourly alerts: Use date_time >= now() - INTERVAL 1 HOUR
  • Weekly alerts: Use day >= today() - INTERVAL 7 DAY
Requirement: Must include LIMIT (max 1000)Valid: LIMIT 100, LIMIT 500, LIMIT 1000For alerts: Consider your expected result volume:
  • High-frequency events: Use lower limits (50-100)
  • Rare events: Can use higher limits (500-1000)
Requirement: Must select source_url or document_identifierWhy for alerts: Users need to click through to original articles when they receive notifications.
Requirement: Only use valid GDELT table namesValid tables:
  • gdelt_events
  • gdelt_mentions
  • mv_event_mention_stats
  • gdelt_gkg_themes_extracted
  • gdelt_gkg_persons_extracted
  • gdelt_gkg_organizations_extracted
  • gdelt_gkg_locations_extracted
  • gdelt_persons_master
  • gdelt_organizations_master

Parsed output explanation

Tables parsed

Extracted from FROM and JOIN clauses. Helps users understand data sources. Example query:
FROM gdelt_events e
JOIN gdelt_mentions m ON e.event_id = m.event_id
Parsed tables:
["gdelt_events", "gdelt_mentions"]

Columns returned

Extracted from SELECT clause. Shows what data users will receive. Example query:
SELECT day, actor1_name, event_code, source_url
Parsed columns:
["day", "actor1_name", "event_code", "source_url"]

Filters applied

Extracted from WHERE clause. Documents the filtering logic. Example query:
WHERE day >= today() - INTERVAL 7 DAY
    AND event_root_code = '14'
    AND actor1_country_code = 'USA'
Parsed filters:
[
  "day >= today() - INTERVAL 7 DAY",
  "event_root_code = '14'",
  "actor1_country_code = 'USA'"
]

Alert creation patterns

Daily protest monitor

present_sql(
    query="""
        SELECT 
            day, action_geo_country_code,
            actor1_name, event_code, source_url
        FROM gdelt_events
        WHERE day >= today() - INTERVAL 1 DAY
            AND event_root_code = '14'
        ORDER BY day DESC
        LIMIT 200
    """,
    description="Daily global protests",
    query_title="Global Protest Monitor"
)
present_sql(
    query="""
        SELECT 
            event_id, event_date, mention_count, source_count
        FROM mv_event_mention_stats
        WHERE day = today()
            AND mention_count >= 50
        ORDER BY mention_count DESC
        LIMIT 100
    """,
    description="Hourly viral events with 50+ mentions",
    query_title="Viral Events Tracker"
)

Weekly theme tracker

present_sql(
    query="""
        SELECT 
            day, theme, document_identifier, tone
        FROM gdelt_gkg_themes_extracted
        WHERE day >= today() - INTERVAL 7 DAY
            AND theme LIKE 'HEALTH_COVID%'
        ORDER BY day DESC
        LIMIT 1000
    """,
    description="Weekly COVID-related articles",
    query_title="COVID News Tracker"
)

Person mention alert

present_sql(
    query="""
        SELECT 
            day, person_name, document_identifier
        FROM gdelt_gkg_persons_extracted
        WHERE day >= today() - INTERVAL 1 DAY
            AND person_name IN ('Elon Musk', 'Mark Zuckerberg')
        LIMIT 500
    """,
    description="Daily tech CEO mentions",
    query_title="Tech CEO Monitor"
)

Iterative query building

1

Start with simple query

Begin with basic filters to understand data volume.
present_sql(
    query="SELECT day, event_code, source_url FROM gdelt_events WHERE day >= today() - INTERVAL 1 DAY LIMIT 1000",
    description="All events from today"
)
Check columns_returned and filters_applied to verify structure.
2

Add specific filters

Refine based on initial results.
present_sql(
    query="SELECT day, event_code, actor1_country_code, source_url FROM gdelt_events WHERE day >= today() - INTERVAL 1 DAY AND event_root_code = '14' LIMIT 500",
    description="Protests from today"
)
Review filters_applied to ensure logic is correct.
3

Optimize and finalize

Adjust LIMIT, add ORDER BY, include title.
present_sql(
    query="SELECT day, event_code, actor1_country_code, goldstein_scale, source_url FROM gdelt_events WHERE day >= today() - INTERVAL 1 DAY AND event_root_code = '14' ORDER BY goldstein_scale ASC LIMIT 200",
    description="Daily protests ordered by intensity",
    query_title="Protest Intensity Monitor"
)
Query is validated and ready for alert creation.

Best practices

Write clear descriptions - Users will see these when managing their alerts. Be specific about what the query monitors.
Match date filter to alert frequency - Daily alerts should use INTERVAL 1 DAY, hourly should use INTERVAL 1 HOUR.
Include query_title when creating alerts - A clear title helps users identify and manage their alerts more easily.
Don’t over-filter - Start broad and narrow down based on results. Too many filters might miss relevant events.
Verify before creating alert - Always check validation_passed is true before proceeding to alert creation.

Error handling

Validation message: “Query must include date filter”Solution: Add WHERE clause with date/time comparison:
WHERE day >= today() - INTERVAL 1 DAY
Validation message: “Query must include LIMIT clause”Solution: Add LIMIT at end of query:
LIMIT 100
Validation message: “Query must select source_url or document_identifier”Solution: Include in SELECT clause:
SELECT day, event_code, source_url FROM...
Validation message: “Table ‘xyz’ not found in GDELT schema”Solution: Use only valid table names from the 9 available GDELT tables.

Next steps