跳到主要内容

SQL Essentials:第1部分

关系数据库和用于查询它们的语言日期回到20世纪70年代. 时至今日,结构化查询语言(SQL)仍然是分析师与关系数据库及其基于云的专栏式对应数据库(数据仓库)通信的标准手段。

本指南假设您具有SQL的基本知识,但将介绍一些您可能不知道的概念、函数和关键语法。在本系列的第1部分中,我们将讨论以下基本主题:

  1. 超越选择:操作顺序

  2. 别名表

  3. 常见的表格表达式

  4. 制作更好的连接

超越选择:操作顺序

SELECT语句构成了您将写入的大多数SQL。因此,可以完全理解,并且在采访中是一个共同的介绍问题。在现代数据流水线和elt的上下文中,甚至创建和插入语句常常仅用为SELECT语句周围的包装器。

除此之外,重要的是要大致了解这些部分将由DB本身执行的顺序。超越基础知识的这一小幅度将在您深入编写SQL时良好地为您服务。

请注意以下查询中括号中的数字:

从(1)连接(1b)中,选择(_)表达式(7)表达式(3)Window_functions(6),其中(2)组(4)BY(8)限制(9)

理解必须晚于巩固两者之间的差异的地方。Where子句告诉系统只能提取符合某些标准的单个记录。具有子句筛选条件,但对于由组副子句汇总的记录。回想一下,组由子句组合在一起的行,然后允许聚合操作,例如SUM和COUNT,它在分组的行中执行计算,从而产生一个输出行。

除了基础知识,当我们遇到更困难的问题时,了解排序和执行的基础知识将非常有用。当性能考虑因素与数据仓库设计相关时,它特别有用,尽管这些主题都不在本文的讨论范围之内。

一个整洁的例子是订购事项的知识是窗口函数的情况(这在本文中的深度深度)。窗口函数在“选择”列表中写入,但在聚合和聚合过滤之后发生大部分计算(具有)。基本上,窗口函数在选择表达式的所有其他部分之后计算,除了订单和限制。雪花有一个可爱的具有资格语法,允许对窗口函数进行筛选。限定为行数(一个窗口函数)等于求和(一个聚合函数)。下面是理论SQL,其组合部分按执行顺序编号。

从订单中选择不同的--(6)--(3)用户id、订单id、收入、第一个价值(订单id)作为第一个订单id--(4b)(1)其中用户年龄>20--(2)限定第一个价值(收入)超过(按用户id按创建的订单进行划分)>0--(4a)仅返回用户第一个订单不是用户id ASC的自由订单的结果--(5)限制100--(6)

在其他雪花中,您将被迫产生以下内容。人们可以看到伪执行顺序由于添加的语法(即子查询)的结果,伪执行顺序不会更大。虽然清洁剂读取大致相同的工作必须在引擎盖下完成。:

Prep As(选择Distinct - (6) - (3)User_ID,Order_ID,收入, - (4)First_Value(Order_ID)over(created_at按user_id顺序分区)作为first_order_id,first_value(收入)超过(分区by eryer_id顺序由created_at)从订单中作为first_order_value - (1)其中user_age> 20 - (2))从prep - (5)中选择* - (7),其中first_order_value> 0 - (6)以前4b按User_ID ASC - (8)限制100 - (9)

有关窗口函数的更深入的处理,请参见第2部分这个系列。

别名表

别名是将新名称分配给表,列和表达式。在表别名的情况下,它通常被削弱 - 甚至完全省略。虽然分析师在选择列表中的别名列或表达式的重要性早期了解,但是桌子别名的效益很容易被忽视。甚至调味兽医甚至是使用完整的表名而不是别名,并在解析器可以弄清楚的地方完全省略别名是令人惊讶的。

虽然前者唯一的问题是它的长荫,但后者难以阅读,因此可以导致错误。采取以下例子:

  • 使用者

    • ID

    • 姓名

  • 订单

    • ORDER_ID.

    • 用户身份

    • 地位

    • 收入

从订单中选择user_id,姓名,状态,uk(收入)everge in id = user_id组上的订单lejined of expers

虽然此查询将在其当前情况下运行,但它面临两个问题:

1) 新列正在联接到源表。例如,如果将“状态”添加到“用户”中,(例如,显示他们是否已完成注册),现在将引入错误,因为“用户”和“订单”之间的“状态”不明确。虽然在一个查询中不难找到这一点,但现实世界的情况却不那么宽容。在大量大型、计划查询中,充满了连接和复杂性,这种情况可能是一场噩梦。

2) 上述查询包含“名称”和“用户id”。如果以后可能不再需要“name”(可能最初只是为了调试目的才包括它),则可能会将其从选择列表中删除。这使得“LEFT JOIN users”语句多余。上述情况经常发生,因此会创建“孤立联接”。在上面,我们只处理4列和2个表,因此不需要的连接很容易找到。但是,在一个更真实的示例中(可能包含数百列),每个无别名的列都会增加孤立联接的风险。由于数据团队中的那些专业人员(与解析器不同)不知道所有的列,因此如果不能确定是否不需要连接,则通常更安全的做法是保留连接。然而,每一个这样的表都会增加代码的长度,从而降低可读性,并增加冲突的可能性。

以下替代方案解决了上述两个问题,并使代码更容易一眼就能理解:

选择O.User_ID,如果省略“名称”列,我们可以看到“左加入用户”不需要U.Name,O.Status,Sum(o.revenue)作为offly_revenue作为o left加入用户的订单U在U.id = O.User_ID组上1,2,3

黄金规则:如果有多个表,则每列参考别名

短表别名通常可读性很强,但为了获得更高的可用性,您应该就团队中常用表的通用别名达成一致。

常见的表格表达式

公共表表达式(CTE)是对所有分析人员来说必不可少的另一种SQL语法。子查询可以创建一个杂乱的,嵌套的混乱,几乎不可能读取。CTE提供了一个新的选择。它们允许您编写可以从上到下线性读取的查询,允许团队中的任何成员在从表格到输出的过程中快速理解您的路径(以及您的思维过程)。cte还可以提供递归查询模式和更清晰的代码重用,但到目前为止,最有用的方面是简单的可读性。作为一个经验法则:总是在子查询上使用CTE,如果您需要使用子查询,请确保它在一行中清晰地读取。

使用load_range(选择min(event_at)为start_at,max(event_at)从raw_data.events_load)选择*,(从last_load中选择end_at)从raw_data.production_orders of lev加入raw_data.events_orders o o o。ORDER_ID = e.ORDER_ID其中O.CREATED_AT(从load_range选择start_at)和(从load_range选择end_at)

更好地加入

加入是一个典型的SQL工具。但是,有两个通常被忽视的连接属性超出基本内部,左和全外连接。它们是自然连接和使用关键字。我们大多数人都会通过ON获得加入的介绍,并经常花时间使用在每个表中拥有“ID”列的生产DBS。由于这些原因,在路边使用和自然跌倒,直到我们深入了解我们的清洁金球,模拟的事实和昏暗(尺寸)。这两个概念都依赖于加入表共享相同名称的列。

例如,给定表格

  • dims.users.

    • 用户身份

    • User_name

  • 事实、命令

    • 目前为止,

    • User_id,

    • Order_ID,

    • 收入

以下都是等同的

从事实。order AS o INNER JOIN dim。user AS u ON u.user_id = o.user_id

从事实上。作为o Inner Join的代号。使用(User_ID)作为UNERS

从事实上.Orders作为自然内部连接Dims.users作为你

从上到下,每个连续的方法都将SQL编写器的更多控制权交给解析引擎。虽然我更喜欢ON-join的显式性质(特别是在SQL转换代码中),但是使用和自然都是值得了解的。一个很好的用例是两个事实表在连接之前要上卷到一个共享粒度。

WITH session_data AS ( SELECT DATE_TRUNC(‘week’,date) AS week, Age_bucket, SUM(sessions) AS sessions, SUM(revenue) AS revenue FROM facts.sessions ), Cost_data AS ( SELECT Week, SUM(cost) AS cost FROM facts.marketing_spend ) SELECT s.week, s.age_bucket, s.sessions, s.revenue, C.cost FROM session_data NATURAL LEFT JOIN cost_data

结论

选择语句,别名,常用表表达式和加入是所有初学者概念,但具有许多对SQL的休闲用户不一定明显的细微差别。采取这些提示和技巧,以心中,您的SQL游戏将以非常基本的水平提高。