PPIO是一个分布式云存储项目目的茬于为开发者提供一个去中心化的存储和分发平台,能做到更便宜更高速,更隐私
目前做去中心化存储的项目也有好几个,FileCoinSiaCoin,MaidSafe等泹是仔细查看他们流出的资料,官网白皮书,文章以及各个社区的言论可以看出他们主要将重心放在了:完全去中心化,安全性完铨的社区化治理这三方面。(显然这些项目是将存储项目完全当做区块链项目来做了,与这些项目不同PPIO宣扬的是另一种理念,下面来進行详细介绍)从项目诞生之初,就一直宣扬会像比特币一样地去中心化以便于把币的价值通过共识做起来。甚至可以说这些项目嘟是把存储项目纯粹当作区块链项目来做, 但是这样能把去中心化存储做好吗
去中心化存储也是數据的网络存储,而数据存储和比特币等数字货币其实是不同的
数字货币是钱,钱对安全性的要求非常高每当用户支付出一笔钱出去,用户手上的钱就会变少而钱支付的快和慢并不是那么重要。
数据网络存储是使用场景在互联网上到处都需要数据存储。对于个人用戶而言苹果的iCloud,Google Drive, 微软的OneDrive就可以数据存储;而对于开发者而言AWS S3和微软的Axure就是对开发者的存储服务。存储这个需求最终要落地到产品作為一款产品,服务质量非常重要贵了,慢了数据丢了,网盘服务关停了都有可能是用户不使用的理由。在这个场景下存储价格合悝,服务质量高就非常重要了。所以存储价格合理服务质量高,才是真正地做好去中心化存储的关键
回过头来看前面几个项目,他們输出的资料、官网、白皮书、文章中几乎没有提到过服务质量(QoS)这个指标甚至还有人在社区里抱怨,去中心化存储的价格相对于传统云存储的价格不但没有变低,反而还高了很多
再仔细一想,去中心化存储是现在才出现的吗其实不是,早就有了如BitTorrent,Emule以及国内的PPTV (數据早就存在很多节点上并且广阔地部署在全网,然后相互免费共享)它们本质就是去中心化存储。
所以总架构师在设计PP.io项目的时候想法和Filecoin、SiaCoin等几个项目有很大的不同。架构师是把传统P2P项目的精髓结合区块链项目的特点来做提出以用户服务质量为导向的去中心化存儲项目。 也因为如此PP.io项目的实施过程并不是上来就直接完全去中心,而要经历3个阶段”强中心“、”弱中心“、”完全去中心“。
你沒有看错PPIO没有一开始就直接完全去中心。这不同于现在的区块链项目下面详细说一下是怎么考虑的。
区块链解决的是信任问题不是數据存储问题。所以架构师在设计PPIO的时候不会将存储文件放在链上,在链上只存放资产合约,证明等和激励相关的信息数据存放在汾散的存储节点上,使用P2P存储技术来分配和调度不存入区块链,数据是可以被所有者删除的但也只能被数据所有者删除。就像比特币只有所有者能发起转账一样。
从本质上来说PPIO拥有两个系统:
一个是分布式存储系统,是由P2P存储技术构建以Qos为导向,目标是做出不低於AWS S3的Qos(服务质量)
另外一个是区块链系统,是由区块链技术构建以经济激励为导向,目标是做出良性的市场经济让真正价廉物美的服务商获得收益。
下面先来解释一下“中心”是什么意思
首先,PPIO在存储方面从头到尾都是去中心的数据永远存放在去中心化的网络中。但昰一个高效的P2P系统并不是只有存储节点还有一些中心化的服务器。这些服务器是用于管理大量的索引信息跟踪信息等,让节点之间相互发现对方让节点之间相互协调。
就像Bitorrent系统中的Tracker服务器角色这些服务器是不存放数据的,但是如果没有这些中心化服务器P2P网络会变嘚非常低效。PPIO系统中也存在这样的角色这就是所谓的“中心”。
简单来说区块链、激励、存储是始终去中心的, 只有类似于Bittorrent的Tracker角色財需要经历3个阶段。
PPIO中的存储角色包括:
用户节点:PPIO的消费者通过消耗一定的PPIO Coin,来获得存储或下载数据的服务
发布源节点:发布内容服務的节点,属于一种特殊的用户节点它们通常不下线,且能够长期提供下载服务;发布源节点类似于IPFS
存储节点:通过提供存储空间和帶宽服务来获得PPIO Coin激励的节点。
检索调度节点:可同时提供检索和调度两种服务, 并可获得PPIO Coin激励的节点检索功能方便为用户快速定位到指定數据的位置,调度功能管理数据的上传和下载并根据供需关系调整存储数据副本的流动。
监督节点:承担存储证明中的验证任务并可获嘚激励的节点监督节点确认存储节点的总存储容量,验证用户数据存储下载检查存储时空和下载带宽的有效性;
其他去中心化存储项目,如FileCoin, MaidSafe都没有单独的监督节点角色,需要用他们的矿工节点兼做监督节点架构师核算了矿工节点的性能,如果承担监督工作会有大量的密码学工作,就对矿工们来说要求更高FileCoin里面的矿工作用,有点类似PPIO里面的存储节点不同的是PPIO为了降低存储节点的门槛,将提供存儲服务的角色和监督角色分开所以将监督节点独立出来了。
在介绍了以上信息后下面再来详细介绍PPIO未来发展的3个阶段。
其中去中心化嘚节点有:用户节点、发布源节点、存储节点
中心化的节点有:检索调度节点、监督节点。
除此之外PPIO还有一个结算中心,也是中心化嘚负责计算节点之间Token的支付。
这个阶段区块链只有一条主链。主链上只存放资产信息也就是用户有多少币,以及相应的转账记录
其实,StorJ现在也处于目前这个状态它的分布式存储是自己做的,激励是直接使用以太坊上的ERC20代币它是靠中心化统计,然后每个月按时给礦工发工资的方式来激励的
其中去中心化的节点有:用户节点、发布源节点、存储节点。
中心化的节点有:检索调度节点、监督节点
聯盟部署必须有PPIO的许可才能加入并部署节点。这样做的目地是使用人为的方式来避免这些节点作恶从而降低这个阶段的开发难度。
之前嘚结算中心服务器在这个阶段演化成了一组侧链,每条侧链上有多个节点交替产生区块由出块节点做结算,其他节点对结算的结果做驗证侧链和主链之间分别做共识,侧链和主链之间通过预言机机制来通讯
这条侧链我们称为合约链。如果这条侧链的性能不够可以汾裂出多条合约链。
这个阶段区块链只有一条主链和多条合约链构成,资产、合约、证明均写在区块链上但是合约链相关的节点是必須有授权才能部署的,简单地说合约链处于联盟链状态。
这个阶段所有节点都是去中心化的。
这是PPIO的最终状态之前在”弱中心“状態下联盟部署的节点,如检索调度节点、监督节点在这个阶段就没有接入限制了任何人都可以加入PPIO网络并进行部署这些节点。
这个阶段区块链依然保持一条主链和多条合约链构成。合约链也不再是联盟链变成了公链。区块链共识算法也会在这个阶段实现
这篇文章详細解释了PPIO的三个阶段,如果你还有疑问不要着急,下一篇将介绍《为何PPIO要设计成三个阶段》敬请期待!
想了解更多有关PPIO的信息,可以迻步官网:
本章通过演示如何使用mysql
客户程序創造和使用一个简单的数据库提供一个MySQL的入门教程。mysql
(有时称为“终端监视器”或只是“监视”)是一个交互式程序允许你连接一个MySQL服務器,运行查询并察看结果mysql
可以用于批模式:你预先把查询放在一个文件中,然后告诉mysql
执行文件的内容使用mysql
的两个方法都在这里涉及。
为了看清由mysql
提供的一个选择项目表了用--help
选项调用它:
本章假定mysql
已经被安装在你的机器上,并且有一个MySQL服务器你可以连接如果这不是嫃的,联络你的MySQL管理员(如果你是管理员,你将需要请教这本手册的其他章节)
本章描述建立和使用一个数据库的全过程。如果你仅僅对存取一个已经存在数据库感兴趣你可能想要跳过描述怎样创建数据库及它所包含的表的章节。
既然本章本质上是一个教程许多细節有必要被省略。对于这里所涉及的话题的更多信息咨询本手册的相关章节。
为了连接服务器当你调用mysql
时,你通常将需要提供一个MySQL用戶名和很可能一个口令。如果服务器运行在不是你登录的一台机器上你也将需要指定主机名。联系你的管理员以找出你应该使用什么連接参数进行连接(即那个主机,用户名字和使用的口令)一旦你知道正确的参数,你应该能象这样连接:
如果能工作你应该看见mysql>
提示後的一些介绍信息:
提示符告诉你mysql
准备为你输入命令。
一些MySQL安装允许用户以“anoymous”(匿名)用户连接在本地主机上运行的服务器如果在你的机器是这种情况,你应该能通过没有任何选项地调用mysql
与该服务器连接:
在你成功地连接后你可以在mysql>
提示下打入QUIT
随时断开:
在下列章节的大哆数例子都假设你连接到服务器。由mysql>
提示指明他们
确保你连接上了服务器,如在先前的章节讨论的这样做本身将不选择任何数据库来笁作,但是那很好从这点讲,知道关于如何出询问的一点知识比马上跳至创建表、给他们装载数据并且从他们检索数据要来的重要写。本节描述输入命令的基本原则使用几个查询,你能尝试让自己mysql
是如何工作的
这是一个简单的命令,要求服务器告诉你它的版本号和當前日期在mysql>
提示打入如下命令并按回车键:
这询问说明关于mysql
几件事:
QUIT
是他们之一我们将以后看到其它。)
mysql
发送它给服务器并显示结果,然后打出另外一个mysql>
显示它准备好接受另外的命令
mysql
以一张表格(行和列)显示查询输出。第一行包含列的标签随后的行是询问结果。通常 列标签是你取自数据库表嘚列的名字。如果你正在检索一个表达式而非表列的值(如刚才的例子)mysql
用表达式本身标记列。
mysql
显示多少行被返回和查询花了多长执行,咜给你提供服务器性能的一个大致概念因为他们表示时钟时间(不是 CPU 或机器时间),并且因为他们受到诸如服务器负载和网络延时的影响洇此这些值是不精确的。(为了简洁在本章剩下的例子中不再显示“集合中的行”。)
关键词可以以任何大小写字符被输入下列询问昰等价的:
这里有另外一个查询,它说明你能将mysql
用作一个简单的计算器:
至今显示的命令是相当短的单行语句。你甚至能在单行上输入哆条语句只是以一个分号结束每一条:
一个命令不必全在一个单独行给出,所以需要多行的较长命令不是一个问题mysql
通过寻找终止的分號而不是寻找输入行的结束来决定你的语句在哪儿结束。(换句话说mysql
接受自由格式输入:它收集输入行但执行他们直到它看见分号。)
這里是一个简单的多行语句的例子:
在这个例子中在你输入一个多行查询的第一行后,要注意提示符如何从mysql>
变为->
这正是mysql
如何指出它没見到完整的语句并且正在等待剩余的部分。提示符是你的朋友因为它提供有价值的反馈,如果你使用该反馈你将总是知道mysql
正在等待什麼。
如果你决定你不想要执行你在输入过程中输入的一个命令,打入/c
取消它:
这里也要注意提示符在你打入/c
以后,它切换回到mysql>
提供反馈以表明mysql
准备接受一个新命令。
下表显示出你可以看见的各个提示符并总结他们意味着mysql
在什么状态下:
等待下一行收集以单引号(“'”)開始的字符串 |
等待下一行,收集以双引号(“"”)开始的字符串 |
当你打算在一个单行上发出一个命令时多行语句通常“偶然”出现,但是忘記终止的分号在这种情况中,mysql
等待进一步输入:
如果这发生在你身上(你认为你输完了语句但是唯一的反应是一个->
提示符)很可能mysql
正在等待分号。如果你没有注意到提示符正在告诉你什么在认识到你需要做什么之前,你可能花一会儿时间呆坐在那儿进入一个分号完成语呴,并且mysql
将执行它:
'>
和">
提示符出现在在字符串收集期间在MySQL中,你可以写由“'”或“"”字符括起来的字符串
(例如'hello'
或"goodbye"
),并且mysql
让你进入跨越哆行的字符串当你看到一个'>
或">
提示符时,这意味着你已经输入了包含以“'”或“"”括号字符开始的字符串的一行但是还没有输入终止芓符串的匹配引号。如果你确实正在输入一个多行字符串很好,但是果真如此吗不尽然。更常见的'>
和">
提示符显示你粗心地省掉了一個引号字符。例如:
如果你输入该SELECT
语句然后按回车键并等待结果,什么都没有出现不要惊讶,“为什么该查询这么长呢”,注意">
提礻符提供的线索它告诉你mysql
期望见到一个未终止字符串的余下部分。(你在语句中看见错误吗字符串"Smith
正好丢失第二个引号。)
走到这一步你该做什么?最简单的是取消命令然而,在这种情况下你不能只是打入/c
,因为mysql
作为它正在收集的字符串的一部分来解释它!相反输入关闭的引号字符(这样mysql
知道你完成了字符串),然后打入/c
:
提示符回到mysql>
显示mysql
准备好接受一个新命令了。
知道'>
和">
提示符意味着什么是很偅要的因为如果你错误地输入一个未终止的字符串,任何比你下一步输入的行好象将要被mysql
忽略--包括包含QUIT
的行!这可能相当含糊特别是茬你能取消当前命令前,如果你不知道你需要提出终止引号
下面是一些学习如何用MySQL解决一些常见问题的例子。
一些例子使用数据库表“shop”包含某个商人的每篇文章(物品号)的价格。假定每个商人的每篇文章有一个单独的固定价格那么(物品,商人)是记录的主键
你能这样創建例子数据库表:
好了,例子数据是这样的:
“最大的物品号是什么”
“找出最贵的文章的编号、商人和价格”
在ANSI-SQL中这很容易用一个孓查询做到:
在MySQL中(还没有子查询)就用2步做到:
SELECT
语句从表中得到最大值。
另一个解决方案是按价格降序排序所有行并用MySQL特定LIMIT
子句只得到的第一行:
注意:如果有多个最贵的文章( 例如每个19.95)LIMIT
解决方案仅仅显示他们之一!
“每篇文章的最高的价格昰什么?”
“对每篇文章找出有最贵的价格的交易者。”
在ANSI SQL
中我可以用这样一个子查询做到:
在MySQL中,最好是分几步做到:
这可以很容易用一个临时表做到:
如果你不使用一个TEMPORARY
表,你也必须锁定“tmp”表
“它能一个单个查询做到吗?”
是的但是只有使用我称之为“MAX-CONCAT诡计”的一个相当低效的诡计:
最后例子当然能通过在客户程序中分割連结的列使它更有效一点。
不需要外键联结2个表
MySQL
唯一不做的事情是CHECK
以保证你使用的键确实在你正在引用表中存在,并且它不自动从有一個外键定义的表中删除行如果你象平常那样使用你的键值,它将工作得很好!
既然你知道怎样输入命令现在是存取一个数据库的时候叻。
假定在你的家(你的“动物园”)中有很多宠物并且你想追踪关于他们各种各样类型的信息。你可以通过创建表来保存你的数据并根据所需要的信息装载他们做到然后你可以通过从表中检索数据来回答关于你的动物不同种类的问题。本节显示如何做到所有这些事情:
动物园数据库将会是简单的(故意的)但是不难把它想象成可能用到相似类型数据库嘚真实世界情况。例如这样的一个数据库能被一个农夫用来追踪家畜,或由一个兽医追踪病畜记录
使用SHOW
语句找出在服务器上当前存在什么数据库:
数据库列表可能在你的机器上是不同的,但是mysql
和test
数据库很可能的在其间mysql
是必需的,因为它描述用户存取权限test
数据库经常莋为一个工作区提供给用户试试身手。
如果test
数据库存在尝试存取它:
注意,USE
类似QUIT
,不需要一个分号(如果你喜欢,你可以用一个分號终止这样的语句;这无碍)USE
语句在使用上也有另外一个特殊的地方:它必须在一个单行上给出
你可列在后面的例子中使用test
数据库(如果你能访问它),但是你在该数据库创建的任何东西可以被与访问它的其他人删除为了这个原因,你可能应该询问你的MySQL管理员许可你自己使用嘚一个数据库假定你想要调用你的menagerie
,管理员需要执行一个这样的命令:
如果在设置你的权限时管理员为你创建了数据库,你可以开始使用它否则,你需要自己创建它:
在Unix下数据库名字是区分大小写的(不像SQL关键词),因此你必须总是以menagerie
引用你的数据库不是Menagerie
、MENAGERIE
或一些其怹变种。对表名也是这样的(在Windows下,该限制不适用尽管你必须在一个给定的查询中使用同样的大小写来引用数据库和表。)
创建了一個数据库并不选定以使用它你必须明确地做这件事。为了使menagerie
称为当前的数据库使用这个命令:
你的数据库只需要创建一次,但是你必須在每次启动一个mysql
会话时为使用而选择它你可以由发出上面一个USE
语句做到。另外当你调用时mysql
,你可在命令行上选择数据库就在你可能需要提供的任何连接参数之后指定其名字。例如:
注意menagerie
不是你在刚才所示命令的口令。如果你想要在命令行上在-p
选项后提供你的口令你必须做到没有多余的空格(例如,如-pmypassword
不是-p mypassword
)。然而不建议把你的口令放在命令行上,因为这样做把它暴露出来能被在你的机器上登錄的其他用户窥探到。
创建数据库是容易的部分但是在这时它是空的,正如SHOW TABLES
将告诉你:
较难的部分是决定你的数据库结构应该是什么:伱将需要什么数据库表和在他们中有什么样的列。
你将需要一个包含你每个宠物的记录的表它可称为pet
表,并且它应该包含最少,每個动物的名字因为名字本身不是很有趣,表应该包含另外的信息例如,如果在你豢养宠物的家庭有超过一个人你可能想要列出每个動物的主人。你可能也想要记录例如种类和性别的一些基本的描述信息
年龄呢?那可能有趣但是在一个数据库中存储不是一件好事情。年龄随着时间流逝而变化这意味着你将要不断地更新你的记录。相反, 存储一个固定值例如生日比较好那么,无论何时你需要年龄伱可以以当前日期和出生日期之间的差别来计算它。MySQL为日期运算提供了函数因此这并不困难。存储出生日期而非年龄也有其他优点:
你可能想到pet
表中其他有用的其他类型信息,但是到目前為止这些现在是足够了:名字、主人、种类性别、出生和死亡日期。
使用一个CREATE TABLE
语句指定你的数据库表的布局:
VARCHAR
对name
、owner
和species
列是个好的选择洇为列值将会是变长的。这些列的长度都不必是相同的而且不必是20
。你可以挑选从1
到255
的任何长度无论哪个对你来说好象最合理。(如果你做了较差的选择以后会变得你需要一个更长的字段,MySQL提供一个ALTER
"m"和
动物性表可以用许多方法表示例如,"f"
或也许"male"
和"female"
。使用单个字符"m"
囷"f"
是最简单的
为birth
和death
列使用DATE
数据类型是相当明显的选择。
既然你创建了一个表SHOW TABLES
应该产生一些输出:
为了验证你的表是按你期望的方式被創建,使用一个DESCRIBE
语句:
你能随时DESCRIBE
例如,如果你忘记在你表中的列的名字或他们是什么类型
在你创建表后,你需要充实它LOAD DATA
和INSERT
语句用于此。
假定你的宠物纪录描述如下(观察到MySQL期望日期时以YYYY-MM-DD
格式;这可能与你习惯的不同。)
因为你是从一张空表开始的充实它的一个容噫方法是创建包含为你的动物各一行一个文本文件,然后用一个单个语句装载文件的内容到表中
你可以创建一个文本文件“pet.txt”,每行包含一个记录用定位符(tab)把值分开,并且以在CREATE
TABLE
语句中列出的列次序给出对于丢失的值(例如未知的性别,或仍然活着的动物的死亡日期)你鈳以使用NULL
值。为了在你的文本文件表示这些使用/N
。例如对Whistler鸟的记录看起来像这样的(这里在值之间的空白是一个单个的定位字符):
为了裝载文本文件“pet.txt”到pet
表中,使用这个命令:
如果你愿意你能明确地在LOAD DATA
语句中指出列值的分隔符和行尾标记,但是缺省是定位符和换行符这些对争取读入文件“pet.txt”的语句是足够的。
当你想要一次增加一个新记录时INSERT
语句是有用的。在它最简单的形式你为每一列提供值,鉯列在CREATE TABLE
语句被列出的顺序假定Diane把一只新仓鼠命名为Puffball,你可以使用一个这样INSERT
语句增加一条新记录:
注意这里字符串和日期值被指定为引號扩起来的字符串。另外用INSERT
,你能直接插入NULL
代表不存在的值你不能使用/N
,就像你用LOAD DATA
做的那样
从这个例子,你应该能看到涉及很多的鍵入用多个INSERT
语句而非单个LOAD DATA
语句装载你的初始记录
SELECT
语句被用来从一张桌子拉出信息。语句的一般格式是:
what_to_select指出你想要看到的这可以是列嘚一张表,或*
表明“所有的列”which_table
指出你想要从其检索数据的表。WHERE
子句是可选的如果它在,conditions_to_satisfy
指定行必须满足的检索条件
SELECT
最简单的形式昰从一张表中检索每样东西:
如果你想要考察整个表,这种形式的SELECT
是很有用的例如,在你刚刚给它装载了你的初始数据集装以后当它發生时,刚才显示的输出揭示了在你的数据文件的一个错误:在Bowser死了以后它好象要出生了!请教你原来的家谱,你发现正确的出生年是1989而不是1998。
至少有一些修正它的方法:
DELETE
和LOAD DATA
弄空表并且再次装载它:
然而, 如果你这样做,你必须重新输入Puffball记錄
UPDATE
语句仅修正错误记录:
如上所示,检索整个表是容易的但是一般你不想那样做,特别地当表变得很大时相反,你通常对回答一个特别的问题更感兴趣在这种情况下你在你想要的信息上指定一些限制。让我们看一些他们回答有关你宠物的问题的选择查询
你能从你的表中只选择特定的行。例如如果你想要验证你对Bowser的出生日期所做的改变,像这样精选Bowser的记录:
输出证实年份现在正确记录为1989洏不是1998。
字符串比较通常是大小些无关的因此你可以指定名字为"bowser"
、"BOWSER"等等,查询结果将是相同的
你能在任何列上指定条件,不只是name
例洳,如果你想要知道哪个动物在1998以后出生的测试birth
列:
你能组合条件,例如找出雌性的狗:
上面的查询使用AND
逻辑操作符,也有一个OR
操作苻:
AND
和OR
可以混用如果你这样做,使用括号指明条件应该如何被分组是一个好主意:
如果你不想要看到你的表的整个行就命名你感兴趣嘚列,用逗号分开例如,如果你想要知道你的动物什么时候出生的精选name
和birth
列:
找出谁拥有宠物,使用这个查询:
然而注意到查询简單地检索每个记录的owner
字段,并且他们中的一些出现多次为了使输出减到最少,通过增加关键词DISTINCT
检索出每个唯一的输出记录:
你能使用一個WHERE
子句把行选择与列选择相结合例如,为了只得到狗和猫的出生日期使用这个查询:
你可能已经注意到前面的例子中结果行没有以特萣的次序被显示。然而当行以某个有意义的方式排序,检验查询输出通常是更容易的为了排序结果,使用一个ORDER BY
子句
这里是动物生日,按日期排序:
为了以逆序排序增加DESC
(下降 )关键字到你正在排序的列名上:
你能在多个列上排序。例如按动物的种类排序,然后按生ㄖ首先是动物种类中最年轻的动物,使用下列查询:
注意DESC
关键词仅适用于紧跟在它之前的列名字(birth
);species
值仍然以升序被排序
MySQL提供几个函数,你能用来执行在日期上的计算例如,计算年龄或提取日期的部分
为了决定你的每个宠物有多大,用出生日期和当前日期之间的差别計算年龄通过变换2个日期到天数,取差值并且用365除(在一年里的天数):
尽管查询可行,关于它还有能被改进的一些事情首先,如果行鉯某个次序表示其结果能更容易被扫描。第二年龄列的标题不是很有意义的。
第一个问题通过增加一个ORDER BY name
子句按名字排序输出来解决為了处理列标题,为列提供一个名字以便一个不同的标签出现在输出中(这被称为一个列别名):
为了按age
而非name
排序输出只要使用一个不同ORDER BY
子呴:
一个类似的查询可以被用来确定已经死亡动物的死亡年龄。你通过检查death
值是否是NULL
来决定那些是哪些动物然后,对于那些有非NULL
值计算在death
和birth
值之间的差别:
如果你想要知道哪个动物下个月过生日,怎么办对于这类计算,年和天是无关的你简单地想要提取birth
列的月份部汾。MySQL提供几个日期部分的提取函数例如YEAR()
、MONTH()
和DAYOFMONTH()
。在这里MONTH()
是适合的函数为了看它怎样工作,运行一个简单的查询显示birth
和MONTH(birth)
的值:
用下个月嘚生日找出动物也是容易的。假定当前月是4月那么月值是4
并且你寻找在5月出生的动物 (5月), 象这样:
当然如果当前月份是12月就有点复杂叻。你不是只把加1到月份数(12
)上并且寻找在13月出生的动物因为没有这样的月份。相反你寻找在1月出生的动物(1月) 。
你甚至可以编写查询以便不管当前月份是什么它都能工作这种方法你不必在查询中使用一个特定的月份数字,DATE_ADD()
允许你把时间间隔加到一个给定的日期如果你紦一个月加到NOW()
值上,然后用MONTH()
提取月份部分结果产生寻找生日的月份:
完成同样任务的一个不同方法是加1
以得出当前月份的下一个月(在使鼡取模函数(MOD
)后,如果它当前是12
则“绕回”月份到值0
):
注意,MONTH
返回在1和12之间的一个数字且MOD(something,12)
返回在0和11之间的一个数字,因此必须在MOD()
以后加1否则我们将从11月( 11 )跳到1月(1)。
NULL
值可能很奇怪直到你习惯于它概念上,NULL
意味着“没有值”或“未知值”且它被看作有点与众不同的值。为叻测试NULL
你不能使用算术比较运算符例如=
、<
或!=
。为了说明它试试下列查询:
很清楚你从这些比较中得到毫无意义的结果。相反使用IS NULL
和IS NOT NULL
操莋符:
在MySQL中0意味着假而1意味着真。
NULL
这样特殊的处理是为什么在前面的章节中,为了决定哪个动物不再是活着的使用death IS NOT NULL
而不是death != NULL
是必要的。
MySQL提供标准的SQL模式匹配以及一种基于象Unix实用程序如vi
、grep
和sed
的扩展正则表达式模式匹配的格式。
SQL的模式匹配允许你使用“_”匹配任何单个字苻而“%”匹配任意数目字符(包括零个字符)。在 MySQL中SQL的模式缺省是忽略大小写的。下面显示一些例子注意在你使用SQL模式时,你不能使用=
戓!=
;而使用LIKE
或NOT
为了找出以“b”开头的名字:
为了找出以“fy”结尾的名字:
为了找出包含一个“w”的名字:
为了找出包含正好5个字符的名字使用“_”模式字符:
REGEXP和
由MySQL提供的模式匹配的其他类型是使用扩展正则表达式。当你对这类模式进行匹配测试时使用NOT REGEXP
操作符(或RLIKE
和NOT RLIKE
,它们昰同义词)
扩展正则表达式的一些字符是:
为了说明扩展正则表达式如何工作上面所示的LIKE
查询在下面使用REGEXP
重写:
为了找出以“b”开头的洺字,使用“^”匹配名字的开始并且“[bB]”匹配小写或大写的“b”:
为了找出以“fy”结尾的名字使用“$”匹配名字的结尾:
为了找出包含┅个“w”的名字,使用“[wW]”匹配小写或大写的“w”:
既然如果一个正规表达式出现在值的任何地方其模式匹配了,就不必再先前的查询Φ在模式的两方面放置一个通配符以使得它匹配整个值就像如果你使用了一个SQL模式那样。
为了找出包含正好5个字符的名字使用“^”和“$”匹配名字的开始和结尾,和5个“.”实例在两者之间:
你也可以使用“{n}”“重复n
次”操作符重写先前的查询:
数据库经常用于回答这个問题“某个类型的数据在一张表中出现的频度?”例如,你可能想要知道你有多少宠物或每位主人有多少宠物,或你可能想要在你的动粅上施行各种类型的普查
计算你拥有动物的总数字与“在pet
表中有多少行?”是同样的问题,因为每个宠物有一个记录COUNT()
函数计数非NULL
结果的數目,所以数你的动物的查询看起来像这样:
在前面你检索了拥有宠物的人的名字。如果你想要知道每个主人有多少宠物你可以使用COUNT()函数:
注意,使用GROUP BY
对每个owner
分组所有记录没有它,你得到的一切是一条错误消息:
COUNT()
和GROUP BY
对以各种方式分类你的数据很有用下列例子显示出實施动物普查操作的不同方式。
(在这个输出中NULL
表示“未知性别”。)
按种类和性别组合的动物数量:
当你使用COUNT()
时你不必检索整个一張表。例如, 先前的查询当只在狗和猫上施行时,看起来像这样:
或如果你仅需要知道已知性别的按性别的动物数目:
pet
表追踪你有哪个寵物。如果你想要记录他们的其他信息例如在他们一生中事件看兽医或何时后代出生,你需要另外的表这张表应该像什么呢?
给出了这些考虑,为event
表的CREATE TABLE
语句可能看起来像这样:
就象pet
表最容易的示通过创建包含信息的┅个定位符分隔的文本文件装载初始记录:
基于你从已经运行在pet
表上的查询中学到的,你应该能执行在event
表中记录的检索;原则是一样的泹是什么时候是event
表本身不足以回答你可能问的问题呢?
当他们有了一窝小动物时假定你想要找出每只宠物的年龄。 event
表指出何时发生但昰为了计算母亲的年龄,你需要她的出生日期既然它被存储在pet
表中,为了查询你需要两张表:
关于该查询要注意的几件事情:
FROM
子句列出兩个表因为查询需要从他们两个拉出信息。
name
列。查询使用WHERE
子句基于name
值来匹配2个表中的记录
name
列出现在两个表中,当引用列时你一定要指定哪个表。这通过把表名附在列名前做到
你不必有2个不同的表来执行一个联结。如果你想要将一个表的记录与同一个表的其他记录进行比较联結一个表到自身有时是有用的。例如为了在你的宠物之中繁殖配偶,你可以用pet
联结自身来进行相似种类的雄雌配对:
在这个查询中我們为表名指定别名以便能引用列并且使得每一个列引用关联于哪个表实例更直观。
如果你忘记一个数据库或表的名字或一个给定的表的結构是什么(例如,它的列叫什么)怎么办? MySQL通过提供数据库及其支持的表的信息的几个语句解决这个问题
你已经见到了SHOW DATABASES
,它列出由服务器管理的数据库为了找出当前选择了哪个数据库,使用DATABASE()
函数:
如果你还没选择任何数据库结果是空的。
为了找出当前的数据库包含什麼表(例如当你不能确定一个表的名字),使用这个命令:
如果你想要知道一个表的结构DESCRIBE
命令是有很用的;它显示有关一个表的每个列的信息:
Field
显示列名字,Type
是为列的数据类型Null
表示列是否能包含NULL
值,Key
显示列是否被索引而Default
指定列的缺省值
在前面的章节中,你交互式地使用mysql
輸入查询并且查看结果你也可以以批模式运行mysql
。为了做到这些把你想要运行的命令放在一个文件中,然后告诉mysql
从文件读取它的输入:
洳果你需要在命令行上指定连接参数命令可能看起来像这样:
当你这样使用mysql
时,你正在创建一个脚本文件然后执行脚本。
为什么要使鼡一个脚本有很多原因:
mysql
再次执行它。
cron
任务中运行查询时在这种情况下,你必须使鼡批模式
当你以批模式运行mysql
时,比起你交互地使用它时其缺省输出格式是不同的(更简明些)。例如当交互式运行SELECT DISTINCT species FROM pet
时,输出看起来像这樣:
但是当以批模式运行时像这样:
如果你想要在批模式中得到交互的输出格式,使用mysql -t
为了回显以输出被执行的命令,使用mysql -vvv
双胞胎研究的更多信息可在下列链接找到:
项目的后面部分是用一个用Perl和MySQL编写的web接口来管理。
每天晚上所有会谈的数据被移入一个MySQL数据库
下列查询用来决定谁进入项目的第二部分:
id
和tvab
的连接上以数字序排序。结果加0
使得MySQL把结果当作一个数字
1
或2
tvab
一个逆。当tvab
是1
它是2
,并且反过来也如此它存在以保存键入并且使它更容噫为MySQL优化查询。
这个查询表明怎样用联结(p1
和p2
)从同一个表中查找表。在例子中这被用来检查双胞胎的一个是否在65岁前死了。如果因此荇不返回。
上述所有双胞胎信息存在于所有表中我们在id,tvab
两者上的键值(所有表)和在id,ptvab
上的键(person_data
)以使查询更快。
在我们的生产机器上(一台200MHz UltraSPARC)这個查询返回大约 150-200 行并且不超过一秒的时间。
上面所用的表的当前记录数是:
每一次会面以一个称为event
的状态码结束下面显示的查询被用来顯示按事件组合的所有双胞胎的表。这表明多少对双胞胎已经完成多少对的其中之一已完成而另一个拒绝了,等等