# Dune基础入门-part1

By [sherry](https://paragraph.com/@sherry-3) · 2022-07-05

---

网址：[https://dune.com/browse/dashboards](https://dune.com/browse/dashboards)

**dune简介**

区块链的本质是一个分布式的公共账本，所有的数据在链上公开透明，包括每一笔转账，每一次的合约调用。Dune将链上数据聚合到可访问的PostgreSQL数据库中，是进行链上数据分析的工具。用户可以通过PostgreSQL查询链上数据并将数据可视化，汇总成dashboard。

**常用数据表介绍**

Dune数据表架构如下：

`raw transaction data: 原始交易数据。`

`decoded data: 解码后的智能合约数据。`

`abstractions: 更高级别的按照主题聚合的数据表，比如price.usd等。在GitHub上可以找到每张表的创建逻辑，链接如下。`

[https://github.com/duneanalytics/abstractions/tree/master/ethereum](https://github.com/duneanalytics/abstractions/tree/master/ethereum)

以ethereum链为例，下图是转移token的过程产生的数据流转。假设现在要在链上转移USDT，就会调用transfer函数，指定接收者和转移的金额，对此条交易进行签名，那么此时链上就会产生calldata数据，dune将这个数据存在了ethereum.transaction表中，这张表主要包含以下字段～from(发送交易的人的地址/签名者)，to(合约交互的地址，现在转移的是USDT，那么就是USDT的合约地址)，success(这条交易是成功？还是失败？)，value(表示的是转移的ETH数值，那现在转移的是USDT，没有转移ETH，所以在这条交易中value的值为0)，gas\_column(主要记录交易的gas使用情况，有gas limit，gas used，gas price)，hash(在链上进行的每次行为都会产生一个唯一的transaction hash，这个值也是用来多表关联的唯一主键)，blocknumber，blocktime主要记录交易发生的区块和时间～

转移USDT的合约调用过程，也称为内部交易/子交易，数据存在了ethereum.traces表中。

交易执行的日志数据，包括签名者、接收者、topic、转账金额等等存在ethereum.logs表中。

![](https://storage.googleapis.com/papyrus_images/64d407bd8bcff4f609674cb4ecff781ab54f97c3234d98a39bdfea30c6b97ff9.png)

ethereum.transaction: eth交易数据

![](https://storage.googleapis.com/papyrus_images/6ce4ad92cacf1d7a5638f1fdf6dc334c2240fdb4dd6116389be9c8a08efb5781.png)

ethereum.traces:eth“内部”交易数据

![](https://storage.googleapis.com/papyrus_images/f1c8ab4b5dcd00fc9f48c90278f51fff461a97afb7cc1b6c9bc5cfa8ec9ef3e2.png)

ethereum.logs:eth交易事件日志

![](https://storage.googleapis.com/papyrus_images/e69dc6d4085a0eea6135950f858d472e62195180efdc28beb59af916d650283c.png)

**SQL基础入门**

SQL是结构化查询语言，用于存取、查询、升级和管理相关的数据库系统。我们以三箭资本的一个地址(0x676Aecc97bF721C3cb3329A22D49C0ea0ED375F7)在eth链的交易数据为例展开讲解分析～

*   查询数据
    
    select \* from ethereum."transactions" order by block\_time desc limit 10
    

![](https://storage.googleapis.com/papyrus_images/2f4fc90be3268127f7dc9791a8a44d8a828e5f99fa4ce64260d4488485ef9a8f.png)

其中select后面表示的是需要的数据字段，\*代表数据表中所有的字段，如果只想选取其中一些字段，则select后面加上相应的字段名就可以了，from后面为数据表，order by表示按照block\_number的顺序排列显示结果，desc为降序，asc为升序。limit是为了限制数据量，否则语句将返回表中全部数据。

*   过滤数据
    
    select \* from ethereum."transactions"
    

where "from" ='\\x676Aecc97bF721C3cb3329A22D49C0ea0ED375F7' order by block\_time desc limit 100

![](https://storage.googleapis.com/papyrus_images/8a25036a8dc39b07381851605a7668399c290b50e928f73e67bd8475192de528.png)

where后面表示根据指定条件对结果进行过滤，只筛选出字段from=\\x676Aecc97bF721C3cb3329A22D49C0ea0ED375F7的数据，即钱包0x676Aecc97bF721C3cb3329A22D49C0ea0ED375F7(三箭资本)的交易数据。

*   多表连接
    

![](https://storage.googleapis.com/papyrus_images/a2cb3997f29fe13b77ba69cab228b5f30d6afe9c54cb8276ccad406d74657de2.png)

比如我想知道这个地址0x676Aecc97bF721C3cb3329A22D49C0ea0ED375F7的账户余额。

with total\_token as ( SELECT token\_address, sum(amount) as amount FROM erc20."view\_token\_balances\_latest" WHERE "wallet\_address" IN ('\\x676aecc97bf721c3cb3329a22d49c0ea0ed375f7') group by token\_address ), token\_price as ( select contract\_address, price from prices.usd where minute-date\_trunc('minute', now())='-06:00:00' AND contract\_address in (select token\_address from total\_token) and price >0 ) Select sum(a.amount \* b.price) as Value from total\_token a left join token\_price b on a.token\_address=b.contract\_address

![](https://storage.googleapis.com/papyrus_images/db2ed99e7c2d76f9608f14eacded52a704d0be2028e577855d6bac453b1c6489.png)

on后面的语句表示将两表连接起来的条件。

在链上交易数据中，Transaction Hash是唯一的，因此Transaction Hash是将表连接起来的唯一主键。

*   数据聚合
    
    select date\_trunc('day', block\_time) date, sum(value)/1e18 as value
    
    from ethereum."transactions"
    
    where "from" ='\\x676Aecc97bF721C3cb3329A22D49C0ea0ED375F7'
    
    and block\_time>='2022-01-01'
    
    and block\_time<now()
    
    group by date\_trunc('day', block\_time)
    
    order by date\_trunc('day', block\_time) desc
    

![](https://storage.googleapis.com/papyrus_images/f12bfa92bd03f865094af75146d5a0324cf2b8008b6f84dc970087cf447d191b.png)

group by函数可以根据一列或者多列对结果进行汇总。其中date\_trunc('day', block\_time)函数为时间截断函数，可以根据指定的日期部分(比如hour,day,month等)对时间戳表达式进行截断。group by date\_trunc('day', block\_time) 表示按照date\_trunc('day', block\_time)即date字段进行汇总，也可以简写为group by 1即按照第一个字段汇总。order by date\_trunc('day', block\_time) desc表示按照date字段降序排列结果。

当有了这种汇总结果后，可以建立我们的第一个数据可视化图表～点击New visualization，可以选择你想使用的可视化图表以及x轴和y轴数据，就对数据进行展示啦。

![](https://storage.googleapis.com/papyrus_images/08557882a8d1b062563e1a40685de3ee5d4bb33013119dc96106638fac6a28e6.png)

*   常用聚合函数
    
    sum() 求和函数、count() 计数函数、avg() 求平均值函数、min()求最小值函数、max()求最大值函数、Cumulative Sum() 累加函数等等。
    
    比如我想知道0x676Aecc97bF721C3cb3329A22D49C0ea0ED375F7这个地址一共发出过多少ETH，一共对外发出的交易次数等等。
    
    select sum(value)/1e18 as sum\_value, count(1) as trans\_cnt
    

from ethereum."transactions"where "from"='\\x676Aecc97bF721C3cb3329A22D49C0ea0ED375F7'

可以看出0x676Aecc97bF721C3cb3329A22D49C0ea0ED375F7这个地址一共发出了365454个ETH，一共对外发出交易次数为6887次。

*   总结
    
    当会了一些基本的SQL语句后，我们就可以从数据表中查询任何我们需要的数据啦。但是会写SQL只是作为一名数据分析师的基本功，我认为最重要的还是理解数据并用数据讲故事，在数据中能总结发现出一些有意思的东西～

---

*Originally published on [sherry](https://paragraph.com/@sherry-3/dune-part1)*
