Execute Query
Executes a SQL Server SELECT query and returns the results as a table.
Common Properties
- Name - The custom name of the node.
- Color - The custom color of the node.
- Delay Before (sec) - Waits in seconds before executing the node.
- Delay After (sec) - Waits in seconds after executing node.
- Continue On Error - Automation will continue regardless of any error. The default value is false.
If the ContinueOnError property is true, no error is caught when the project is executed, even if a Catch node is used.
Inputs
- Connection Id - The unique identifier of the database connection to use (optional if credentials provided directly).
- Transaction Id - The unique identifier of a transaction (optional). Use when the query is part of a database transaction.
- SQL Query - The SQL SELECT statement to execute. Supports mustache template variables (e.g.,
{{userId}}).
Options
- Command Timeout - Command execution timeout in seconds (default: 30). Increase for long-running queries.
- Credentials - SQL Server database credentials (optional). Use this if you want to execute the query without a Connect node.
Output
- Result - The query results returned as a table structure with columns and rows.
How It Works
The Execute Query node executes a SQL SELECT statement and returns the results. When executed, the node:
- Retrieves the database connection (either from connection ID or creates new connection from credentials)
- Optionally retrieves the transaction if a transaction ID is provided
- Processes mustache template variables in the SQL query using the message context
- Decodes any HTML entities in the rendered query
- Creates a SqlCommand with the SQL query and timeout settings
- Executes the query using ExecuteReader
- Loads the results into a DataTable
- Converts the DataTable to a table structure with columns and rows
- Returns the table structure as output
Requirements
- Either: A valid connection ID from Connect node OR valid database credentials
- Valid SQL SELECT statement
- If using transactions, a valid transaction ID from Start Transaction node
- Appropriate SELECT permission on the queried tables
Error Handling
The node will return specific errors in the following cases:
- ErrInvalidArg - Neither connection ID nor credentials provided, or command timeout is invalid
- ErrNotFound - Connection ID not found in connections dictionary
- ErrConnection - Cannot connect to SQL Server (when using credentials mode)
- ErrRuntime - Query execution failed (syntax error, table doesn't exist, timeout, etc.)
Usage Examples
Basic SELECT Query
SELECT * FROM Customers WHERE Status = 'Active'
Query with Template Variables
SELECT CustomerID, CustomerName, Email, City
FROM Customers
WHERE City = '{{city}}' AND Country = '{{country}}'
In your message context:
{
"city": "New York",
"country": "USA"
}
JOIN Query
SELECT
o.OrderID,
o.OrderDate,
c.CustomerName,
p.ProductName,
od.Quantity,
od.UnitPrice
FROM Orders o
INNER JOIN Customers c ON o.CustomerID = c.CustomerID
INNER JOIN OrderDetails od ON o.OrderID = od.OrderID
INNER JOIN Products p ON od.ProductID = p.ProductID
WHERE o.OrderDate >= '{{startDate}}'
ORDER BY o.OrderDate DESC
Aggregate Query
SELECT
Category,
COUNT(*) AS TotalProducts,
AVG(Price) AS AveragePrice,
SUM(Stock) AS TotalStock,
MIN(Price) AS MinPrice,
MAX(Price) AS MaxPrice
FROM Products
GROUP BY Category
HAVING COUNT(*) > 5
ORDER BY AveragePrice DESC
Query with Subquery
SELECT CustomerName, TotalOrders, TotalRevenue
FROM (
SELECT
c.CustomerName,
COUNT(o.OrderID) AS TotalOrders,
SUM(o.TotalAmount) AS TotalRevenue
FROM Customers c
LEFT JOIN Orders o ON c.CustomerID = o.CustomerID
GROUP BY c.CustomerID, c.CustomerName
) AS CustomerStats
WHERE TotalOrders > {{minOrders}}
ORDER BY TotalRevenue DESC
Common Table Expression (CTE)
WITH RegionalSales AS (
SELECT
Region,
SUM(SalesAmount) AS TotalSales
FROM Sales
WHERE SalesDate >= '{{startDate}}'
GROUP BY Region
)
SELECT
Region,
TotalSales,
CAST(TotalSales * 100.0 / SUM(TotalSales) OVER() AS DECIMAL(5,2)) AS PercentOfTotal
FROM RegionalSales
ORDER BY TotalSales DESC
Common Use Cases
- Data Retrieval - Fetch customer information, product details, order history
- Business Intelligence - Generate sales reports, inventory summaries, analytics
- Data Validation - Check if records exist, verify data integrity
- Dashboard Data - Retrieve metrics and KPIs for dashboards
- Export Operations - Extract data for export to Excel, CSV, or other formats
- Search Functionality - Implement search features in automation workflows
- Conditional Processing - Query data to determine next automation steps
- Data Synchronization - Read data from SQL Server to sync with other systems
Working with Query Results
Access Results in JavaScript
// Query results are in $item.result
const results = $item.result;
// Access table structure
const columns = results.columns; // Array of column names
const rows = results.rows; // Array of row objects
// Iterate through rows
rows.forEach(row => {
console.log(`Customer: ${row.CustomerName}, Email: ${row.Email}`);
});
// Get first row
const firstRow = rows[0];
// Count rows
const rowCount = rows.length;
// Check if results are empty
if (rows.length === 0) {
console.log('No results found');
}
// Access specific columns
const customerNames = rows.map(row => row.CustomerName);
Use with Loop Node
Connect the Query node to a Loop node to process each row:
Query → Loop (over $item.result.rows)
└─ Process each row individually
Filter and Transform Results
// Filter results in JavaScript
const activeCustomers = $item.result.rows.filter(row => row.Status === 'Active');
const highValueOrders = $item.result.rows.filter(row => row.Total > 1000);
// Transform results
const emailList = $item.result.rows.map(row => ({
email: row.Email,
name: row.CustomerName
}));
// Group results
const groupedByCity = $item.result.rows.reduce((acc, row) => {
if (!acc[row.City]) acc[row.City] = [];
acc[row.City].push(row);
return acc;
}, {});
Tips for Effective Use
- Template Variables - Use mustache syntax
{{variable}}to make queries dynamic and secure - SQL Editor - The node provides syntax highlighting for SQL statements
- Query Optimization - Use WHERE clauses to limit results, add indexes to improve performance
- Column Selection - Select only needed columns instead of using SELECT *
- Limit Results - Use TOP clause for large datasets to prevent memory issues
- Direct Credentials Mode - Use the optional Credentials field to query without a Connect node
- Transaction Support - Include queries in transactions for data consistency
- Result Validation - Always check if results are empty before processing
- Command Timeout - Increase timeout for complex queries that take longer to execute
- Parameterization - Use template variables instead of string concatenation to prevent SQL injection
Performance Best Practices
Optimize Queries
-- GOOD: Specific columns, WHERE clause, TOP
SELECT TOP 100 CustomerID, CustomerName, Email
FROM Customers
WHERE Status = 'Active'
AND CreatedDate >= '{{startDate}}'
-- AVOID: SELECT * without conditions
SELECT * FROM Customers
Use Indexes
Ensure your SQL Server tables have proper indexes on columns used in:
- WHERE clauses
- JOIN conditions
- ORDER BY clauses
- GROUP BY clauses
Pagination
For large datasets, implement pagination:
-- SQL Server 2012+ pagination
SELECT CustomerID, CustomerName, Email
FROM Customers
WHERE Status = 'Active'
ORDER BY CustomerID
OFFSET {{offset}} ROWS
FETCH NEXT {{pageSize}} ROWS ONLY
const pageSize = 100;
const page = 1;
const offset = (page - 1) * pageSize;
Connection Reuse
Connect (once)
↓
Query 1
↓
Query 2
↓
Query 3
↓
Disconnect
Better than connecting/disconnecting for each query.
Execution Plan
For complex queries, check execution plan in SQL Server Management Studio to identify bottlenecks.
Common Errors and Solutions
Query Execution Failed
Error: ErrRuntime: Query execution failed
Common Causes:
- Syntax error in SQL
- Table or column doesn't exist
- Invalid template variable values
- Permission denied on table
- Query timeout exceeded
Solutions:
- Test query in SQL Server Management Studio (SSMS) first
- Verify table and column names (check case sensitivity in collation)
- Check template variables are properly substituted
- Ensure database user has SELECT permission
- Increase Command Timeout for long-running queries
- Check execution plan for performance issues
Connection Not Found
Error: ErrNotFound: Connection not found
Solutions:
- Ensure Connect node runs before Query node
- Verify connection ID variable is correct
- Or use the Credentials option to connect directly
Invalid Object Name
Error: Invalid object name 'TableName'
Solutions:
- Verify table name spelling and case
- Check if schema is specified (use
dbo.TableNameorschema.TableName) - Ensure you're connected to the correct database
- Use
SELECT * FROM sys.tablesto list available tables - Check if table exists in the database
Invalid Column Name
Error: Invalid column name 'ColumnName'
Solutions:
- Verify column name spelling and case
- Use
sp_help 'TableName'to see column names - Check for typos in template variables
- Ensure column exists in the queried table
Command Timeout Expired
Error: Timeout expired. The timeout period elapsed prior to completion
Solutions:
- Increase the Command Timeout option (default: 30 seconds)
- Optimize the query (add indexes, reduce data scanned)
- Add WHERE clause to limit rows processed
- Check for table locks or blocking queries
- Use SQL Server Activity Monitor to identify issues
Arithmetic Overflow Error
Error: Arithmetic overflow error converting expression to data type
Solutions:
- Check data type conversions in query
- Use CAST or CONVERT with appropriate data types
- Verify numeric calculations don't exceed data type limits
- Handle NULL values properly in calculations
Advanced Examples
Dynamic Filtering with Template Variables
SELECT * FROM Products
WHERE Category = '{{category}}'
AND Price BETWEEN {{minPrice}} AND {{maxPrice}}
AND Stock > {{minStock}}
AND CreatedDate >= '{{startDate}}'
ORDER BY
CASE WHEN '{{sortBy}}' = 'Price' THEN Price END,
CASE WHEN '{{sortBy}}' = 'Name' THEN ProductName END
Window Functions
SELECT
ProductID,
ProductName,
Category,
Price,
ROW_NUMBER() OVER (PARTITION BY Category ORDER BY Price DESC) AS PriceRank,
AVG(Price) OVER (PARTITION BY Category) AS AvgCategoryPrice,
SUM(Stock) OVER (PARTITION BY Category) AS CategoryTotalStock
FROM Products
WHERE Category IN ({{categoryList}})
Pivot Query
SELECT *
FROM (
SELECT Year, Quarter, SalesAmount
FROM Sales
WHERE Year = {{year}}
) AS SourceTable
PIVOT (
SUM(SalesAmount)
FOR Quarter IN ([Q1], [Q2], [Q3], [Q4])
) AS PivotTable
Recursive CTE
WITH EmployeeHierarchy AS (
-- Anchor member
SELECT EmployeeID, EmployeeName, ManagerID, 0 AS Level
FROM Employees
WHERE EmployeeID = {{rootEmployeeId}}
UNION ALL
-- Recursive member
SELECT e.EmployeeID, e.EmployeeName, e.ManagerID, eh.Level + 1
FROM Employees e
INNER JOIN EmployeeHierarchy eh ON e.ManagerID = eh.EmployeeID
)
SELECT * FROM EmployeeHierarchy
ORDER BY Level, EmployeeName
JSON Query (SQL Server 2016+)
SELECT
CustomerID,
CustomerName,
(
SELECT OrderID, OrderDate, TotalAmount
FROM Orders o
WHERE o.CustomerID = c.CustomerID
FOR JSON PATH
) AS OrdersJSON
FROM Customers c
WHERE Country = '{{country}}'
FOR JSON PATH
Temporal Table Query (SQL Server 2016+)
-- Query historical data
SELECT * FROM Products
FOR SYSTEM_TIME AS OF '{{historicalDate}}'
WHERE Category = '{{category}}'
-- Query changes over time
SELECT * FROM Products
FOR SYSTEM_TIME BETWEEN '{{startDate}}' AND '{{endDate}}'
WHERE ProductID = {{productId}}
Transaction Example
Connect
↓
Start Transaction (get trx_id)
↓
Query 1 (read data with isolation, use trx_id)
↓
Query 2 (read related data, use trx_id)
↓
Non Query (update based on queries, use trx_id)
↓
Commit (commit trx_id)
↓
Disconnect
Using Direct Credentials (Without Connect)
Query Node:
- SQL Query: SELECT * FROM Customers
- Credentials: [Select Database Credential]
- Connection Id: (leave empty)
This creates a temporary connection, executes the query, and closes the connection automatically. Useful for one-off queries.
Date and Time Handling
SQL Server Date Formats
-- ISO 8601 format (recommended)
SELECT * FROM Orders
WHERE OrderDate >= '2024-01-15T10:30:00'
-- Date only
SELECT * FROM Orders
WHERE CAST(OrderDate AS DATE) = '{{orderDate}}'
-- Date range
SELECT * FROM Orders
WHERE OrderDate >= '{{startDate}}'
AND OrderDate < DATEADD(day, 1, '{{endDate}}')
Format Dates in Results
SELECT
OrderID,
FORMAT(OrderDate, 'yyyy-MM-dd') AS OrderDateFormatted,
FORMAT(OrderDate, 'yyyy-MM-dd HH:mm:ss') AS OrderDateTimeFormatted,
CONVERT(VARCHAR, OrderDate, 120) AS OrderDateISO
FROM Orders
See Also
- Connect - Establish database connections
- Non Query - Execute INSERT, UPDATE, DELETE
- Insert - Bulk insert table data
- Start Transaction - Begin transactions
- Commit - Commit transactions