Title: SQL 查询 Locale: zh URL: https://sensorswave.com/docs/analytics/sql-query/ Description: 使用 SQL 进行灵活的自定义数据查询 SQL 查询是 Sensors Wave 最灵活和强大的数据分析工具。当预定义的分析模型无法满足您的需求时,您可以使用 SQL 直接查询底层数据,进行任意复杂的自定义分析。通过 SQL 查询,您可以完全掌控数据分析的逻辑,轻松应对各种复杂的数据分析需求。 SQL 查询基于 Apache Doris 查询引擎构建,支持标准 SQL 语法,并提供友好的编辑器和可视化工具,让您快速开发、执行和管理 SQL 查询。 ## 典型使用场景 SQL 查询可以帮助您解决以下分析问题: **复杂的跨表关联分析**: - 关联用户表和事件表,分析不同用户属性群体的事件表现 - 关联事件表和自定义维度表,丰富事件数据维度 - 多表 JOIN 组织复杂的分析逻辑 **高级数据聚合与统计**: - 多维度透视和交叉分析 - 自定义聚合函数和窗口函数 - 复杂的分组、排序和过滤条件 **用户分群与用户运营**: - 基于行为特征定义用户分群 - 计算用户的累计指标和生命周期价值 - 实现复杂的用户分层逻辑 **性能指标和监控**: - 自定义关键业务指标的计算 - 实时监控和告警数据的生成 - 对比期间对标分析 **数据质量和审计**: - 检测数据异常和重复 - 查询日志分析和性能诊断 - 用户行为的合规性审计 ## 前提条件 在使用 SQL 查询之前,请确保您已经: - 完成了 [SDK 集成](../data-integration/client-sdks/javascript.mdx) 并开始接收数据 - 理解了 [数据模型](../data-integration/data-model.mdx) 的核心概念 - 具备项目的查看或分析权限,详见 [角色和用户权限](../10-组织与项目/03-角色和用户权限.md) - 熟悉基本的 SQL 语法(可选,但建议) ## 快速开始 ### 打开 SQL 查询编辑器 1. 点击左侧导航栏的 **数据洞察** 2. 点击右上角的 **新建分析** 按钮 3. 选择 **SQL 查询** 选项 4. 系统将打开 SQL 编辑器页面 ### 编写和执行您的第一个查询 1. 在左侧的元数据浏览区,查看可用的表和字段 2. 在右上角的编辑器中输入 SQL 语句 3. 点击 **执行** 按钮(或使用快捷键 `Ctrl+Enter`)运行查询 4. 在右下角的结果区查看查询结果 **简单示例**:查询过去 7 天内最活跃的 10 个用户 ```sql SELECT login_id, COUNT(*) as event_count FROM events WHERE time >= DATE_SUB(NOW(), INTERVAL 7 DAY) AND login_id IS NOT NULL GROUP BY login_id ORDER BY event_count DESC LIMIT 10 ``` ### 保存和复用查询 完成 SQL 查询编写后,您可以: 1. 点击 **保存** 按钮,为查询命名并保存到"我的查询" 2. 点击 **可视化** 按钮,将结果转换为图表 3. 点击 **添加到报表** 按钮,将图表添加到报表中 4. 点击 **下载** 按钮,导出查询结果为 CSV 或 Excel 文件 ## 界面功能详解 ### 1. 左侧:元数据浏览区 左侧的元数据浏览区展示了所有可查询的表和它们的列信息,帮助您快速了解数据结构。 #### 表列表 系统默认提供以下四张表: | 表名 | 说明 | 行数示例 | |-----|------|--------| | **events** | 事件表,记录所有用户行为事件 | ~194 行 | | **users** | 用户表,存储用户的属性信息 | ~94 行 | | **cohorts** | 用户分群表,存储分群结果 | ~1 行 | | **query_log** | 查询日志表,记录所有 SQL 查询历史 | ~31 行 | > **提示**:括号中的数字表示表中的行数,这只是示意,实际行数取决于您的数据量。 #### 字段信息 点击表名可以展开查看该表的所有字段: - **字段名**:列的名称 - **字段类型**:列的数据类型(如 varchar、int、datetime 等) - **说明**:该字段的含义和用途 您可以: - 点击字段名快速将其复制到编辑器 - 搜索字段快速定位所需的列 - 了解字段的数据类型选择合适的 SQL 函数 ### 2. 右上角:编辑和执行区 右上角的编辑和执行区提供完整的 SQL 编辑和运行功能。 #### 功能按钮 **编辑功能**: - **撤销/重做**:撤销或重做编辑操作 - **格式化**:自动格式化 SQL 语句,使代码更易读 - **复制**:将 SQL 语句复制到剪贴板 **执行功能**: - **执行**:运行当前 SQL 查询(快捷键:Ctrl+Enter) - **停止**:中断正在运行的查询 - **保存**:保存查询到"我的查询"列表 **可视化和分享**: - **可视化**:将查询结果转换为图表(折线图、柱状图等) - **图表设置**:配置图表的标题、坐标轴、颜色等 - **添加到报表**:将生成的图表添加到现有报表中 #### SQL 编辑器 编辑器支持以下高级功能: **代码补全**: - 支持关键字补全(SELECT、WHERE、GROUP BY 等) - 支持表名补全(events、users 等) - 支持字段名补全(根据当前输入的表名) **语法高亮**: - SQL 关键字显示为蓝色 - 字符串显示为红色 - 数字显示为绿色 - 提升代码可读性 **错误提示**: - 当 SQL 语法错误时,编辑器会在错误行显示红色波浪线 - 悬停错误处可查看详细的错误信息 **快捷键**: - `Ctrl+Enter`:执行查询 - `Ctrl+/`:快速注释/取消注释 - `Ctrl+Z`:撤销 - `Ctrl+Y`:重做 ### 3. 右下角:查询结果区 右下角的结果区展示 SQL 查询的执行结果。 #### 结果表格 - **列表展示**:以表格形式展示查询结果,每行对应一条数据 - **列宽自适应**:系统自动调整列宽以适配内容 - **列排序**:点击列标题可按该列升序或降序排列 - **列隐藏/显示**:右键列标题可隐藏或显示某些列 #### 翻页和下载 - **翻页控制**:查询结果默认分页显示(每页 20 条),可在底部选择跳转的页码 - **行数显示**:显示当前页的行数范围和总行数 - **下载**:点击 **下载** 按钮可导出结果为: - CSV 格式:便于 Excel 或其他工具打开 - Excel 格式:自动格式化表格 - 图片格式:若已转换为图表则可导出为 PNG #### 执行信息 查询执行后,系统会展示以下信息: - **执行时间**:查询耗时(毫秒) - **返回行数**:查询结果的行数 - **查询 ID**:系统分配的唯一查询 ID,用于在查询日志中追踪 ## 可查询的表详解 ### events 表(事件表) 事件表是数据模型的核心,记录所有用户行为事件。详细的事件表字段说明,请参考 [数据模型 - 事件表](../data-integration/data-model.mdx#事件表-events)。 **核心字段速查**: | 字段名 | 数据类型 | 说明 | 示例 | |-------|---------|------|------| | `time` | datetime | 事件发生时间 | 2026-01-27 10:30:00 | | `event` | varchar | 事件名称 | PageView, Purchase | | `event_id` | int | 事件 ID | 12345 | | `distinct_id` | varchar | 当前生效的用户唯一标识 | abc123 | | `anon_id` | varchar | 匿名 ID(设备标识) | device_xyz | | `login_id` | varchar | 登录 ID(用户账号) | user_12345 | | `ssid` | bigint | 服务端生成的用户唯一 ID | 9876543 | | `trace_id` | varchar | 事件去重 ID | trace_abc123 | | `received_at` | datetime | 服务端接收时间 | 2026-01-27 10:30:05 | | `e_*` | 各类型 | 事件属性(前缀为 e_) | e_product_id, e_category | | `u_*` | 各类型 | 用户属性快照(前缀为 u_) | u_age, u_vip_level | **常用查询示例**: ```sql -- 查询某事件的触发次数和触发用户数 SELECT event, COUNT(*) as event_count, COUNT(DISTINCT ssid) as user_count FROM events WHERE time >= DATE_SUB(NOW(), INTERVAL 7 DAY) GROUP BY event ORDER BY event_count DESC; -- 查询特定用户的最近 10 次行为 SELECT time, event, e_product_id, u_vip_level FROM events WHERE login_id = 'user_12345' ORDER BY time DESC LIMIT 10; -- 查询事件属性值的分布 SELECT e_category, COUNT(*) as count FROM events WHERE event = 'PageView' AND time >= DATE_SUB(NOW(), INTERVAL 30 DAY) GROUP BY e_category ORDER BY count DESC; ``` ### users 表(用户表) 用户表存储用户的基本信息和属性数据。详细的用户表字段说明,请参考 [数据模型 - 用户表](../data-integration/data-model.mdx#用户表-users)。 **核心字段速查**: | 字段名 | 数据类型 | 说明 | 示例 | |-------|---------|------|------| | `ssid` | bigint | 用户唯一 ID(主键) | 9876543 | | `login_id` | varchar | 登录 ID | user_12345 | | `anon_id` | array | 设备 ID 列表 | ['device_xyz'] | | `$first_seen_time` | datetime | 首次访问时间 | 2025-01-01 14:30:00 | | `$last_seen_time` | datetime | 最后活跃时间 | 2026-01-27 09:15:00 | | `created_at` | datetime | 用户记录创建时间 | 2025-01-01 14:30:05 | | `updated_at` | datetime | 用户记录最后更新时间 | 2026-01-27 09:15:05 | | `u_*` | 各类型 | 用户属性(前缀为 u_) | u_age, u_vip_level | **常用查询示例**: ```sql -- 查询活跃用户统计 SELECT COUNT(*) as total_users, COUNT(DISTINCT login_id) as active_users, ROUND(DATEDIFF(NOW(), AVG($first_seen_time))) as avg_days_active FROM users WHERE $last_seen_time >= DATE_SUB(NOW(), INTERVAL 30 DAY); -- 查询用户注册来源分布 SELECT u_signup_channel, COUNT(*) as user_count, ROUND(100.0 * COUNT(*) / (SELECT COUNT(*) FROM users), 2) as percentage FROM users GROUP BY u_signup_channel ORDER BY user_count DESC; -- 查询新老用户对比 SELECT CASE WHEN DATEDIFF(NOW(), $first_seen_time) | 查询涉及的事件名称列表 | | `cohorts` | array | 查询涉及的分群 ID 列表 | | `event_properties` | array | 查询涉及的事件属性列表 | | `user_properties` | array | 查询涉及的用户属性列表 | | `hit_sql_cache` | tinyint | 是否命中 SQL 函数缓存 | | `error_code` | int | Doris 错误码(成功时为 0) | | `error_message` | varchar | Doris 错误信息 | **常用查询示例**: ```sql -- 查询最慢的 10 个查询 SELECT query_id, start_time, cost_time_ms, account, status FROM query_log WHERE status = 'SUCCESS' ORDER BY cost_time_ms DESC LIMIT 10; -- 统计用户的查询情况 SELECT account, COUNT(*) as query_count, ROUND(AVG(cost_time_ms)) as avg_cost_ms, MAX(cost_time_ms) as max_cost_ms, SUM(CASE WHEN status = 'SUCCESS' THEN 1 ELSE 0 END) as success_count FROM query_log WHERE start_time >= DATE_SUB(NOW(), INTERVAL 7 DAY) GROUP BY account ORDER BY query_count DESC; -- 查询内存占用过高的查询 SELECT query_id, start_time, query_type, cost_time_ms, peak_memory_bytes, scan_rows, return_rows FROM query_log WHERE peak_memory_bytes > 1024 * 1024 * 1024 -- 大于 1GB AND status = 'SUCCESS' ORDER BY peak_memory_bytes DESC LIMIT 20; -- 分析查询缓存命中率 SELECT DATE(start_time) as query_date, COUNT(*) as total_queries, SUM(CASE WHEN cache_hit = true THEN 1 ELSE 0 END) as cache_hit_count, ROUND(100.0 * SUM(CASE WHEN cache_hit = true THEN 1 ELSE 0 END) / COUNT(*), 2) as cache_hit_rate FROM query_log WHERE start_time >= DATE_SUB(NOW(), INTERVAL 30 DAY) GROUP BY DATE(start_time) ORDER BY query_date DESC; ``` ## 表关联示例 ### 事件表与用户表关联 关联事件和用户属性进行分析: ```sql SELECT e.login_id, u.u_vip_level, u.u_city, COUNT(*) as event_count, COUNT(DISTINCT e.event) as event_variety FROM events e INNER JOIN users u ON e.ssid = u.ssid WHERE e.time >= DATE_SUB(NOW(), INTERVAL 30 DAY) GROUP BY e.login_id, u.u_vip_level, u.u_city ORDER BY event_count DESC LIMIT 20; ``` ### 事件表与分群表关联 分析特定分群的事件表现: ```sql SELECT e.event, COUNT(*) as event_count, COUNT(DISTINCT e.ssid) as user_count FROM events e INNER JOIN cohorts c ON e.ssid = c.ssid WHERE c.cohort_123 = true -- 假设分群 ID 为 123 AND e.time >= DATE_SUB(NOW(), INTERVAL 7 DAY) GROUP BY e.event ORDER BY event_count DESC; ``` ### 多表关联 关联事件、用户和分群进行深度分析: ```sql SELECT u.u_city, c.cohort_name, COUNT(*) as event_count, ROUND(AVG(e.e_purchase_amount), 2) as avg_amount FROM events e INNER JOIN users u ON e.ssid = u.ssid INNER JOIN cohorts c ON e.ssid = c.ssid WHERE e.event = 'Purchase' AND e.time >= DATE_SUB(NOW(), INTERVAL 30 DAY) GROUP BY u.u_city, c.cohort_name ORDER BY event_count DESC; ``` ## SQL 最佳实践 ### 1. 查询性能优化 **使用时间范围筛选**: ```sql -- [推荐] 好的做法:明确指定时间范围 SELECT * FROM events WHERE time >= DATE_SUB(NOW(), INTERVAL 30 DAY) AND event = 'Purchase'; -- [避免] 避免:查询全量数据 SELECT * FROM events WHERE event = 'Purchase'; ``` **使用索引字段**: ```sql -- [推荐] 优先使用索引字段(time, event, ssid 等)进行筛选 SELECT * FROM events WHERE time >= '2026-01-01' AND event = 'PageView' AND ssid = 12345; -- [避免] 避免:仅对高基数字段(e_product_id)进行筛选 SELECT * FROM events WHERE e_product_id = 'SKU123'; ``` **合理使用 GROUP BY**: ```sql -- [推荐] 好的做法:分组字段基数较低 SELECT event, COUNT(*) FROM events GROUP BY event; -- [避免] 避免:对高基数字段分组 SELECT e_product_id, COUNT(*) FROM events GROUP BY e_product_id; -- 可能产生数百万个分组 ``` ### 2. 数据准确性 **检查空值处理**: ```sql -- [推荐] 使用 IS NOT NULL 或 IS NULL 明确处理空值 SELECT COUNT(DISTINCT ssid) FROM events WHERE login_id IS NOT NULL AND time >= DATE_SUB(NOW(), INTERVAL 7 DAY); -- [注意] 注意:空值在聚合时可能被忽略 SELECT COUNT(DISTINCT e_product_id) FROM events; -- 包含 NULL 值时的行为 ``` **使用 DISTINCT 去重**: ```sql -- [推荐] 统计去重用户数 SELECT COUNT(DISTINCT ssid) FROM events; -- [避免] 避免:直接计数可能重复 SELECT COUNT(ssid) FROM events; -- 这会包含重复的用户 ``` **验证数据一致性**: ```sql -- [推荐] 定期检查事件和用户表的关联 SELECT COUNT(*) as orphaned_events FROM events e LEFT JOIN users u ON e.ssid = u.ssid WHERE u.ssid IS NULL; -- 检查孤立的事件(没有对应用户) ``` ### 3. 代码可读性 **使用明确的列别名**: ```sql -- [推荐] 使用有意义的别名 SELECT login_id as user_account, COUNT(*) as total_events, COUNT(DISTINCT event) as event_types FROM events GROUP BY login_id; -- [避免] 避免:无意义或过长的别名 SELECT login_id as a, COUNT(*) as b FROM events GROUP BY login_id; ``` **添加有意义的注释**: ```sql -- 查询过去 7 天内的高频搜索用户 SELECT login_id, COUNT(*) as search_count FROM events WHERE event = 'Search' -- 只统计搜索事件 AND time >= DATE_SUB(NOW(), INTERVAL 7 DAY) -- 限制时间范围 AND login_id IS NOT NULL -- 排除匿名用户 GROUP BY login_id HAVING COUNT(*) >= 10 -- 只看搜索超过 10 次的用户 ORDER BY search_count DESC; ``` **合理使用 WHERE 和 HAVING**: ```sql -- [推荐] WHERE 用于单行筛选,HAVING 用于聚合筛选 SELECT u_city, COUNT(*) as user_count FROM users WHERE u_vip_level = 'gold' -- 单行条件用 WHERE GROUP BY u_city HAVING COUNT(*) >= 100; -- 聚合条件用 HAVING ``` ### 4. 常见陷阱 **关于 login_id 的 NULL 值**: ```sql -- [注意] 注意:未登录用户的 login_id 为 NULL -- 如果需要分析已登录用户,需要明确过滤: SELECT login_id, COUNT(*) FROM events WHERE login_id IS NOT NULL -- 重要:排除未登录用户 GROUP BY login_id; ``` **关于 distinct_id 的使用**: ```sql -- [提示] 提示:distinct_id 是当前生效的标识(登录 ID 优先,否则为匿名 ID) -- 如果需要区分已登录和未登录: SELECT CASE WHEN login_id IS NOT NULL THEN login_id ELSE anon_id END as user_identifier, COUNT(*) FROM events GROUP BY user_identifier; ``` **避免重复计数**: ```sql -- [错误] 错误:多个 COUNT(DISTINCT) 可能导致结果不准确 -- (在涉及 JOIN 的复杂查询中尤其要注意) SELECT event, COUNT(DISTINCT ssid), -- 如果有 JOIN,可能计数不准 COUNT(DISTINCT e_product_id) FROM events GROUP BY event; -- [推荐] 正确做法:使用子查询或窗口函数 SELECT event, COUNT(DISTINCT ssid) as user_count, COUNT(DISTINCT e_product_id) as product_count FROM events GROUP BY event; ``` ## 分析模式示例 ### 用户生命周期分析 ```sql -- 分析用户的生命周期价值 SELECT ssid, login_id, DATEDIFF(NOW(), $first_seen_time) as days_active, DATEDIFF($last_seen_time, $first_seen_time) as lifespan_days, COUNT(DISTINCT DATE(time)) as active_days, COUNT(*) as total_events, COUNT(DISTINCT event) as event_types FROM events WHERE $first_seen_time IS NOT NULL GROUP BY ssid, login_id, $first_seen_time, $last_seen_time ORDER BY total_events DESC LIMIT 100; ``` ### 转化漏斗分析 ```sql -- 分析用户转化漏斗(浏览 → 加购 → 支付) WITH funnel_steps AS ( SELECT ssid, MAX(CASE WHEN event = 'PageView' THEN 1 ELSE 0 END) as has_view, MAX(CASE WHEN event = 'AddCart' THEN 1 ELSE 0 END) as has_addcart, MAX(CASE WHEN event = 'Purchase' THEN 1 ELSE 0 END) as has_purchase FROM events WHERE time >= DATE_SUB(NOW(), INTERVAL 30 DAY) GROUP BY ssid ) SELECT COUNT(*) as total_users, SUM(has_view) as view_users, SUM(has_addcart) as addcart_users, SUM(has_purchase) as purchase_users, ROUND(100.0 * SUM(has_addcart) / SUM(has_view), 2) as addcart_rate, ROUND(100.0 * SUM(has_purchase) / SUM(has_view), 2) as purchase_rate FROM funnel_steps; ``` ### 用户留存分析 ```sql -- 分析用户 7 日留存率 WITH first_active AS ( SELECT ssid, DATE($first_seen_time) as cohort_date FROM users ) SELECT cohort_date, COUNT(DISTINCT u.ssid) as cohort_size, SUM(CASE WHEN DATE(e.time) = DATE_ADD(DATE(u.$first_seen_time), INTERVAL 7 DAY) THEN 1 ELSE 0 END) as day_7_active, ROUND(100.0 * SUM(CASE WHEN DATE(e.time) = DATE_ADD(DATE(u.$first_seen_time), INTERVAL 7 DAY) THEN 1 ELSE 0 END) / COUNT(DISTINCT u.ssid), 2) as retention_rate FROM users u LEFT JOIN events e ON u.ssid = e.ssid GROUP BY cohort_date ORDER BY cohort_date DESC LIMIT 30; ``` ## 注意事项 ### 查询限制 - **超时时间**:单个查询的执行时间不超过 10 分钟,超时会被自动中断 - **结果行数**:单次查询返回的最大行数为 10000 行(可通过 LIMIT 灵活控制) - **并发查询**:同一账号最多同时运行 5 个查询 ### 数据安全 - **查询日志**:所有 SQL 查询都会被记录在 query_log 表中,用于审计 - **权限控制**:用户只能查询其有权访问的项目数据 - **敏感数据**:避免在查询中包含密码、身份证等敏感信息 ### 性能建议 - **避免全表扫描**:始终在 WHERE 子句中包含时间范围限制 - **限制返回行数**:对于大数据量查询,使用 LIMIT 限制返回行数 - **使用缓存**:频繁执行的相同查询会自动缓存,加快响应 - **监控资源**:监控 CPU、内存和 I/O 等资源占用,避免超载 ### 数据延迟 - **实时性**:事件数据通常在 1-5 分钟内写入数据库 - **分群数据**:用户分群的更新可能有 5-10 分钟的延迟 - **查询日志**:查询日志的完整记录可能有 1 分钟左右的延迟 ## 相关文档 **数据模型和概念**: - [数据模型](../data-integration/data-model.mdx):了解事件表、用户表的详细结构 - [事件和属性](../data-integration/events-and-properties.mdx):理解事件属性和用户属性的定义 **SQL 语法参考**: - [Apache Doris SQL 文档](https://doris.apache.org/zh-CN/docs/3.x/sql-manual/sql-statements/data-query/SELECT):完整的 SQL 语法参考和函数手册 **相关分析**: - [找到合适的分析模型](choosing-analysis-model.mdx):了解何时使用 SQL vs 预定义模型 - [事件分析](event-analysis.mdx):使用 UI 分析事件数据 - [用户分群](../05-受众计算/02-用户分群.md):创建用户分群 **可视化和报表**: - [图表管理](../04-可视化与报表/01-图表管理.md):将 SQL 查询结果可视化 - [报表管理](../04-可视化与报表/02-报表管理.md):将图表添加到报表 ## 下一步 完成 SQL 查询后,您可以: 1. **可视化查询结果**:将查询结果转换为折线图、柱状图等,更直观地展示数据 2. **添加到报表**:将重要的查询结果和图表添加到报表中,定期查看 3. **保存为分群**:基于 SQL 查询结果创建用户分群,用于精准营销 4. **查看最佳实践**:参考 [最佳实践](best-practices.mdx) 提升分析效率 6. **解决常见问题**:如遇到问题,请查看 [常见问题](faq.mdx) --- **最后更新时间**:2026 年 2 月 3 日