{
  "id": "sql_to_redis_queries",
  "title": "Write SQL Queries for Redis",
  "url": "https://redis.io/docs/latest/develop/ai/redisvl/0.15.0/user_guide/sql_to_redis_queries/",
  "summary": "",
  "content": "\n\nWhile Redis does not natively support SQL, RedisVL provides a `SQLQuery` class that translates SQL-like queries into Redis queries.\n\nThe `SQLQuery` class wraps the [`sql-redis`](https://pypi.org/project/sql-redis/) package. This package is not installed by default, so install it with:\n\n```bash\npip install redisvl[sql-redis]\n```\n\n## Prerequisites\n\nBefore you begin, ensure you have:\n- Installed RedisVL with SQL support: `pip install redisvl[sql-redis]`\n- A running Redis instance ([Redis 8+](https://redis.io/downloads/) or [Redis Cloud](https://redis.io/cloud))\n\n## What You'll Learn\n\nBy the end of this guide, you will be able to:\n- Write SQL-like queries for Redis using `SQLQuery`\n- Translate SELECT, WHERE, and ORDER BY clauses to Redis queries\n- Combine SQL queries with vector search\n- Use aggregate functions and grouping\n\n## Create an index to search\n\n\n```python\nfrom redisvl.utils.vectorize import HFTextVectorizer\n\nhf = HFTextVectorizer()\n\nschema = {\n    \"index\": {\n        \"name\": \"user_simple\",\n        \"prefix\": \"user_simple_docs\",\n        \"storage_type\": \"json\",\n    },\n    \"fields\": [\n        {\"name\": \"user\", \"type\": \"tag\"},\n        {\"name\": \"region\", \"type\": \"tag\"},\n        {\"name\": \"job\", \"type\": \"tag\"},\n        {\"name\": \"job_description\", \"type\": \"text\"},\n        {\"name\": \"age\", \"type\": \"numeric\"},\n        {\n            \"name\": \"job_embedding\",\n            \"type\": \"vector\",\n            \"attrs\": {\n                \"dims\": len(hf.embed(\"get embed length\")),\n                \"distance_metric\": \"cosine\",\n                \"algorithm\": \"flat\",\n                \"datatype\": \"float32\"\n            }\n        }\n    ]\n}\n```\n\n    /Users/tyler.hutcherson/Documents/AppliedAI/redis-vl-python/.venv/lib/python3.13/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n      from .autonotebook import tqdm as notebook_tqdm\n\n\n## Create sample dataset\n\n\n```python\ndata = [\n    {\n        'user': 'john',\n        'age': 34,\n        'job': 'software engineer',\n        'region': 'us-west',\n        'job_description': 'Designs, develops, and maintains software applications and systems.'\n    },\n    {\n        'user': 'bill',\n        'age': 54,\n        'job': 'engineer',\n        'region': 'us-central',\n        'job_description': 'Applies scientific and mathematical principles to solve technical problems.'\n    },\n    {\n        'user': 'mary',\n        'age': 24,\n        'job': 'doctor',\n        'region': 'us-central',\n        'job_description': 'Diagnoses and treats illnesses, injuries, and other medical conditions in the healthcare field.'\n    },\n    {\n        'user': 'joe',\n        'age': 27,\n        'job': 'dentist',\n        'region': 'us-east',\n        'job_description': 'Provides oral healthcare including diagnosing and treating teeth and gum issues.'\n    },\n    {\n        'user': 'stacy',\n        'age': 61,\n        'job': 'project manager',\n        'region': 'us-west',\n        'job_description': 'Plans, organizes, and oversees projects from inception to completion.'\n    }\n]\n\ndata = [\n    {  \n        **d,\n        \"job_embedding\": hf.embed(f\"{d['job_description']=} {d['job']=}\"),\n    } \n    for d in data\n]\n```\n\n## Create a `SearchIndex`\n\nWith the schema and sample dataset ready, create a `SearchIndex`.\n\n### Bring your own Redis connection instance\n\nThis is ideal in scenarios where you have custom settings on the connection instance or if your application will share a connection pool:\n\n\n```python\nfrom redisvl.index import SearchIndex\nfrom redis import Redis\n\nclient = Redis.from_url(\"redis://localhost:6379\")\nindex = SearchIndex.from_dict(schema, redis_client=client, validate_on_load=True)\n```\n\n### Let the index manage the connection instance\n\nThis is ideal for simple cases:\n\n\n```python\nindex = SearchIndex.from_dict(schema, redis_url=\"redis://localhost:6379\", validate_on_load=True)\n```\n\n### Create the index\n\nNow that we are connected to Redis, we need to run the create command.\n\n\n```python\nindex.create(overwrite=True, drop=True)\n```\n\n## Load Data to `SearchIndex`\n\nLoad the sample dataset to Redis.\n\n### Validate data entries on load\nRedisVL uses pydantic validation under the hood to ensure loaded data is valid and confirms to your schema. This setting is optional and can be configured in the `SearchIndex` class.\n\n\n```python\nkeys = index.load(data)\n\nprint(keys)\n```\n\n    ['user_simple_docs:01KHKJGG26AR3VW2RJA381R8YK', 'user_simple_docs:01KHKJGG2R8EZP6H15MG1V4E53', 'user_simple_docs:01KHKJGG369F5R0R51PW2HP8MV', 'user_simple_docs:01KHKJGG3MGVPAZ6XEQVEWXZFC', 'user_simple_docs:01KHKJGG44ZEKJVRQJ0EF72PV7']\n\n\n## Create a `SQLQuery` Object\n\nFirst, let's test a simple select statement such as the one below.\n\n\n```python\nfrom redisvl.query import SQLQuery\n\nsql_str = \"\"\"\n    SELECT user, region, job, age\n    FROM user_simple\n    WHERE age \u003e 17\n    \"\"\"\n\nsql_query = SQLQuery(sql_str) \n```\n\n## Check the created query string\n\n\n```python\nsql_query.redis_query_string(redis_url=\"redis://localhost:6379\")\n```\n\n\n\n\n    'FT.SEARCH user_simple \"@age:[(17 +inf]\" RETURN 4 user region job age'\n\n\n\n### Executing the query\n\n\n```python\nresults = index.query(sql_query)\nresults\n```\n\n\n\n\n    [{'user': 'john',\n      'region': 'us-west',\n      'job': 'software engineer',\n      'age': '34'},\n     {'user': 'bill', 'region': 'us-central', 'job': 'engineer', 'age': '54'},\n     {'user': 'mary', 'region': 'us-central', 'job': 'doctor', 'age': '24'},\n     {'user': 'joe', 'region': 'us-east', 'job': 'dentist', 'age': '27'},\n     {'user': 'stacy', 'region': 'us-west', 'job': 'project manager', 'age': '61'}]\n\n\n\n## Additional query support\n\n### Conditional operators\n\n\n```python\nsql_str = \"\"\"\n    SELECT user, region, job, age\n    FROM user_simple\n    WHERE age \u003e 17 and region = 'us-west'\n\"\"\"\n\nsql_query = SQLQuery(sql_str)\nredis_query = sql_query.redis_query_string(redis_url=\"redis://localhost:6379\")\nprint(\"Resulting redis query: \", redis_query)\nresults = index.query(sql_query)\nresults\n```\n\n    Resulting redis query:  FT.SEARCH user_simple \"@age:[(17 +inf] @region:{us\\-west}\" RETURN 4 user region job age\n\n\n\n\n\n    [{'user': 'john',\n      'region': 'us-west',\n      'job': 'software engineer',\n      'age': '34'},\n     {'user': 'stacy', 'region': 'us-west', 'job': 'project manager', 'age': '61'}]\n\n\n\n\n```python\nsql_str = \"\"\"\n    SELECT user, region, job, age\n    FROM user_simple\n    WHERE region = 'us-west' or region = 'us-central'\n    \"\"\"\n\nsql_query = SQLQuery(sql_str)\nredis_query = sql_query.redis_query_string(redis_url=\"redis://localhost:6379\")\nprint(\"Resulting redis query: \", redis_query)\nresults = index.query(sql_query)\nresults\n```\n\n    Resulting redis query:  FT.SEARCH user_simple \"((@region:{us\\-west})|(@region:{us\\-central}))\" RETURN 4 user region job age\n\n\n\n\n\n    [{'user': 'john',\n      'region': 'us-west',\n      'job': 'software engineer',\n      'age': '34'},\n     {'user': 'bill', 'region': 'us-central', 'job': 'engineer', 'age': '54'},\n     {'user': 'stacy', 'region': 'us-west', 'job': 'project manager', 'age': '61'},\n     {'user': 'mary', 'region': 'us-central', 'job': 'doctor', 'age': '24'}]\n\n\n\n\n```python\n# job is a tag field therefore this syntax works\nsql_str = \"\"\"\n    SELECT user, region, job, age\n    FROM user_simple\n    WHERE job IN ('software engineer', 'engineer', 'pancake tester')\n    \"\"\"\n\nsql_query = SQLQuery(sql_str)\nredis_query = sql_query.redis_query_string(redis_url=\"redis://localhost:6379\")\nprint(\"Resulting redis query: \", redis_query)\nresults = index.query(sql_query)\nresults\n```\n\n    Resulting redis query:  FT.SEARCH user_simple \"@job:{software engineer|engineer|pancake tester}\" RETURN 4 user region job age\n\n\n\n\n\n    [{'user': 'john',\n      'region': 'us-west',\n      'job': 'software engineer',\n      'age': '34'},\n     {'user': 'bill', 'region': 'us-central', 'job': 'engineer', 'age': '54'}]\n\n\n\n### Text based searches\n\nSee [the docs](https://redis.io/docs/latest/develop/ai/search-and-query/query/full-text/) for available text queries in Redis.\n\nFor more on exact matching see [here](https://redis.io/docs/latest/develop/ai/search-and-query/query/exact-match/)\n\n\n```python\n# Prefix\nsql_str = \"\"\"\n    SELECT user, region, job, job_description, age\n    FROM user_simple\n    WHERE job_description = 'sci*'\n\"\"\"\n\nsql_query = SQLQuery(sql_str)\nredis_query = sql_query.redis_query_string(redis_url=\"redis://localhost:6379\")\nprint(\"Resulting redis query: \", redis_query)\nresults = index.query(sql_query)\nresults\n```\n\n    Resulting redis query:  FT.SEARCH user_simple \"@job_description:sci*\" RETURN 5 user region job job_description age\n\n\n\n\n\n    [{'user': 'bill',\n      'region': 'us-central',\n      'job': 'engineer',\n      'job_description': 'Applies scientific and mathematical principles to solve technical problems.',\n      'age': '54'}]\n\n\n\n\n```python\n# Suffix\nsql_str = \"\"\"\n    SELECT user, region, job, job_description, age\n    FROM user_simple\n    WHERE job_description = '*care'\n\"\"\"\n\nsql_query = SQLQuery(sql_str)\nredis_query = sql_query.redis_query_string(redis_url=\"redis://localhost:6379\")\nprint(\"Resulting redis query: \", redis_query)\nresults = index.query(sql_query)\nresults\n```\n\n    Resulting redis query:  FT.SEARCH user_simple \"@job_description:*care\" RETURN 5 user region job job_description age\n\n\n\n\n\n    [{'user': 'mary',\n      'region': 'us-central',\n      'job': 'doctor',\n      'job_description': 'Diagnoses and treats illnesses, injuries, and other medical conditions in the healthcare field.',\n      'age': '24'},\n     {'user': 'joe',\n      'region': 'us-east',\n      'job': 'dentist',\n      'job_description': 'Provides oral healthcare including diagnosing and treating teeth and gum issues.',\n      'age': '27'}]\n\n\n\n\n```python\n# Fuzzy\nsql_str = \"\"\"\n    SELECT user, region, job, job_description, age\n    FROM user_simple\n    WHERE job_description = '%diagnose%'\n\"\"\"\n\nsql_query = SQLQuery(sql_str)\nredis_query = sql_query.redis_query_string(redis_url=\"redis://localhost:6379\")\nprint(\"Resulting redis query: \", redis_query)\nresults = index.query(sql_query)\nresults\n```\n\n    Resulting redis query:  FT.SEARCH user_simple \"@job_description:%diagnose%\" RETURN 5 user region job job_description age\n\n\n\n\n\n    [{'user': 'mary',\n      'region': 'us-central',\n      'job': 'doctor',\n      'job_description': 'Diagnoses and treats illnesses, injuries, and other medical conditions in the healthcare field.',\n      'age': '24'}]\n\n\n\n\n```python\n# Phrase no stop words\nsql_str = \"\"\"\n    SELECT user, region, job, job_description, age\n    FROM user_simple\n    WHERE job_description = 'healthcare including'\n\"\"\"\n\nsql_query = SQLQuery(sql_str)\nredis_query = sql_query.redis_query_string(redis_url=\"redis://localhost:6379\")\nprint(\"Resulting redis query: \", redis_query)\nresults = index.query(sql_query)\nresults\n```\n\n    Resulting redis query:  FT.SEARCH user_simple \"@job_description:\"healthcare including\"\" RETURN 5 user region job job_description age\n\n\n\n\n\n    [{'user': 'joe',\n      'region': 'us-east',\n      'job': 'dentist',\n      'job_description': 'Provides oral healthcare including diagnosing and treating teeth and gum issues.',\n      'age': '27'}]\n\n\n\n\n```python\n# Phrase with stop words currently limitation of core Redis\nsql_str = \"\"\"\n    SELECT user, region, job, job_description, age\n    FROM user_simple\n    WHERE job_description = 'diagnosing and treating'\n\"\"\"\n\nsql_query = SQLQuery(sql_str)\nredis_query = sql_query.redis_query_string(redis_url=\"redis://localhost:6379\")\nprint(\"Resulting redis query: \", redis_query)\nresults = index.query(sql_query)\nresults\n```\n\n    Resulting redis query:  FT.SEARCH user_simple \"@job_description:\"diagnosing treating\"\" RETURN 5 user region job job_description age\n\n\n    /Users/tyler.hutcherson/Documents/AppliedAI/redis-vl-python/.venv/lib/python3.13/site-packages/sql_redis/translator.py:136: UserWarning: Stopwords ['and'] were removed from phrase search 'diagnosing and treating'. By default, Redis does not index stopwords. To include stopwords in your index, create it with STOPWORDS 0.\n      return self._query_builder.build_text_condition(\n\n\n\n\n\n    [{'user': 'joe',\n      'region': 'us-east',\n      'job': 'dentist',\n      'job_description': 'Provides oral healthcare including diagnosing and treating teeth and gum issues.',\n      'age': '27'}]\n\n\n\n\n```python\nsql_str = \"\"\"\n    SELECT user, region, job, age\n    FROM user_simple\n    WHERE age BETWEEN 40 and 60\n    \"\"\"\n\nsql_query = SQLQuery(sql_str)\nredis_query = sql_query.redis_query_string(redis_url=\"redis://localhost:6379\")\nprint(\"Resulting redis query: \", redis_query)\nresults = index.query(sql_query)\nresults\n```\n\n    Resulting redis query:  FT.SEARCH user_simple \"@age:[40 60]\" RETURN 4 user region job age\n\n\n\n\n\n    [{'user': 'bill', 'region': 'us-central', 'job': 'engineer', 'age': '54'}]\n\n\n\n### Aggregations\n\nSee docs for redis supported reducer functions: [docs](https://redis.io/docs/latest/develop/ai/search-and-query/advanced-concepts/aggregations/#supported-groupby-reducers).\n\n\n```python\nsql_str = \"\"\"\n    SELECT\n        user,\n        COUNT(age) as count_age,\n        COUNT_DISTINCT(age) as count_distinct_age,\n        MIN(age) as min_age,\n        MAX(age) as max_age,\n        AVG(age) as avg_age,\n        STDEV(age) as std_age,\n        FIRST_VALUE(age) as fist_value_age,\n        ARRAY_AGG(age) as to_list_age,\n        QUANTILE(age, 0.99) as quantile_age\n    FROM user_simple\n    GROUP BY region\n    \"\"\"\n\nsql_query = SQLQuery(sql_str)\nredis_query = sql_query.redis_query_string(redis_url=\"redis://localhost:6379\")\nprint(\"Resulting redis query: \", redis_query)\nresults = index.query(sql_query)\nresults\n```\n\n    Resulting redis query:  FT.AGGREGATE user_simple \"*\" LOAD 2 age region GROUPBY 1 @region REDUCE COUNT 0 AS count_age REDUCE COUNT_DISTINCT 1 @age AS count_distinct_age REDUCE MIN 1 @age AS min_age REDUCE MAX 1 @age AS max_age REDUCE AVG 1 @age AS avg_age REDUCE STDDEV 1 @age AS std_age REDUCE FIRST_VALUE 1 @age AS fist_value_age REDUCE TOLIST 1 @age AS to_list_age REDUCE QUANTILE 2 @age 0.99 AS quantile_age\n\n\n\n\n\n    [{'region': 'us-west',\n      'count_age': '2',\n      'count_distinct_age': '2',\n      'min_age': '34',\n      'max_age': '61',\n      'avg_age': '47.5',\n      'std_age': '19.091883092',\n      'fist_value_age': '34',\n      'to_list_age': [b'34', b'61'],\n      'quantile_age': '61'},\n     {'region': 'us-central',\n      'count_age': '2',\n      'count_distinct_age': '2',\n      'min_age': '24',\n      'max_age': '54',\n      'avg_age': '39',\n      'std_age': '21.2132034356',\n      'fist_value_age': '54',\n      'to_list_age': [b'24', b'54'],\n      'quantile_age': '54'},\n     {'region': 'us-east',\n      'count_age': '1',\n      'count_distinct_age': '1',\n      'min_age': '27',\n      'max_age': '27',\n      'avg_age': '27',\n      'std_age': '0',\n      'fist_value_age': '27',\n      'to_list_age': [b'27'],\n      'quantile_age': '27'}]\n\n\n\n### Vector search\n\n\n```python\nsql_str = \"\"\"\n    SELECT user, job, job_description, cosine_distance(job_embedding, :vec) AS vector_distance\n    FROM user_simple\n    ORDER BY vector_distance ASC\n    \"\"\"\n\nvec = hf.embed(\"looking for someone to use base principles to solve problems\", as_buffer=True)\nsql_query = SQLQuery(sql_str, params={\"vec\": vec})\n\nredis_query = sql_query.redis_query_string(redis_url=\"redis://localhost:6379\")\nprint(\"Resulting redis query: \", redis_query)\nresults = index.query(sql_query)\n\nresults\n```\n\n    Resulting redis query:  FT.SEARCH user_simple \"*=\u003e[KNN 10 @job_embedding $vector AS vector_distance]\" PARAMS 2 vector $vector DIALECT 2 RETURN 4 user job job_description vector_distance SORTBY vector_distance ASC\n\n\n\n\n\n    [{'vector_distance': '0.82351064682',\n      'user': 'bill',\n      'job': 'engineer',\n      'job_description': 'Applies scientific and mathematical principles to solve technical problems.'},\n     {'vector_distance': '0.965160369873',\n      'user': 'john',\n      'job': 'software engineer',\n      'job_description': 'Designs, develops, and maintains software applications and systems.'},\n     {'vector_distance': '1.00401353836',\n      'user': 'mary',\n      'job': 'doctor',\n      'job_description': 'Diagnoses and treats illnesses, injuries, and other medical conditions in the healthcare field.'},\n     {'vector_distance': '1.00626885891',\n      'user': 'stacy',\n      'job': 'project manager',\n      'job_description': 'Plans, organizes, and oversees projects from inception to completion.'},\n     {'vector_distance': '1.01110625267',\n      'user': 'joe',\n      'job': 'dentist',\n      'job_description': 'Provides oral healthcare including diagnosing and treating teeth and gum issues.'}]\n\n\n\n\n```python\nsql_str = \"\"\"\n    SELECT user, region, cosine_distance(job_embedding, :vec) AS vector_distance\n    FROM user_simple\n    WHERE region = 'us-central'\n    ORDER BY vector_distance ASC\n    \"\"\"\n\nvec = hf.embed(\"looking for someone to use base principles to solve problems\", as_buffer=True)\nsql_query = SQLQuery(sql_str, params={\"vec\": vec})\n\nredis_query = sql_query.redis_query_string(redis_url=\"redis://localhost:6379\")\nprint(\"Resulting redis query: \", redis_query)\nresults = index.query(sql_query)\n\nresults\n```\n\n    Resulting redis query:  FT.SEARCH user_simple \"(@region:{us\\-central})=\u003e[KNN 10 @job_embedding $vector AS vector_distance]\" PARAMS 2 vector $vector DIALECT 2 RETURN 3 user region vector_distance SORTBY vector_distance ASC\n\n\n\n\n\n    [{'vector_distance': '0.82351064682', 'user': 'bill', 'region': 'us-central'},\n     {'vector_distance': '1.00401353836', 'user': 'mary', 'region': 'us-central'}]\n\n\n\n## Next Steps\n\nNow that you understand SQL queries for Redis, explore these related guides:\n\n- [Use Advanced Query Types](11_advanced_queries.ipynb) - Learn about TextQuery, HybridQuery, and MultiVectorQuery\n- [Query and Filter Data](02_complex_filtering.ipynb) - Apply filters using native RedisVL query syntax\n- [Getting Started](01_getting_started.ipynb) - Review the basics of RedisVL indexes\n\n## Cleanup\n\nTo remove all data from Redis associated with the index, use the `.clear()` method. This leaves the index in place for future insertions or updates.\n\nTo remove everything including the index, use `.delete()` which removes both the index and the underlying data.\n\n\n```python\nindex.delete()\n```\n",
  "tags": [],
  "last_updated": "2026-04-21T14:39:33+02:00"
}
