初学者的实战型SQL教程——应用程序开发基础知识

151 阅读20分钟

结构化查询语言(SQL)是为了与关系型数据库一起工作而开发的,关系型数据库将信息组织和存储在称为表的列和行组中。它们之所以是 "关系型 "的,是因为不同的表之间存在着连接数据的关系(想想:Excel)。

SQL已经持续了几十年,它已经成为行业标准,因为它在处理事务性数据方面具有简易性、多功能性和强大功能。SQL对于初学者来说很容易学习,并且可以使开发人员在他们的职业生涯中走得更远。它仍然是定义数据架构的最佳语言,而且它在数据工程师和科学家中仍然比Python或R等语言更受欢迎。

作为一种声明性语言,它是简洁的,并将重任留给了数据库系统。这与命令式语言的工作方式有些不同,在命令式语言中,我们给系统提供我们想要做的事情的确切步骤(StackOverflow的这个主题解释了声明式语言与命令式语言

通过SQL学习与数据打交道的基本原理和逻辑,为开发人员转向较新的面向数据的工具(如Spark)和功能语言(如Scala)打下坚实的基础。

数据库是构建现代应用程序的一个关键因素,而学习的最好方式之一就是实践。让我们亲身体验一下SQL!在这些SQL教程中,我们将手动运行SQL查询,但这些查询的类型是相同的,它们是用于构建应用程序编程接口(API)背后的构建块。

什么是关系型数据库?

关系型数据库是一个表现出两个关键SQL概念的数据库:表和数据关系(因此被称为 "关系型数据库")。每个表由行和列组成,表的配置被称为其 "模式"。

例如,这里是我们在本指南中要使用的两个表的模式的图示。每个表的下面是该表的列的列表,以及它们相应的数据类型。这两个表是通过Animals表的id列联系起来的。

思考表格的一个有用的方法是把它们看作是一个电子表格,其中的列代表我们想要跟踪的信息,行代表我们想要存储的每个数据条目。我们可以创建多个表,每个表内有不同类型的信息,然后使用SQL查询来连接和处理所有表内的数据。

什么是SQL中的数据语言?

SQL由三种不同类型的基础组组成:

  • 数据定义语言(DDL)
  • 数据操作语言(DML)
  • 数据/事务控制语言(DCL/TCL)

DDL允许我们使用CREATE和ALTER等命令来定义我们数据库的结构。我们可以把它想象成为我们的数据设置和标记架子,并在移动和处理数据之前指定我们要如何组织它。

DML提供了如何操作数据的方法,通过SELECT、INSERT、UPDATE和DELETE等命令实际进行添加、更改和删除。

DCL/TCL使我们能够指定谁用权利和权限来控制我们的数据库。

最后,还有一些实用功能,为我们提供信息,如显示表或用户权限的列表。

让我们假设我们正在创办一个新的动物收容所,名为 "Animals 4 Homes",随着它的成长和扩大,通过帮助设置它的数据库来经历它的旅程。

要跟上本指南,你需要一个SQL环境。如果你想要一个简单的方法来连接和使用SQL数据库,而不需要任何安装或设置,你可以使用这个SQL Playground。请注意,本指南中的步骤不是专门针对CockroachDB的,本指南中的知识可以用于PostgreSQL、MySQL和其他关系型数据库。

设置狗狗收容所数据库,创建数据库

好了!动物4之家正准备开业,帮助狗找到爱的家。

为了开始工作,我们需要建立一个SQL数据库来存储和管理每只狗,因为它们进来并被收养。

首先,我们需要为我们的数据创建一个数据库。我们将使用以下SQL语句将其命名为pet_adoption。

CREATE DATABASE pet_adoption;

创建一个数据库并不会自动将其设置为活动数据库,所以现在让我们用USE 命令选择pet_adoption数据库。

USE pet_adoption;

接下来,我们需要设置将存储我们的数据的表。

这是使用SQL的一个关键步骤,因为这一步是我们定义我们将存储什么信息以及如何组织这些信息的地方。即使我们以后可以改变或 "改变 "表,但从一开始就把它配置好,可以使我们的数据库顺利运行,而不需要我们以后再去洗牌。

对于这个项目,让我们只创建两个表:动物和收养。

表1:动物的表,创建表和UUID

第一个表,animals,将保持一个通过我们收容所的狗的列表。

我们将这个表称为 "动物",而不是 "狗",因为一个动物收容所很可能会扩展到更多类型的动物,而不仅仅是狗(psst,我们将在接下来的步骤中这样做)。从一开始就这样命名,将使我们在未来不需要重新命名该表。

我们可能想在这个表中得到的信息是狗的唯一ID、它的名字、品种、颜色、性别和收养状态。让我们为它们设置相应的列。

用以下命令创建动物表。

CREATE TABLE animals (id UUID NOT NULL, name STRING, breed STRING, color STRING, gender STRING, status INTEGER);

我们将为注册到数据库中的每只动物分配一个通用唯一标识符(UUID)作为ID。如果你不熟悉UUID,它是一个由32个十六进制数字组成的唯一生成的组合。例如,一个UUID可能看起来像这样。123e4567-e89b-12d3-a456-426614174000.它通常是在代码中生成的,但你也可以使用在线生成器来手动获得一个。

我们表中另一个有趣的列是状态,我们将为每只动物存储一个0或1的整数,以代表它的收养状态。这个数字值是任意的,但是我们说0=开放收养,1=收养。在这一列中使用一个整数而不是一个文本字符串将有助于保持整个数据库的大小。同时,这将使我们的SQL查询更快,因为数字操作比文本操作更容易、更快速地进行计算。

第二个表将被命名为收养表。它将被用来跟踪所有的收养交易。

每条领养记录都将包括一个animal_id UUID,我们将添加这个UUID来匹配我们在第一个表中为动物设置的id字段中的UUID值。在本指南中,我们将手动复制UUID值到两个表中,但通常是用代码生成。这个表还将包含收养动物的人的姓名和联系信息以及收养日期。

使用以下命令创建这个收养表。

CREATE TABLE adoptions (animal_id UUID NOT NULL, name STRING, contact STRING, date TIMESTAMP);

我们在这个表中添加了一个具有TIMESTAMP数据类型的日期列,这将使我们能够按照最近的收养情况进行排序,或者搜索特定时间范围内的收养情况。

虽然我们的数据库的上述设计只是许多其他可能的变化中的一种选择,但请记住,我们可以用不同的方式组织相同的信息。我们可以在必要和适当的情况下添加尽可能多的表、列和细节。然而,用较少的表和列来保持简单的东西,通常对数据库的复杂性和速度都有好处。

举个例子,我们可以为每个品种的狗创建一个表,但这可能很快就会增加到一百多个表,使我们很难搜索到合适的狗。同时,如果我们的细节太少,完全不跟踪狗的品种,我们就不能用SQL查询来指定潜在领养者正在寻找的狗的类型。这将限制数据库的实用性。

验证数据库设置,显示表和列

在我们继续前进之前,让我们确保我们的表在数据库中被正确创建。

运行这个命令来获得当前数据库中的表的列表,检查我们是否有动物表和收养表。

SHOW TABLES;

如果你看到这两个表,那么你可以运行这两条语句,以确保每个表的列是正确的。

SHOW COLUMNS FROM animals;

SHOW COLUMNS FROM adoptions;

现在,我们的数据库模式看起来不错,我们准备开始在我们的庇护所接受狗。

将狗添加到数据库。INSERT

是时候欢迎和登记第一批来到 "动物之家 "的狗了!

它们急于办理入住手续,在游客面前显得很可爱,所以让我们迅速将它们加入系统。我们可以在动物表上使用一个INSERT语句来完成这个任务,该语句看起来像下面这样。

INSERT INTO animals (id, name, breed, color, gender, status) VALUES ('89354034-20d9-4c3d-8195-3294bfd9dbc5', 'Bellyflop', 'Beagle', 'Brown', 'Male', 0);

练习1:将所有的狗添加到数据库中

这里是所有排队等候的狗的名单。试着根据上面的SQL语句把它们放入系统中。

sql table with sample data

答案是。

你明白了吗?SQL的INSERT语句应该是这样的。

INSERT INTO animals (id, name, breed, color, gender, status) VALUES ('89354034-20d9-4c3d-8195-3294bfd9dbc5', 'Bellyflop', 'Beagle', 'Brown', 'Male', 0);

INSERT INTO animals (id, name, breed, color, gender, status) VALUES ('ae91cf1c-f972-42f3-8160-6c04d935699c', 'Snowy', 'Husky', 'White', 'Female', 0);

INSERT INTO animals (id, name, breed, color, gender, status) VALUES ('37df3388-b0f4-4f0d-b6ef-0d840923a4d8', 'Princess', 'Pomeranian', 'Black', 'Female', 0);

INSERT INTO animals (id, name, breed, color, gender, status) VALUES ('94545432-d27a-4ac8-ab7c-38270d7535f3', 'Cricket', 'Chihuahua', 'Brown', 'Male', 0);

INSERT INTO animals (id, name, breed, color, gender, status) VALUES ('a1e7a7fc-b429-41ec-9924-8bb39dd397c8', 'Princess', 'Poodle', 'Purple', 'Female', 0);

INSERT INTO animals (id, name, breed, color, gender, status) VALUES ('5138ed53-2ab2-400b-973c-91186f8c673d', 'Spot', 'Dalmation', 'Black and White', 'Male', 0);

检索狗的名单: SELECT * FROM

在将全部狗的名单加入我们的数据库后,我们可以尝试运行一些SELECT查询来查看它们。下面是一些可能运行的SQL语句的小例子。

获取所有狗的所有属性的完整列表(默认限制为100行)。

SELECT * FROM animals;

获取所有狗的品种。

SELECT breed FROM animals;

通过包含一个WHERE子句,只获取母狗的名字。

SELECT name FROM animals WHERE gender = 'Female';

获得待收养的狗的ID。

SELECT id FROM animals WHERE status = 0;

作为练习,测试并创造性地使用SQL语句,以获得使用带有WHERE子句的SELECT语句的感觉。

事实证明,我们的狗的一些原始信息需要纠正(因为紫色的狗不存在),所以让我们看看我们如何在数据库中更新和删除信息。

更新一行的最好方法是使用每只狗的唯一ID,这样我们就能确定被改变的具体单行。因此,要把公主犬的颜色从紫色改成棕色,我们可以使用以下语句。

UPDATE animals SET color = 'Brown' WHERE id = 'a1e7a7fc-b429-41ec-9924-8bb39dd397c8';

(记住,你可以用SELECT语句来获得狗的ID)。

虽然使用狗的名字来更新数据库可能看起来更容易、更自然,但我们需要确保只有这一只贵宾犬的颜色条目被改变。因为我们的收容所里有两只叫 "公主 "的狗--一只博美犬和一只狮子狗--而且我们将来可能会有其他也叫 "公主 "的狗,像下面这样的语句会引起问题,因为它将把数据库里所有狗的颜色都改为棕色。

UPDATE animals SET color = 'Brown' WHERE name = 'Princess';

然而,另一个可行的方案是在数据库中专门修复紫色的颜色条目,因为没有狗应该是紫色的。

UPDATE animals SET color = 'Brown' WHERE color = 'Purple';

当我们准备进入下一节时,其中一只狗的主人来找他的小猎犬,在这里找到了它。因此,让我们在有人试图收养小猎犬之前,用DELETE语句将小猎犬Bellyflop从我们的数据库中删除。

DELETE FROM animals WHERE id = '89354034-20d9-4c3d-8195-3294bfd9dbc5';

好消息!我们为吉娃娃蟋蟀找到了一个家。让我们在数据库中记录 "动物之家 "有史以来的第一次收养。

要做到这一点,我们需要运行两条不同的语句:一条是在动物表中把Cricket的状态更新为1,即 "被收养",另一条是把事件插入到收养表中,使之成为最终结果。

第一条语句看起来像这样,使用Cricket的id字段。

UPDATE animals SET status = 1 WHERE id = '94545432-d27a-4ac8-ab7c-38270d7535f3';

领养的SQL语句应该是这样的。

INSERT INTO adoptions (animal_id, name, contact, date) VALUES ('94545432-d27a-4ac8-ab7c-38270d7535f3', 'Pinocchio', 'realboy@cockroachlabs.com', NOW());

在我们的INSERT 语句中,你可能注意到,我们用NOW() 来表示日期值。这个特殊的SQL函数会自动将该值设置为服务器内的当前时间,这样我们就不需要查找时间并将其写下来。

练习2:记录收养情况

我们还有两只狗要去一个新家,请尝试写出四条SQL语句,以正确记录下面列表中的收养情况。

sql table with sample data

答案

你明白了吗?这些SQL语句应该是这样的。

UPDATE animals SET status = 1 WHERE id = 'a1e7a7fc-b429-41ec-9924-8bb39dd397c8';

INSERT INTO adoptions (animal_id, name, contact, date) VALUES ('a1e7a7fc-b429-41ec-9924-8bb39dd397c8', 'Patalie', 'poodlequeen@cockroachlabs.com', NOW());

UPDATE animals SET status = 1 WHERE id = '5138ed53-2ab2-400b-973c-91186f8c673d';

INSERT INTO adoptions (animal_id, name, contact, date) VALUES ('5138ed53-2ab2-400b-973c-91186f8c673d', 'Ella', 'ellacrew@cockroachlabs.com', NOW());

验证更改。ORDER BY

现在,让我们检查一下,以确保我们的查询在数据库内正确运行。

当我们运行以下语句时,我们应该看到三个新的收养条目。

SELECT * FROM adoptions;

我们也可以使用ORDER BY修改器按最近的收养情况排序(日期降序)来查看它们。

SELECT * FROM adoptions ORDER BY date DESC;

最后,我们应该确保正确的三只狗(吉娃娃Cricket、狮子狗Princess和大麦町Spot)的状态被设置为1("被收养 "状态)。

验证你在运行时是否得到三个结果。

SELECT * FROM animals WHERE status = 1;

我们的新动物收容所似乎运行良好,这要归功于SQL领养系统!该组织现在已经决定接受猫。

该组织现在决定也接受猫,并为它们寻找新家。让我们更新我们的数据库系统,以便在未来处理猫和可能的其他物种的动物。

添加一个表列。ALTER TABLE

首先,我们需要在动物表中添加一个新的物种列,以跟踪一个动物条目是狗还是猫。这可以用ALTER TABLE命令来完成。

ALTER TABLE animals ADD COLUMN species STRING;

我们可以使用SHOW COLUMNS命令来验证该表是否被正确更新。

SHOW COLUMNS FROM animals;

在我们开始添加任何猫之前,我们有机会轻松地将数据库中所有当前动物的物种设置为 "狗",因为我们已经知道系统中只有狗。

要做到这一点,我们首先需要关闭安全更新,这样我们就可以使用不带WHERE子句的UPDATE语句,用一条语句更新表中的所有行。

SET sql_safe_updates = FALSE;

然后运行下面的查询,为数据库中当前所有的动物指定 "狗"。

UPDATE animals SET species = 'Dog';

现在,如果我们检索动物表,我们应该看到每一行都被配置为狗。

SELECT * FROM animals;

我们可以开始在系统中添加我们的新猫。添加这些猫的方法与我们先前用来添加狗的INSERT INTO语句类似。但我们必须记住添加物种列,并将其值设置为 "猫"。

下面是我们刚收进来的猫的名单。试着将它们添加到数据库中。

sql table with 5 columns of data

回答

你明白了吗?SQL语句应该是这样的。

INSERT INTO animals (id, name, species, breed, color, gender, status) VALUES ('11d6fa07-449f-4053-a7cb-ae4ec8570f3f', 'Meowmix', 'Cat', 'Munchkin', 'Yellow', 'Female', 0);

INSERT INTO animals (id, name, species, breed, color, gender, status) VALUES ('4e55860a-ec39-494b-845a-2e0a6496bf9b', 'Ash', 'Cat', 'Persian', 'Gray', 'Female', 0);

INSERT INTO animals (id, name, species, breed, color, gender, status) VALUES ('e80b92e5-98ed-458d-885d-b9e05d0d123e', 'Tiger', 'Cat', 'Bengal', 'Brown', 'Male', 0);

为了确定,让我们检查一下这些猫是否被正确地添加到数据库中。

SELECT * FROM animals;

高级:扩展到多个地点

四海一家 "取得了巨大的成功,我们现在要把业务扩展到其他地方!我们要继续使用同一个数据库系统来记录猫咪的情况。

我们希望继续使用同一个数据库系统来跟踪所有的动物并处理所有的收养,所以我们需要对数据库进行一些更新。

一个用于收容所的表:更改表...添加列

从现在开始,所有的收容所都将在我们的数据库中被追踪。因此,创建第三个表,命名为shelters,包含ID、名称和位置等列。与动物表不同的是,我们最终可能会在数据库中拥有数千甚至数百万只动物,为了简单起见,我们可以为避难所的ID列使用一个整数而不是UUID。

CREATE TABLE shelters (id INTEGER, name STRING, location STRING);

让我们添加我们当前和第一个收容所,即位于红城的Animals 4 Homes。

INSERT INTO shelters (id, name, location) VALUES (1, 'Animals 4 Homes', 'Red City');

而接下来,我们需要用一个新的庇护所列来调整动物表,趁此机会,将所有现有的动物数据行更新为位于这个庇护所的id = 1:

ALTER TABLE animals ADD COLUMN shelter INTEGER;

UPDATE animals SET shelter = 1;

然后,我们可以为其他两个加入我们的宠物收养工作的庇护所创建条目。Adopt A Buddy 和 Fluffy Animals:

INSERT INTO shelters (id, name, location) VALUES (2, 'Adopt A Buddy', 'Green Town');

INSERT INTO shelters (id, name, location) VALUES (3, 'Fluffy Animals', 'Blue Hills');

为新家庭提供的新动物

我们的新动物收容所正在接收一些新的动物,它们正在寻找爱的家园。

练习4:增加多种类型的动物

这里有最新的动物名单,你可以尝试将其添加到数据库中:

sql table with 7 columns

答案

你明白了吗?这些是添加新动物的SQL语句:

INSERT INTO animals (id, name, shelter, species, breed, color, gender, status) VALUES ('ac1a773d-6912-45cc-b296-1b58d13dbd32', 'Snoops', 2, 'Dog', 'Beagle', 'Brown', 'Male', 0);

INSERT INTO animals (id, name, shelter, species, breed, color, gender, status) VALUES ('56e9be70-ed24-4949-bb54-70329c2caf82', 'Salt', 2, 'Cat', 'Turkish Angora', 'White', 'Female', 0);

INSERT INTO animals (id, name, shelter, species, breed, color, gender, status) VALUES ('b91df9f1-8e3d-4cce-a4ba-9d1a3ad6a12b', 'Fuzz', 3, 'Dog', 'Papillon', 'Gray', 'Male', 0);

更多高级SQL:索引和连接

我们还要对我们的数据库做两件事。我们将创建一个索引,以帮助提高我们的SQL查询的性能,并且我们将在多个表中运行一个JOIN语句,将所有的信息拉到一个单一的结果中。要想更深入地了解JOINS,请看这篇博文JOIN排序。介绍

什么是索引?

索引基本上是向数据库提示某个特定的列是重要的,应该被用来帮助对数据进行分类和过滤。这就告诉数据库任务在每次添加或更新一些数据时要添加一些索引信息。这样一来,整个数据库可以更有效地运行,通过数据的查询可以更快完成。在我们的案例中,我们可以为动物表中的避难所列创建一个索引,因为这将是划分数据的关键方式之一。关于索引的更多实验,请跳转到全文索引和搜索

要做到这一点,我们可以运行这个命令:

CREATE INDEX animal_shelter ON animals (shelter);

使用JOIN的复杂查询

最后,使用JOIN ,我们可以在多个表中进行查询,不仅可以检索每个动物的信息,还可以在一个SQL语句中检索它们的住所,而不是自己做这些工作。

它看起来有点像这样:

SELECT * FROM animals JOIN shelters ON animals.shelter = shelters.id;

上面的ON 子句指定了动物表中的庇护所列将与庇护所表中的一个ID相匹配。这将是一个链接,使组合表的查询结果成为可能。

练习5:获取所有动物的列表

好的,如果我们想从第一个庇护所得到一个被收养的动物的列表呢?看看你能不能想出这个语句应该是什么。(提示:WHERE ,你在改变你的语句吗?)

答案是

你明白了吗?这里是SQL语句。

SELECT * FROM adoptions JOIN animals ON adoptions.animal_id = animals.id WHERE animals.shelter = 1;

在免费的SQL数据库上继续练习

在现代数据驱动的世界中,能够有效地使用数据库可以说是一种技术上的超能力。而现在你已经学会了如何使用关系型数据库并编写SQL语句来添加、更新、删除和搜索,你现在有能力处理大量的数据。

如果你想继续学习,这里有一些资源可以提高你的技能。

如果你正在寻找一个很好的地方来练习和建立你在这里学到的SQL技能,你可以非常容易地开始使用一个永远免费的数据库,无需安装或设置服务器。注册后就可以开始了。

查询愉快!