如何使用SQL系列 之 了解SQL中的约束规则

简介

在设计数据库时,有时可能需要对某些列中允许的数据设置限制。例如,如果你要创建一张表来保存摩天大楼的信息,你可能希望在保存每座大楼高度的列中禁止使用负值。

关系型数据库管理系统(RDBMS)允许你使用约束来控制哪些数据被添加到表中。约束是适用于一个或多个列或整个表的特殊规则,它限制了可以对表的数据进行哪些更改,无论是通过INSERTUPDATE还是DELETE语句。

本文将详细介绍什么是约束以及如何在RDBMS中使用约束。它还将遍历SQL标准中定义的五个约束,并解释它们各自的功能。

什么是约束?

在SQL中,约束是应用于列或表的限制可以输入哪些数据的任何规则。任何时候,当你试图执行一个改变表中数据的操作时——例如INSERTUPDATEDELETE语句——RDBMS都会测试该数据是否违反了任何现有的约束,如果是,则返回一个错误。

数据库管理员通常依赖约束来确保数据库遵循一组已定义的业务规则。在数据库环境中,业务规则是任何企业或其他组织遵循的政策和程序,它的数据也必须遵守。例如,假设您正在构建一个数据库,该数据库将对客户的商店库存进行分类。如果客户指定记录每个产品应该有一个独特的识别号码,你可以创建一个列与一个“独特”约束,将确保没有两个条目列是相同的。

约束对于维护数据完整性也很有帮助。数据完整性是一个宽泛的术语,通常用于描述基于特定用例的数据库中数据的整体准确性、一致性和合理性。数据库中的表通常是紧密相关的,一张表中的列依赖于另一张表中的值。由于数据输入经常容易出现人为错误,因此约束在这种情况下很有用,因为它们可以帮助确保没有错误输入的数据会影响这种关系,从而损害数据库的数据完整性。

假设你正在设计一个包含两个表的数据库。一个用于列出学校的当前学生,另一个用于列出学校的篮球队成员。你可以将FOREIGN KEY约束应用于篮球队表中的一列,该列指向学校表中的一列。这将通过要求team表中的任何条目引用student表中已存在的条目来建立两个表之间的关系。

用户定义的约束时,首先创建一个表,或者他们可以添加他们后来的ALTER TABLE语句,只要它不与任何数据冲突。当你创建约束时,数据库系统会自动为它生成一个名称,但在大多数SQL实现中,你可以为任何约束添加一个自定义名称。这些名称用于在ALTER TABLE语句中更改或删除约束。

SQL标准正式定义了5个约束:

  • PRIMARY KEY
  • FOREIGN KEY
  • UNIQUE
  • CHECK
  • NOT NULL

注意:许多rdbms包含DEFAULT关键字,用于在插入行时为非NULL列定义一个默认值。其中一些数据库管理系统的文档将DEFAULT称为约束,因为它们的SQL实现使用了DEFAULT语法,类似于UNIQUECHECK等约束。然而,从技术上讲,DEFAULT并不是一个约束,因为它并不限制可以输入哪些数据到一列中。

现在你已经对约束的使用方式有了大致的了解,让我们仔细看看这五个约束。

PRIMARY KEY

PRIMARY KEY约束要求给定列中的每一项都是唯一的且不为NULL,并允许你使用该列来标识表中的每一行

在关系模型中,是表中的一列或一组列,其中每个值都保证是唯一的,并且不包含任何NULL值。主键是一种特殊的键,它的值用于标识表中的各行,组成主键的一列或多列可以用于标识数据库的其余部分中的表。

这是关系数据库的一个重要方面。有了主键,用户不需要知道他们的数据在机器上的物理存储位置,DBMS可以跟踪每条记录并临时返回它们。反过来,这意味着记录没有定义逻辑顺序,用户可以以任何顺序或通过任何他们想要的过滤器返回数据。

您可以创建一个主键在SQL的主键约束,这本质上是一个“独特的”和“不空”约束。在定义一个主键之后,DBMS将自动创建一个与之关联的索引。索引是一种帮助从表中更快地检索数据的数据库结构。类似于教科书索引、查询只需要审查从索引列条目找到相关联的值。这使得主键可以作为表中每一行的标识符。

一张表只能有一个主键,但和普通键一样,一个主键可以包含多个列。也就是说,主键的一个定义特性是,它们只使用唯一标识表中每一行所需的最小属性集。为了说明这个想法,假设有一个表,使用以下3列存储某所学校的学生信息:

  • studententid:用于保存每个学生的唯一识别号码
  • firstName:用于保存每个学生的名字
  • lastName:用于保存每个学生的姓氏

学校里的一些学生可能共用一个名字,这使得firstName这一列成为一个重复的主键。lastName列也是如此。firstNamelastName两列组成主键是可以的,但是仍然有两个学生有可能名字和姓氏都是相同的。

studententidfirstNamelastName列组成的主键可以正常工作,但由于每个学生的识别号都是唯一的,在主键中包含任何name列都是多余的。因此,在这种情况下,可以标识每一行的最小属性集是studententid列本身,这将是一个很好的选择主键。

如果一个键是由可观察的应用数据(即代表真实世界实体、事件或属性的数据)组成的,它被称为自然键。如果这个键是在内部生成的,并且不代表数据库之外的任何东西,它被称为代理键合成键。有些数据库系统不建议使用自然键,因为即使是看似恒定的数据点也可能以不可预测的方式发生变化。

FOREIGN KEY

FOREIGN KEY约束要求给定列中的每个条目必须已经存在于另一张表的特定列中。

如果你有两个表想要相互关联,一种方法是使用FOREIGN KEY约束定义一个外键。外键是一个表(子表)中的一列,它的值来自另一个表(父表)中的一个键。这是一种表达两张表之间关系的方式:FOREIGN KEY约束要求它所应用的列中的值必须已经存在于它引用的列中。

下图突出了两个表之间的关系:一个用于记录关于公司员工的信息,另一个用于跟踪公司的销售。在这个例子中,EMPLOYEES表的主键被SALES表的外键引用:

Diagram example of how the EMPLOYEE table's primary key acts as the SALES table's foreign key

如果试图向子表添加一条记录,而输入到外键列的值在父表的主键中不存在,那么插入语句将无效。这有助于维护关系级别的完整性,因为两个表中的行总是正确关联的。

表的外键通常是父表的主键,但情况并不总是如此。在大多数rdbms中,父表中任何具有UNIQUEPRIMARY KEY约束的列都可以被子表的外键引用。

UNIQUE

UNIQUE约束禁止向给定列中添加任何重复的值。

顾名思义,UNIQUE约束要求给定列中的每个条目都是唯一的值。任何试图添加一个值,已经出现在列将导致一个错误。

UNIQUE约束在表之间强制一对一关系时非常有用。如前所述,用户可以通过外键在两张表之间建立关系,但表与表之间还存在多种关系:

  • 一对一:如果父表中的行只与子表中的一行相关,那么两个表是一对一关系
  • 一对多:在多对多关系中,父表中的一行可以关联到子表中的多行,但子表中的每一行只能关联到父表中的一行
  • 多对多:如果父表中的行可以关联到子表中的多行,反之亦然,这两者称为多对多关系

通过为应用了FOREIGN KEY约束的列添加UNIQUE约束,你可以确保父表中的每个条目在子表中只出现一次,从而在两个表之间建立一对一的关系。

注意,你可以在表级别和列级别定义UNIQUE约束。当定义在表级别时,UNIQUE约束可以应用于多个列。在这种情况下,约束中的每一列可以有重复的值,但每一行必须是受约束列中值的唯一组合。

CHECK

CHECK约束定义了列的一个要求,称为谓词,输入的每个值都必须满足。

CHECK约束谓词以表达式的形式编写,可以计算为TRUEFALSE或潜在的UNKNOWN。如果你试图在带有CHECK约束的列中输入一个值,并且该值导致谓词计算为TRUEUNKNOWN(对于NULL值会发生这种情况),操作将成功。但是,如果表达式解析为FALSE,它将失败。

CHECK谓词通常依赖于数学比较运算符(如<><=>=)来限制允许进入给定列的数据范围。例如,CHECK约束的一个常见用途是在负数没有意义的情况下防止某些列保存负数,如下面的例子所示。

这条CREATE TABLE语句创建了一个名为productInfo的表,其中包含每个产品的名称、标识号和价格的列。因为一个产品的价格是负数是没有意义的,这条语句对price列施加了一个CHECK约束,以确保它只包含正值:

CREATE TABLE productInfo (
productID int,
name varchar(30),
price decimal(4,2)
CHECK (price > 0)
);

并不是每个CHECK谓词都必须使用数学比较运算符。通常,你可以在CHECK语句中使用任何可以计算为TRUEFALSEUNKNOWN的SQL操作符,包括LIKEBETWEENIS NOT NULL等。有些SQL实现(但不是全部)甚至允许你在CHECK谓词中包含子查询。请注意,大多数实现都不允许你在一个谓词引用另一个表。

NOT NULL

NOT NULL约束禁止将任何NULL值添加到给定列中。

在大多数SQL实现中,如果你添加了一行数据,但没有为某一列指定值,数据库系统将默认将缺失的数据表示为NULL。在SQL中,NULL是一个特殊的关键字,用于表示未知、缺失或未指定的值。然而,NULL本身不是一个值,而是一个未知值的状态

为了说明这种区别,想象一个用于跟踪人才中介客户的表,表中有每个客户的名字和姓氏的列。如果客户端使用单名,如“Cher”、“Usher”或“Beyoncé”,则数据库管理员可能只在first name列中输入单名,导致DBMS在last name列中输入NULL 。数据库并不认为客户端的姓氏字面上是“Null”。它只是意味着该行的last name列的值是未知的,或者该字段没有应用于特定的记录。

顾名思义,NOT NULL约束阻止给定列中的任何值为NULL。这意味着对于任何列的NOT NULL约束,你必须为它指定一个值时插入一个新行。否则,INSERT操作将会失败。

总结

对于任何希望设计具有高数据完整性和安全性的数据库的人来说,约束都是必不可少的工具。通过限制输入到列中的数据,可以确保正确维护表之间的关系,并确保数据库遵循定义其用途的业务规则。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/115964.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring Boot源码解读与原理剖析:深入探索Java开发的奥秘!

评论区留言赠书15本 关注点赞评论&#xff0c;评论区回复“Spring Boot源码解读与原理剖析&#xff1a;深入探索Java开发的奥秘&#xff01;” 每篇最多评论3条&#xff01;&#xff01;采用抽奖助手自动拉取评论区有效评论送书两本&#xff0c; 开奖时间&#xff1a;9月11号 承…

MySQL数据库——多表查询(3)-自连接、联合查询、子查询

目录 自连接 查询语法 自连接演示 联合查询 查询语法 子查询 介绍 标量子查询 列子查询 行子查询 表子查询 自连接 通过前面的学习&#xff0c;我们对于连接已经有了一定的理解。而自连接&#xff0c;通俗地去理解就是自己连接自己&#xff0c;即一张表查询多次。…

二进制数的位运算(非和异或)invert()和bitwise_xor()

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 二进制数的位运算(非和异或) invert()和bitwise_xor() [太阳]选择题 下列代码最后一次输出的结果是&#xff1f; import numpy as np a, b 3, 10 print("【执行】np.binary_repr(a, 4)…

vue3+ts组件通信

1、父组件向组件传参 父组件代码 子组件代码 2、子组件向父组件传参 组件间代码 父组件代码 3、如果eslint报错&#xff0c;需在.eslintrc.js中添加一行代码 4、通过父组件通过 ref 获取子组件的属性或者方法 父组件代码 子组件代码 5、孙子组件provide和inject 父组件…

再也不信能用99年的IDEA激活方式了

今天给大家安利一款IDEA伴侣神器 Toolbox&#xff0c;开发必备的IDEA大家都在用&#xff0c;但很多小伙伴没用过Toolbox。 介绍 为什么使用 JetBrains Toolbox&#xff1f; 包含超过 15 款可用于专业开发的工具。 每个工具专门针对其技术开发。 所有工具都会定期更新&#…

python 笔记(3)——request、爬虫、socket、多线程

目录 1、使用requests发送http请求 1-1&#xff09;发送get请求 1-2&#xff09;发送 post 请求 1-3&#xff09;发送 get 请求下载网络图片 1-4&#xff09;使用 post 上传文件 1-5&#xff09;自动维护 session 的方式 2、使用 os.popen 执行cmd命令 3、基于 beautif…

卷积神经网络实现运动鞋识别 - P5

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f366; 参考文章&#xff1a;Pytorch实战 | 第P5周&#xff1a;运动鞋识别&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制&#x1f680; 文章来源&#xff1a;K同学的学习圈子 目录…

沐风老师3DMAX厨房橱柜生成器KitchenCabinetGenerator教程

3DMAX厨房橱柜生成器插件使用方法 3DMAX橱柜生成器KitchenCabinetGenerator是一个在3dMax中自动创建三维橱柜模型的高效脚本。它有多种风格的台面、门和橱柜&#xff0c;可以灵活地应用于Archviz项目&#xff0c;同时为3D艺术家节省大量时间。 【适用版本】 1.3dMax2018 – 20…

YOLO数据集划分(训练集、验证集、测试集)

1.将训练集、验证集、测试集按照7:2:1随机划分 1.项目准备 1.在项目下新建一个py文件&#xff0c;名字就叫做splitDataset1.py 2.将自己需要划分的原数据集就放在项目文件夹下面 以我的为例&#xff0c;我的原数据集名字叫做hatDataXml 里面的JPEGImages装的是图片 Annota…

设计模式-适配器

文章目录 一、简介二、适配器模式基础1. 适配器模式定义与分类2. 适配器模式的作用与优势3.UML图 三、适配器模式实现方式1. 类适配器模式2. 对象适配器模式3.类适配器模式和对象适配器模式对比 四、适配器模式应用场景1. 继承与接口的适配2. 跨平台适配 五、适配器模式与其他设…

C++之std::distance应用实例(一百八十八)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

论文解读 | 三维点云深度学习的综述

原创 | 文 BFT机器人 KITTI 是作为基准测试是自动驾驶中最具影响力的数据集之一&#xff0c;在学术界和工业界都被广泛使用。现有的三维对象检测器存在着两个限制。第一是现有方法的远程检测能力相对较差。其次&#xff0c;如何充分利用图像中的纹理信息仍然是一个开放性的问题…

uniapp授权小程序隐私弹窗效果demo(整理)

9月15号前要配置这句话 "__usePrivacyCheck__": true,官方“小程序隐私协议开发指南”文档 <template> <view class"dealBox"><view class"txtBox padding10"><!-- 查看协议 -->在您使用施工现场五星计划小程序之前&am…

解决D盘的类型不是基本,而是动态的问题

一、正确的图片 1.1图片 1.2本人遇到的问题 二、将动态磁盘 转为基本盘 2.1 基本概念&#xff0c;动态无法转化为基本&#xff0c;不是双向的&#xff0c;借助软件 网址&#xff1a;转换动态磁盘到普通磁盘_检测到计算机本地磁盘为动态分区_卫水金波的博客-CSDN博客 2.2分区…

我开课了!《机器学习》公益课9月4日开课

我是黄海广&#xff0c;大学老师&#xff0c;我上的一门课叫《机器学习》&#xff0c;本科生学机器学习有点难&#xff0c;但也不是没有可能&#xff0c;我在摸索中&#xff0c;设计适合本科生的机器学习课程&#xff0c;写了教材&#xff0c;录了视频&#xff0c;做了课件。我…

安装使用electron

一、安装node和npm 运行cmd查看是否安装及版本号 npm -v node -v 二、安装electron npm直接安装会报错缺少什么文件&#xff0c;使用cnpm进行安装 直接安装cnmp后&#xff0c;再用cnmp命令安装可能会报错Error: Cannot find module ‘node:util’ 原因是npm版本与cnpm版本…

MySQL官网下载安装包

MySQL官网&#xff1a; MySQL MySQL 8.0官网下载地址&#xff1a; MySQL :: Download MySQL Community Server 2023-07-18 MySQL 8.1.0 发布&#xff0c;这是 MySQL 变更发版模型后的第一个创新版本 (Innovation Release) 。 如果在官网中找不到下载位置&#xff0c;点击第二个…

在Visual Studio 2017上配置并使用OpenGL

1 在Visual Studio 2017上配置并使用OpenGL 在GLUT - The OpenGL Utility Toolkit&#xff1a;GLUT - The OpenGL Utility Toolkit中点击“GLUT for Microsoft Windows 95 & NT users”&#xff0c;选择“If you want just the GLUT header file, the .LIB, and .DLL file…

elementplus实现左侧菜单栏收缩与展开

1.页面结构 Home.vue下包含aside.vue和menu.vue 2.TAside.vue el-menu左侧菜单栏显示 注意&#xff1a; 要使用收缩与展开&#xff0c;el-aside必须设置width"collapse"&#xff0c;否则收缩展开会出现收缩后&#xff0c;el-aside宽度不变窄需要使用动态改变展开收…

使用boost::geometry::union_ 合并边界(内、外)- 方案一

使用boost::geometry::union_ 合并边界&#xff08;内、外&#xff09;&#xff1a;方案一 结合 boost::geometry::read_wkt() 函数 #include <iostream> #include <vector>#include <boost/geometry.hpp> #include <boost/geometry/geometries/point_x…