#15 Introduction to DuneSQL
Last updated
Last updated
Dune has officially launched its team's self-developed query engine, Dune SQL, based on Trino (https://trino.io/). This article introduces some common query syntax, considerations, and details of Dune SQL.
Note: as Dune has announced that it will fully transition to the Dune SQL query engine from the second half of 2023, this tutorial upgrades all the original Query to the Dune SQL version.
There are several key points to note in the syntax of Dune SQL:
Dune SQL uses double quotation marks to quote field names or table names that contain special characters or are keywords, such as "from"
or "to"
.
The string type in Dune SQL is varchar
, and the commonly used numeric types are double
and decimal(38, 0)
.
Dune SQL does not support implicit type conversions. For example, in Dune SQL, you cannot directly compare '2022-10-01'
with block_time; you need to use functions like date('2022-10-01')
to explicitly convert it to a date before comparison. You cannot directly concatenate numeric types and strings; you need to use cast(number_value as varchar)
to convert them to strings before concatenation.
The Dune documentation provides a detailed syntax comparison table. You can refer to the Syntax Comparison for more information. The following shows a partial comparison of the differences:
Dune SQL uses double quotation marks for this purpose
Dune SQL does not support implicit conversion of string-formatted date values to datetime types. Explicit conversion must be used. Date and time functions or operators can be utilized for this purpose.
Using Date Values
Dune SQL utilizes the date() function
Using Date and Time Values
Dune SQL employs the timestamp operator
Using Interval
Dune SQL utilizes the interval '12' hour
syntax
In Dune SQL queries, addresses and hash values can be used without enclosing them in single quotes. In this case, the case sensitivity is not enforced and there is no need to explicitly convert them to lowercase.
In Dune SQL, the string type is varchar
and the commonly used numeric type is double
. Integer values in Dune SQL are default to the bigint
type. When performing multiplication with large numbers, it is prone to overflow errors. In such cases, you can forcefully convert them to double
type or decimal(38, 0)
type. Integer division in Dune SQL does not implicitly convert to a floating-point number and perform division; instead, it directly returns an integer. This aspect should also be taken into consideration.
Converting to String
Dune SQL
Checking the SQL output above, you can see that when casting a large or small number directly to a string using cast(), it is displayed in scientific notation, which may not be desirable. However, it is recommended to use the format()
function, which allows for precise control over the output string format.
Converting to Numeric Values
Note that the type of the value
is string in the table erc20_ethereum.evt_Transfer
. You can use the cast()
to convert it to the double or decimal(38, 0) numeric types.
As mentioned earlier, Dune SQL does not support implicit type conversion. When we compare or perform operations on values of different types, it is necessary to ensure that they are of the same (compatible) data type. If they are not, explicit type conversion should be performed using relevant functions or operators. Otherwise, type mismatch errors may occur. Here's another simple example:
Without type conversion, the following SQL will result in an error in Dune SQL:
Explicit type conversion allows for the execution as the following in Dune SQL:
When encountering errors like "Error: Line 47:1: column 1 in UNION query has incompatible types: integer, varchar(1) at line 47, position 1," it is necessary to address the type compatibility issues of the respective fields.
Dune SQL supports integer types such as int
and bigint
. However, numeric values can often be very large due to the lack of support for decimals in blockchain systems like EVM. For example, we may encounter errors related to numeric overflow when calculating gas fees. In the following SQL, we intentionally cause an error by multiplying the calculated gas fee by 1000:
Executing the above SQL will result in an error:
To avoid type overflow errors, we can explicitly convert the first parameter to double type. The following SQL will execute correctly:
Similarly, if two values are of bigint type and their division is performed, the result will be truncated to an integer and discarded the decimal portion. To obtain the decimal portion in the result, the dividend should be explicitly converted to double type.
Executing the above SQL, the value of gas_used_percentage will be either 0 or 1, and the decimal part will be discarded and rounded up. Clearly, this is not the desired outcome. By explicitly converting the dividend gas_used to double type, we can obtain the correct result:
Dune SQL defines a set of new functions to handle the conversion of varbinary type strings to decimal numeric values. The string must start with the prefix 0x
.
For detailed assistance, please refer: Byte Array to Numeric Functions.
Numeric Sequences
The syntax for generating numeric sequences in Dune SQL is as follows:
Date Sequences
Dune SQL utilizes the unnest()
in conjunction with sequence()
to generate date sequence values and convert them into multiple rows of records.
The syntax for generating date sequences in Dune SQL is as follows:
Dune SQL utilizes the cardinality()
to query the size of an array.
The syntax for array queries in Dune SQL is as follows:
Dune SQL's array indexing starts counting from 1.
Accessing Array Elements in Dune SQL:
Splitting Array Elements into Multiple Rows of Records
Splitting array elements into multiple rows of records in Dune SQL:
Splitting Multiple Array Fields into Multiple Rows of Records To split multiple array fields into multiple rows (assuming they have the same length), Dune SQL can include multiple fields within the unnest()
and output corresponding fields simultaneously.
Splitting multiple array elements into multiple rows in Dune SQL:
It is a straightforward process to migrate queries written in the existing Spark SQL engine to Dune SQL. You can directly access the Edit interface of the query and switch to "1. v2 Dune SQL" from the left dropdown menu of datasets. Then, make the necessary adjustments to the query content, as described in the previous sections of this article. Here's an example:
Spark SQL Version: https://dune.com/queries/1773896 Dune SQL Version: https://dune.com/queries/1000162
Here is a comparison of the modifications during the migration:
Dune SQL also has a potential advanced feature that allows querying based on a saved query (Query of Query). This feature offers a lot of possibilities for simplifying query logic and optimizing cache usage. For example, you can save the base part of a complex query as a query itself and then perform further aggregation and analysis based on that query. However, this feature may still be unstable at times. Nevertheless, you can give it a try.
Sixdegree
is a professional onchain data analysis team Our mission is to provide users with accurate onchain data charts, analysis, and insights. We are committed to popularizing onchain data analysis. By building a community and writing tutorials, among other initiatives, we train onchain data analysts, output valuable analysis content, promote the community to build the data layer of the blockchain, and cultivate talents for the broad future of blockchain data applications. Welcome to the community exchange!
Website: sixdegree.xyz
Email: contact@sixdegree.xyz
Twitter: twitter.com/SixdegreeLab
Dune: dune.com/sixdegree
Github: https://github.com/SixdegreeLab