Kaizen #207 - Answering your Questions | Advanced Queries using COQL API

Kaizen #207 - Answering your Questions | Advanced Queries using COQL API



Hi everyone, and welcome to another Kaizen week!

As part of Kaizen #200 milestone, many of you shared topics you would like us to cover, and we have been addressing them one by one over the past few weeks. Today, we are picking up one of those requests - a deep dive into advanced queries using Zoho CRM’s COQL APIs.

When you start building complex applications on top of Zoho CRM, you may feel that basic record fetch APIs like GET records are not enough. Business logic often demands far more, like combining data from multiple modules, applying conditional filters, grouping results, or even running aggregate calculations.

This is exactly where COQL (CRM Object Query Language) shines. If you have already used COQL for straightforward queries, this post will help you go further. 

COQL Recap - Why Use It?

COQL is your go-to when you need more than what the standard GET Records API can provide. It gives you:

  • SQL-like flexibility for querying CRM data.
  • Access to related records across multiple modules using lookups and joins.
  • Powerful filtering, aggregation, and sorting well beyond simple searches.

In short: use COQL when you want fine-grained control over results, complex reporting logic, or performance improvements in large data environments.

Understanding COQL Queries

The Query API (COQL) is best when you need flexible record retrieval without chaining multiple API calls or creating custom views.

Instead of building and maintaining complex filters in the UI, you can describe your data needs in one SQL-like query.

For example, with COQL you can:

  • Fetch all products within a certain price range that also have a 5-star rating, sorted by price.
  • Filter deals based on details from a related module, like the Vendor’s status.
  • Pull a precise slice of data on-demand without altering CRM views.

What kind of queries are supported?

COQL currently supports only the SELECT statement, which lets you pick fields, apply conditions, sort results, and control pagination.

A typical query looks like this:

SELECT {field_api_namesFROM {module_api_nameWHERE {field_api_name} {comparator} {valueGROUP BY {field_api_name} ORDER BY {field_api_nameASC/DESC LIMIT {limitOFFSET {offset}

  • FROM - specifies the module to query
  • WHERE - filters records based on conditions

  • GROUP BY - groups records by one or more fields for aggregation
  • ORDER BY - sorts results ascending or descending
  • LIMIT - restricts the number of records returned
  • OFFSET - skips a certain number of records before fetching results

Example:

{

 "select_query" : "select Last_Name, First_Name, Mobile, Final_Score from Leads where Lead_Status 'Not Contacted' order by Final_Score desc limit 5 offset 10"

}


The above query retrieves five Leads who have not been contacted, ordered by Final_Score, skipping the first 10(OFFSET). You can also use the shorthand LIMIT offset, limit:

{

 "select_query" : "select Last_Name, First_Name, Mobile, Final_Score from Leads where Lead_Status = 'Not Contacted' order by Final_Score desc limit 10, 5"

}


Supported Data Types & Operators

COQL supports multiple field types, each with dedicated operators:

Field Type

Supported Operators

Text, Picklist, Email, Phone, Website, Autonumber 

=, !=, like, not like, in, not in, is null, is not null

Lookup

=, !=, in, not in, is null, is not null

Date, DateTime, Number, Currency

=, !=, >=, >, <=, <, between, not between, in, not in, is null, is not null

Boolean

=

Formula

If the return type is:

  1. Decimal/Currency/Date/Datetime: =, !=, >=, >, <=, <, between, not between, in, not in, is null, is not null
  2. String: =, !=, like, not like, in, not in, is null, is not null
  3.  Boolean: =


Queries can be further refined with sorting (ORDER BY) and pagination using LIMIT and OFFSET.

Aggregate functions

COQL supports aggregate functions to summarize data:

  • SUM(field) – total of numeric values
  • MAX(field) – largest value
  • MIN(field) – smallest value
  • AVG(field) – average value
  • COUNT(*) – number of records matching criteria 


Please note that aggregate functions are supported only for numeric data types such as number, decimal, currency, etc.

Wildcards

The % character is supported with the LIKE operator for flexible text matching:

  • '%tech' → values ending with “tech”
  • 'C%' → values starting with “C”
  • '%tech%' → values containing “tech”


With these building blocks, you can already express a wide range of queries. Let’s now move into advanced scenarios where COQL really shines.

Beyond basics: COQL Patterns for real-world scenarios

Once you are comfortable with the basics of COQL, you can start combining them into more powerful query patterns. Some of these go beyond simple filtering and field selection, helping you minimize API calls, handle relationships, and emulate unsupported features.

1. Advanced Filtering & Conditions

Beyond equality, COQL supports operators like LIKEINBETWEEN, and date comparisons.

Example: Fetch Leads from the IT or Finance industry created in the year 2025.

{

 "select_query": "select Full_Name, Industry from Leads where Industry in ('IT', 'Finance') and Created_Time between '2025-01-01T00:00:00+05:30' and '2025-12-31T23:59:59+05:30'"

}


Use case: Run targeted campaigns or segment leads for analysis without multiple API calls.

2. Combining Multiple Conditions

You can query diverse conditions, combining exact, partial matches, and set memberships.

Example: Pre-qualified leads in target industries with company names containing “zylker”:

{

 "select_query": "select First_Name, Last_Name from Leads where (((Lead_Status = 'Pre-Qualified') and (Company like '%zylker%')) and Industry in ('Technology', 'Government/Military'))"

}



Use case: Sophisticated audience segmentation or analytics for campaigns.

3. Fetching related records and their fields using Joins (Dot notation)

COQL allows you to retrieve related records efficiently by navigating lookup relationships using dot notation. This makes it possible to pull in contextual information across modules without chaining multiple API calls.

Single-level join: Fetch contacts and their account names, excluding a specific account:

{

 "select_query": "select Last_Name, First_Name, Account_Name.Account_Name, Owner from Contacts where (Account_Name.Account_Name != 'Zylker') limit 2"

}


Sample use case: Retrieve all contacts along with their associated account names while excluding certain accounts (e.g., competitors or internal test accounts). This avoids multiple queries across modules and helps in cleaner campaign targeting.

Hierarchical / nested join: Fetch contacts whose accounts have a parent account named “Kings”:

{

 "select_query": "select Account_Name, Account_Name.Parent_Account.Account_Name from Contacts where Account_Name.Parent_Account.Account_Name = 'Kings' limit 5"

}


Sample use case: Easily retrieve multi-level relationships such as parent-child accounts for reporting, territory alignment, or hierarchical sales analysis.

Multi-Level Join with Extended Lookup : Fetch contacts, their accounts, the parent accounts of those accounts, and the owner of the parent account:

{

 "select_query": "select Last_Name, First_Name, Account_Name.Account_Name, Account_Name.Parent_Account, Account_Name.Parent_Account.Owner AS 'Parent Account Owner', Owner from Contacts where (Account_Name.Account_Name != 'Zylker') limit 2"

}


Sample use case: Useful in complex account management and escalation scenarios where responsibility spans multiple levels. For instance, sales managers may want to see not just the contact and their account, but also which parent account owner is responsible for the overall relationship. These types of queries are helpful in large enterprises with layered ownership structures.

4. Using Subqueries to detect missing relationships

COQL supports subqueries to filter based on related module data or detect missing relationships.

Example: Find contacts whose accounts have no closed deals:

{

 "select_query": "select Full_Name, Email from Contacts where Account_Name not in (select Account_Name from Deals where Stage = 'Closed Won')"

}


Use case: Identify potential follow-ups, audit compliance, or uncover opportunities.

These types of queries are handy for:

  • Sales follow-ups – identify contacts from accounts that haven’t yet converted.
  • Compliance checks – ensure certain accounts meet deal requirements.
  • Pipeline building – target untouched accounts for new opportunities.

By combining subqueries with conditions like NOT IN, COQL makes it easy to surface hidden opportunities that would otherwise require multiple API calls and custom logic.

NoteSubqueries in COQL can return a maximum of 100 records. If the inner query has more than 100 matches, any extra records are ignored. This means you may get incomplete results in larger datasets. In such cases, it is better to redesign the query using joins or multiple API calls, which can handle broader datasets without this limit.

Advanced COQL Querying: Real-World Patterns

Once you’ve mastered filters, joins, and subqueries, you can combine them for advanced business logic. 

1. Filtering Deals Based on Account Attributes

Generic Use Case:
You want to prioritize deals connected to high-value accounts that meet specific business criteria, such as strong credit ratings or key industries.

Retrieve all deals for accounts that:

  • Have a high credit rating (>750)
  • Belong to a specific industry, e.g., Communications

COQL Query:

{

 "select_query": "SELECT Deal_Name, Amount, Account_Name, Contact_Name.Email FROM Deals WHERE Account_Name in (SELECT id FROM Accounts WHERE Credit_Rating > 750 AND Industry = 'Communications') AND Stage != 'Closed Won'"

}


Dynamically filter deals by account attributes while fetching related contact details in a single query.

2. Emulating MIN/MAX for Date fields

When working with date fields in COQL, a common analytical need is to compare records against the latest date from a related subset. For example, identifying deals that closed before the most recent high-value deal.

Intuitively, one might try to use aggregate functions like MAX() on a date field in a subquery, such as:

{

 "select_query": "SELECT Deal_Name FROM Deals WHERE Closing_Date < (SELECT MAX(Closing_Date) FROM Deals WHERE Amount > 500000)"

}

Warning
However, COQL currently does not support aggregate functions like MAX() or MIN() on Date or DateTime fields. Attempting this will result in errors or unexpected behavior, as COQL aggregates are primarily designed for numeric fields.

Workaround: Using Subquery with ORDER BY and LIMIT

Instead of MAX(), the recommended COQL approach leverages sorting and limiting the result set to a single latest date within a subquery:

{

 "select_query": "select Deal_Name from Deals where Closing_Date < (select Closing_Date from Deals where Amount > 500000 order by Closing_Date desc limit 1)"

}


How this works:

The inner subquery fetches the single most recent Closing_Date where deals exceed $500,000, ordering by date descending and limiting to one record. The outer query then retrieves all deals closed before that date.

This pattern mimics the MAX() date comparison in a manner supported by COQL’s current capabilities. You can apply the same approach with ascending sort order to emulate MIN() as well.

3. Combining Multiple Subqueries for Complex Business Logic

Real-world CRM scenarios often require filtering records based on multiple interconnected conditions across different modules. Consider this sales intelligence use case: you want to identify Contacts who are:

  • Associated with Accounts that have annual revenue greater than $1000000000000
  • Connected to Deals that were created in the previous quarter    

{

 "select_query": "SELECT First_Name, Last_Name, Email, Account_Name.Account_Name FROM Contacts WHERE Account_Name in (SELECT Account_Name FROM Deals WHERE Created_Time >= '2025-06-01' AND Account_Name in (SELECT id FROM Accounts WHERE Annual_Revenue > 1000000000000)) "

}


Query Breakdown:

  • Innermost subquery: (SELECT id FROM Accounts WHERE Annual_Revenue > 1000000000000) identifies high-revenue accounts
  • Middle subquery: (SELECT Account_Name FROM Deals WHERE Created_Time >= '2022-07-02T15:18:31+05:30' AND Account_Name in (...)) filters for accounts with deals created after the specified date that are also high-revenue accounts
  • Main query: Retrieves contact details for all contacts associated with these filtered accounts while fetching the related account names via JOIN


This pattern finds contacts from high-value accounts that have had recent deal activity, combining temporal filtering with revenue-based account qualification in a single efficient query.

Dynamic Account and Deal Performance Analysis

Imagine you need to find all Leads from industries where accounts have historically closed high-value deals (over $100K) and those leads have "Hot" ratings.

This requires filtering leads based on:

  • Industry performance from accounts with successful deals
  • Lead rating criteria
  • Retrieving lead details with industry information


{

 "select_query": "SELECT First_Name, Last_Name, Lead_Source, Company, Industry FROM Leads WHERE Industry in (SELECT Industry FROM Accounts WHERE id in (SELECT Account_Name FROM Deals WHERE Amount > 100000 AND Stage = 'Closed Won') GROUP BY Industry) AND Rating = 'Hot'"

}


What makes this powerful:

  • Inner subquery (SELECT Account_Name FROM Deals WHERE Amount > 100000 AND Stage = 'Closed Won') identifies accounts with successful high-value deals
  • Outer subquery (SELECT Industry FROM Accounts WHERE id in (...) GROUP BY Industry) gets the industries of those successful accounts
  • Groups by Industry to get unique industry values and avoid duplicates
  • Main query finds leads in those proven successful industries with "Hot" ratings.

    Note: Both subqueries in this query are limited to 100 records each. If either the Deals or Accounts module returns more than 100 matches, the additional records are silently ignored. This can lead to incomplete results when working with larger datasets. For scenarios where the inner queries are expected to return more than 100 records, redesign the query using joins or break it down into multiple API calls for complete coverage.


Conclusion

By going beyond simple record fetches, COQL gives you the power to do true analytics and querying. By mastering patterns that range from straightforward joins to complex multi-module subqueries, you can consolidate multiple API calls into a single query, reduce complexity, and streamline performance. At the same time, dynamic filtering across modules facilitates richer business logic, while relationship-aware queries let you build automations that can handle real-world exceptions with precision.

As you implement these patterns, remember that the most powerful COQL queries often combine multiple techniques: JOINs for data enrichment, subqueries for dynamic filtering, and careful aggregation for performance optimization. However, it is equally important to understand COQL's limitations too. Being aware of these limitations will help you design effective workarounds and choose the right approach for your specific use cases. For a comprehensive list of limitations, please refer to our COQL Limitations documentation.

Start with simpler patterns and gradually build complexity as your use cases demand. The investment in mastering COQL will pay you with cleaner code base, better performance, lesser credit consumption, and more sophisticated CRM functionality.

We hope that you found this post on COQL useful. If you have any queries or need further assistance, please feel free to comment below or email us at support@zohocrm.com. We are here to help!



    • Sticky Posts

    • Kaizen #198: Using Client Script for Custom Validation in Blueprint

      Nearing 200th Kaizen Post – 1 More to the Big Two-Oh-Oh! Do you have any questions, suggestions, or topics you would like us to cover in future posts? Your insights and suggestions help us shape future content and make this series better for everyone.
    • Kaizen #226: Using ZRC in Client Script

      Hello everyone! Welcome to another week of Kaizen. In today's post, lets see what is ZRC (Zoho Request Client) and how we can use ZRC methods in Client Script to get inputs from a Salesperson and update the Lead status with a single button click. In this
    • Kaizen #222 - Client Script Support for Notes Related List

      Hello everyone! Welcome to another week of Kaizen. The final Kaizen post of the year 2025 is here! With the new Client Script support for the Notes Related List, you can validate, enrich, and manage notes across modules. In this post, we’ll explore how
    • Kaizen #217 - Actions APIs : Tasks

      Welcome to another week of Kaizen! In last week's post we discussed Email Notifications APIs which act as the link between your Workflow automations and you. We have discussed how Zylker Cloud Services uses Email Notifications API in their custom dashboard.
    • Kaizen #216 - Actions APIs : Email Notifications

      Welcome to another week of Kaizen! For the last three weeks, we have been discussing Zylker's workflows. We successfully updated a dormant workflow, built a new one from the ground up and more. But our work is not finished—these automated processes are
    • Recent Topics

    • My client requires me to have custom pdf file names to except payment for invoices, how can I customize this before emailing.

      Hello! I love the program so far but there are a few things that are standing in the way. I hope you guys can code them in so I can keep the program for years to come. My client requires I customize the pdf file names I send in for billing. Can you please
    • When I schedule calendar appointments in zoho and invite external emails, they do not receive invites

      Hello, We have recently transitioned to zoho and are having a problem with the calendar feature. When we schedule new calendar appointments in zoho the invite emails aren't being sent to the external users that we list in participants. However, this works
    • Migrate different zoho subscription to zoho one

      Dear We have different zoho subscription we need to migrate it to zoho one. Currently we are paying for zoho email, zoho expense, zoho payroll etc under different admin We need to move it too zoho one flexlible plan for all my employees
    • Bigin use in hospital- Human Med or Veterinary

      I am looking for users who are in either human or veterinary medicine and use the CRM specifically for referral management tasks. Are you using the basic version? How many users update the CRM and is it effective? Did you pay for additional customizations?
    • Standardize email communication with Signature Template

      Maintaining a consistent and professional signature across all outgoing emails is essential for any organization. However, when users manage their signatures individually, it often leads to inconsistencies like varying formats, missing designations, or
    • Zoho Books: tax is not automatically pulled from product-data anymore - why?

      Hi, until a short time ago, you could set a default taxrate for each product/item. This taxrate automatically appeared each time the item was chosen in an invoice or quote. Why does this not work anymore? The field is still there at the product record,
    • Setting up property management in Zoho Books

      Hi, I run a property management business that manages property complexes. There are multiple owners, some owning more than one property on the same complex. My role is to manage the fees they pay for maintenance of common areas, such as the swimming pool
    • Zoho Creator to GMAIL API Setup - Where Do I Begin?

      Does anyone know how to connect Zoho Creator to Google Workspace (Specifically GMAIL?) We have FLOW setup and working fine to send emails via GMAIL, but Flow doesn't accept file attachments which is a major problem. So, we need to be able to send an email
    • Kiosk Page Refresh

      We have a Kiosk running from a button in contacts to update values and also add related lists, which works great, but when the kiosk is finished the page does not refresh to show the changes. Is there a way to force the contact to refresh/update when
    • Setting GC session variable programatically in a website

      Hi! Is there a way now to programatically set session variables from a website for a Guided Conversations? The current available methods are dependent on react-native.
    • Ticket Merge Error

    • Refresh frequency

      Dear Zoho Team, I really, truly appreciate that Zoho Books gets frequent updates. As a matter of fact this is how a good SaaS company should stay on top. However, I feel that I have to hit refresh almost every day. This was exciting at the beginning but
    • Update application by uploading an updated DS file

      Is it possible? I have been working with AI on my desktop improving my application, and I have to keep copy pasting stuff... Would it be possible to import the DS file on top of an existing application to update the app accordingly?
    • Two-factor authentication (2FA) Log-in Problems

      The Two-factor authentication (2FA) Login on my passwords doesn't match , so it wont accept login I'm down to my last backup code.
    • Remove my video

      Hi, How can I remove my video so that I don't have to see myself. It's weird so I always remove my own video from what I see but cannot find this feature here. Thanks!
    • Client Script: Any plans to add support for multi-select field with onChange

      Client Script is fantastic and the documentation lists multiselect form fields as unsupported. Just wondering if there are any plans to make this a supported field. https://www.zoho.com/crm/developer/docs/client-script/client-script-events.html 2. Field
    • Feature Reqeust - Include MPN In Selectable FIelds

      I have noticed that the MPN is not available to show in the list view of Items. Please consider adding it as EAN, UPC and ISBN are all available, so it doesn't make much sense to exclude this similar option. Thanks for considering my feedback.
    • Experience effortless record management in CRM For Everyone with the all-new Grid View!

      Hello Everyone, Hope you are well! As part of our ongoing series of feature announcements for Zoho CRM For Everyone, we’re excited to bring you another type of module view : Grid View. In addition to Kanban view, List view, Canvas view, Chart view and
    • Windows Desktop Application for Bigin

      I'm finding the need for a standalone Bigin desktop app for Windows users. Most of my daily work is done through a browser, so I often have several open tabs while working with customers and checking product information, etc. With Bigin currently only
    • Set another Layout as Standard

      We created a few layouts and we want to set another one to standard:
    • Salesforceに添付ファイルを格納したい

      お世話になっております。 Salesforceに添付ファイルを格納したく、カスタムオブジェクトに連携し、 「ファイルのアップロード」項目を設けました。 実際、エラーもなく送信出来たのですが、実際生成されたカスタムオブジェクトのレコードを見ると、どこにも添付ファイルがありません。仕様として、この添付ファイルはSalesforceのどこに格納されるのでしょうか? 今回作りたいフォームは、複数の書類を添付するため、Zohoformのファイルアップロード項目「本人確認書類」「源泉徴収票」などの項目を、Salesforce側にも設けた「本人確認書類」「源泉徴収票」という各項目にURLリンクとして紐づけたいと思っておりました。
    • Knowledge Base article lists

      Is it possible to adjust the number of articles that are visible under a category of the Knowledge Base portal? Currently it looks like by default it populates about 5 articles before it puts the "more" option at the bottom. Looking to see if I can extend
    • Discrepancy in Contracts with Fields list/Layout

      The Support Plan field on the layout isn't in the fields list. What am I missing?
    • Migrating all workflows to another Zoho account

      We are going to transfer into another company, and we are going to get new emails and new Zoho accounts. Is there a way to migrate (or save in some sort of external file) all presets and settings that we have on this account? That includes primarily workflows,
    • Edit The Newsletter

      There doesn't seem to be the ability add a title and a caption below the button. Can this be done?
    • Unable to Delete Items – No Visible Transactions but Error “Items which are a part of other transactions cannot be deleted…”

      Hello Community, We are using Zoho Inventory for our business and encountered a persistent issue that is preventing us from deleting certain items. The message shown is: “Items which are a part of other transactions cannot be deleted. Instead, mark them
    • Keyboard UX for Assemblies

      The new Assembly module has a counter-intuitive behavior that ought to be corrected. When an Assembly is ready to be entered, there are two options given, the blue-highlighted "Assemble" and the gray "Save as Draft". This correctly implies that the normal
    • landed cost-need help with different currency under the same bill

      I’m having trouble recording landed costs in Zoho Inventory/Books. My purchase order is in CNY, but the landed cost (freight) I pay is in USD. Zoho forces everything under the same bill to use one currency, so I can’t enter the landed cost in its actual
    • Improved Functionality PO Bill SO Invoice

      Hello, I need to enter over 100 items, it's frustrating to scroll a few item rows and wait for more to load, then scroll again. It would be nice to have buttons that scroll to the top or bottom with one click. Furthermore, these items I'm adding are VAT
    • Generate a link for Zoho Sign we can copy and use in a separate email

      Please consider adding functionality that would all a user to copy a reminder link so that we can include it in a personalized email instead of sending a Zoho reminder. Or, allow us to customize the reminder email. Use Case: We have clients we need to
    • I would like to request a new feature or setting for SalesIQ.

      Hello Zoho Team, I would like to request a new feature or setting for SalesIQ. Currently, when a user opens our contact widget and clicks on the "Chat with us" option, it opens a standard chat window that remains empty until either the user types a message
    • In Zoho inventory Converting sales return to cerdit note from using Api from Creator Error details: {"code":-1,"message":"Invalid Sales Return ID."}

      In Zoho inventory Converting sales return to cerdit note from using Api from Creator Error details: {"code":-1,"message":"Invalid Sales Return ID."} this is button Function used in the Creator map Inventory.Create_Credit_note(int CRE_ID) { return_value
    • Zia should track how customer relationships evolve over time

      Here's a feature idea that I've been thinking about The Problem Zia is great at analyzing individual interactions email sentiment, call transcription, best time to contact. But here's what it can't do: tell you how a relationship has evolved over time.
    • FSM integration with Books

      Hi, I have spent a few months working with FSM and have come across a critical gap in the functionality, which I find almost shocking....either that, or I am an idiot. The lack of bi-directional sync between Books and FSM on Sales Orders/ Work Orders
    • How to Track Inventory Usage from Zoho FSM to Zoho Inventory?

      Hi everyone, We’re currently working on integrating Zoho FSM with Zoho Inventory, and we’ve encountered a challenge we’re hoping the community can help us understand better. Here’s the context: When we create a Work Order in Zoho FSM that involves parts
    • Set Field Mandatory by Client Script ZOHO CRM

      #Tips of the day We can set the field as mandatory by the client script var field_obj = ZDK.Page.getField('Custom_Field1'); field_obj.setMandatory(true); Custom_Field1 = Field API Name Apart from is if you have required any kind of Zoho work please do
    • associating products with accounts

      I have all my accounts and products in zoho now. I need to generate a sales order for an account. The product lookup feature on the sales order shows no products...how can I get them to appear.
    • Can we rely on order of returned ids when inserting multiple records?

      Hello! API https://www.zoho.com/crm/developer/docs/api/v8/insert-records.html does not mention that the response array will match the input array*, keeping this important information implicit and someone might have doubts to rely on it. (*the response
    • New UI for Writer - Disappointed

      I've been enjoying Zoho Writer as a new user for about 6 months, and I really like it. One of my favorite things about it is the menu bar, which you can hide or leave out while still seeing most of your page because it is off to the left. I think this
    • Zoho CRM Community Digest - February 2026 | Part 2

      In this edition, we’re highlighting a few more product enhancements, along with some helpful community discussions that explore everyday CRM scenarios from automating reminders and managing lead outreach to making the most of APIs and client scripts.
    • Next Page