English Русский Español Português
preview
市场模拟(第 21 部分):SQL 入门(四)

市场模拟(第 21 部分):SQL 入门(四)

MetaTrader 5测试者 |
20 1
Daniel Jose
Daniel Jose

概述

大家好,欢迎阅读本系列关于复制/模拟系统的又一篇文章。

在上一篇文章“市场模拟(第 20 部分):SQL 入门(三)”中,我们简要介绍了 SELECT 命令。为了更有效地使用 SQL,或者更准确地说,为了充分利用 SQL 的所有功能,我们还需要了解一个概念。这比编写一个能完成相同工作的应用程序(即管理数据库并让我们对其进行操作)要好得多。对于数据库来说,这个概念可谓是‘关键中的关键’。这里说的就是键(key)。我们正在讨论的是键,也就是数据库中的键,包括主键和外键。

尽管 MetaEditor 允许我们使用 SQLite 执行任务,但如果你刚开始学习并希望更连贯、更规范地学习如何使用 SQL,那么你需要一个更高级的工具。一个重点:我并不是说 MetaEditor 没有用。但是,MetaEditor 并不适合用于理解某些要点,这是因为它的用途不同,即用于编辑和编译用 MQL5 编写的代码。它在帮助我们使用 SQLite 方面提供的帮助虽然很大,但对于我们学习时真正需要的却远远不够。

因此,在这种情况下,我建议使用另一种工具。这是因为它实际上是面向 SQLite 的。尽管在使用 MySQL 或其他任何 SQL 平台时,实际上我们会得到相同的结果。正如我们在之前的文章中所阐明的,我们使用哪个系统来访问 SQL 并不重要。只要我们只使用 SQL 语法,而不依赖于仅存在于特定 SQL 变体中的任何内容,那么所有这些变体都能做同样的事情。

因此,我建议你使用 DB Browser 工具。它是开源的,用 C++ 编写,可在 GitHub 上免费下载。本文末尾附有从 GitHub 下载该工具的链接。DB Browser 的一个优点是,它使得理解各种概念变得更加容易,因为该软件提供了其他语言的翻译版本,这对许多不懂英语的用户会很有帮助。

另一个细节是,与 MetaEditor 不同,MetaEditor 无法编辑、保存和使用 SQL 脚本,而 DB Browser 可以做到这一点。在学习过程的初期,这些功能非常有帮助。但对于那些已经了解 SQL 并且仅将其用于数据库查询的人来说,使用这个工具或那个工具并不会带来任何改变。因此,工具的选择由您自行决定。

下图展示了 DB Browser 的界面。当然,在这张图中,我们移除了一些选项,因为它们对于我们即将研究的内容来说是不必要的。

但在我们开始探讨主键和外键的话题之前,我想先解释一些可能会引发疑问的内容,尤其是当我们想要深入学习 SQL 时。


为何策略发生了改变?

如果你尝试在任何特定实现中使用 SQL,可能会感到有些不舒服,甚至有些失望。一些管理员在招聘数据库专家时,通常要求应聘者了解如何使用特定的数据库实现。例如:你可能会学习 SQL Server,但却找不到工作,因为那里用的是 MySQL。或者你可能会听到关于 Oracle 比其他 SQL 实现更好的观点。在之前的文章中,我们已证明持有这种想法的人实际上对数据库一无所知。他们只是简单地认为某个软件更好或更差。他们对事物的具体运作方式缺乏深入的理解,只是停留在表面,试图去评判他们并不真正了解的事物。

如果我们要使用数据库或使用服务器的实现,那么我们就会有访问数据库的方法。最常见的访问方式是通过套接字。在讨论 SQL 之前,我们在多篇文章中已详细讲解了如何使用套接字。这个想法不仅是为了解释套接字的工作原理,也是为了展示如何在 Excel 和 MetaTrader 5 之间建立双向通信。换句话说,Excel 和 MetaTrader 5 可以互相交换数据。我们不会仅限于使用 RTD 或 DDE 来传输数据,因为那样的话,数据只能被 Excel 接收。但是,如果我们知道如何使用套接字,就可以做更多的事情。

这里所展示的相同知识可用于使 MQL5 或在 MetaTrader 5 中运行的可执行文件能够通过 SQL 命令访问数据库。你只需要知道如何使用 SQL 命令,以及如何通过套接字发送和接收信息即可。从那时起,剩下的就变得简单明了,因为在信息流动方面,服务器数据库要实用得多。为了更清楚地说明这一点,我们来解释一下:托管在 SQL 服务器上的数据库比存储在文件中的数据库更具可扩展性。

然而,在使用 SQLite 时,我们的初始前提是将数据库存储在一个文件中。但这并不意味着我们只能这样做。是的,可以使用 SQLite 服务器,但通常在使用 SQLite 时,我们使用的是文件。这给我们带来了一些限制和不便。其中一些限制是可以接受的,因为数据库往往仅供特定应用程序使用。在其他情况下,这些限制将迫使我们改变策略,转而使用 SQL 服务器。

然而,本文旨在提供教育意义,主要目的是向您展示:我们无需对某些特定内容进行编程,而应尽可能使用现有工具。当数据库以文件形式存储时,这类限制就会出现,但实际上这并不会成为问题。但请记住:与使用文件存储数据库的实现方式相比,SQL 服务器在多个方面始终具有优势。

既然我们已经解释了这一点,我们可以暂时放下 MySQL 了。尽管我真的很喜欢它,但我们首先需要关注真正必要的事情。也许在未来的另一篇文章中,我们会解释如何使用套接字来编程数据库。但就目前而言,让我们看看别的东西,为了避免把一个话题和另一个话题混在一起,我们将开始一个新的话题。


为什么需要主键和外键?

要解释一些相当难以理解的内容(至少对于不了解数据库的人来说是这样),首先必须解释一个对于完全不熟悉编程的人来说同样难以理解的概念。换言之,两者之间存在联系。不过,让我们来看看我能否向你解释主键和外键存在的原因。然而,如果你对编程一无所知,我建议你至少学习一些编程语言的基础知识,以便理解我们在本讲解中会用到的某些概念。

我总是将主键和外键结合使用,它们存在的原因与关系型数据库与非关系型数据库存在差异的原因相同。现在一切都变得更为复杂,因为许多人认为数据库只有一种类型。也就是说,当大多数人听到“数据库”这个词时,他们会立刻想到键和值之间存在的关系。但这并非完全属实。问题在于某些概念的使用不当。“键-值”的概念本身并不能说明数据库是否是关系型数据库。事实上,“键-值”的概念远不止于此。为了理解这一点,让我们暂时抛开数据库,回想一下在“数据库”这个词出现之前,一切是怎样的。

应用“键-值”概念最简单的方法是使用数组。如果你知道数组是什么,那么你就知道数组中的每个索引或位置都可以包含一个值或一条记录。好,然后,使用索引(相当于键),您可以获取该位置的记录(相当于值)。知道了这一点,你就可以修改、删除这些数据,或者对这些数据做任何你想做的事情。这是该概念最基本的层面。

如果你将内存中的那个相同数组保存到文件中,那么你就可以创建一种格式,使得在将文件重新读入内存时,可以轻松地重新创建原始数组。再说一次,这只是这个想法的最基本层面。在这个阶段,你可能会想到以下内容:“嗯,作为一名程序员,我可以创建一系列的程序和子程序来更改、搜索、整理、删除数组中的任何记录等等。”请注意,此时此刻,你自己在不知不觉中已经创建了一个数据库。这是因为你使用的东西和数据库完全一样。

然后,要访问现在数据库中的任何记录或值,你需要将文件加载到内存中的数组中,执行必要的操作,然后立即将数组保存回文件中。在我们开始学习编程时,经常会练习和讲解这类内容。然而,据我所知,没有人将这类事物视为数据库。为什么?谁知道呢。但事实是,你甚至都没有意识到,你已经创建了一个个人且私密的数据库。

然而,这种解决方案往往不具备可扩展性。也就是说,信息无法在不同应用程序之间轻松传输。正是在这一点上,数据库的概念开始变得有意义,因为你可以使用其他人也会使用的东西,在这种情况下是 SQL,并编写一个可以被不同应用程序使用的数据库。这就是为什么我们从一开始就说,尽管你可以创造新的东西,但有时使用已有的东西会更好。

然而,所有这些解释仍然没有回答引出这个话题的问题。我们稍后会再谈到这一点。但是既然我们已经对数据库的基本概念有所了解,接下来就可以继续讨论下一个话题了。即,关系型数据库和非关系型数据库之间有什么区别,以及为何存在这种区别?虽然这是一个简单的问题,但答案却并不那么简单。有些有一定经验的人会立刻说:关系型数据库使用 SQL,而非关系型数据库则不使用。我甚至希望答案就这么简单,但事实并非如此。关系型数据库和非关系型数据库的区别在于“键-值”集在数据库中的放置方式。

“我的天哪!如果之前一切都很艰难,那么现在则变得完全难以忍受。但这怎么可能呢?数据库中“键-值”的放置方式怎么会有区别呢?”乍一看,这似乎没什么意义,但随着我们经验的积累和与数据库的接触,在某个时候你会明白的。然而,为了让你至少能理解我们在说什么,即使你觉得这听起来很疯狂,无论有多难,我都会尽力解释这一点。

关系型数据库的主要特征之一是其完整性,或者更准确地说,是数据库即使在我们试图破坏其完整性时,仍能保持其完整性的能力。你可以将整个数据库视为一个整体,具有完整性。但有些情况下,完整性并非首要考虑因素。当这种情况发生时,我们会得到一个不理想的结果,因为数据库应该保持其完整性。我们存在重复的“键-值”集合。“但是等一下。这种重复不应该发生,因为每个索引(作为键)都会与一条记录(作为值)相关联。”事实上,如果你这么想,那就对了。然而,如果你这么想,就说明你还在用数组的思维来思考问题。现在情况变得稍微复杂一些了。对于数组而言,每个位置代表一个值。因此,不可能占据一个位置而代表两个不同的值。从本质上讲,这是事实。

但是,如果我们不使用索引或位置,而是使用其他东西,例如一个值或一个字符串,来代表索引或键,那会怎么样呢?现在,一切开始显得相当熟悉。为了理解这一点,让我们想想如今非常普遍的事情:用 Python 编程。为什么我们要在解释中使用 Python 呢?原因是 Python 有一个概念非常适合用来解释关系型数据库和非关系型数据库之间的区别。此外,Python 还可以使用数组,这样解释就会更加合乎逻辑。

在 Python 中有一个叫做字典的概念。从广义上讲,字典是一种数据结构,其中每个条目都由一个键和一个值组成。也就是说,数组中的索引不再指示哪个值将与键相关联。你可以将键放在任何索引位置,当按键搜索时,我们仍然能找到对应的值。这种类比很有用,因为键和值变成了显式的字段,并且关联不再依赖于数字数组索引。就像可以用 Python 完成这项任务一样,也可以使用 SQL 来执行类似的任务。也就是说,我们将创建一个包含用作键的值的列。

在另一列中,我们将指定每个键与记录值之间的对应关系。如果没有适当的保护措施,一个数据库,即使是使用 SQL 编写的,也会变成非关系型数据库。你看到了吗?虽然这看起来很简单,但理解其中的各种元素能帮助我们更好地理解一些概念?但到目前为止所展示的一切都只是为了说明我们如何查看数据库。人们如何才能抵制住诱惑,不去编写一系列子程序和过程来实现 SQL 可以完成的功能呢?或者你认为你不能使用 SQL 为此目的创建一个 Python 字典吗?

在此,在继续讲解关系型数据库的基础知识之前,值得一提一个有趣的细节。许多人,主要是编程经验不多的爱好者,已经想出了无数种使用 Python 创建人工智能系统的方法。我不想批评这些人,也不想说他们错了。然而,想想以下情况:这样的人工智能系统本质上使用的是数据库。它可能是非关系型的,就像我们刚刚考察过的那种,也可能是关系型的,我们稍后会对此进行探讨。我的问题是:既然可以用 SQL 创建数据库,为什么还要用 Python 创建呢?

因此,尽管这些 GPT 引起了人们的极大热情,促使许多人学习 Python 来尝试创建类似的东西,或者至少创建一些满足特定需求的东西,但同样的事情也可以用 SQL 来完成。关键在于:使用一种或另一种语言做某事,你需要付出多少努力?之前我写了一系列关于如何创建自动运行的 EA 的文章,有些人问我为什么要这样做。但就我个人而言,我认为创建这样的东西并不存在任何特别的困难,因为其实非常容易实现。

相比之下,使用 SQL 维护和编写的数据库来学习如何在市场中进行交易的 EA 值得尊重。虽然实现起来并不困难,但需要相当多的知识和努力,尤其是为了让 EA 能够正确学习并创建数据库。最有可能的是,已经存在这样的机器人:它结合 MetaTrader 5 和 SQL,像人一样工作,在决策时具有完全的主观性:是否应该交易、买入或卖出,哪种信号更好。归根结底,只要我们掌握了正确的概念,这类东西就是可以做出来的。

现在我们可以来了解一下关系型数据库究竟是什么。如果你对编程有所了解,你肯定能理解非关系型数据库是如何产生的。但是,如果不理解第一个问题,你就无法理解第二个问题。同样,使用或不使用 SQL 都无关紧要。区别仅在于如何构建基础。

为了理解关系类型,我们需要稍微回顾一下过去。事实上,我们需要回顾上一篇文章,其中我们解释了如何从数据库中更改和删除记录。阅读之前的文章就足以理解本文所讲内容。我们已经很清楚地表明,需要一些东西来查找特定的记录。如果不使用这个“东西”(这是关键),我们就无法找到正确的位置。但是,关系型数据库中使用的键与非关系型数据库中使用的相同键有何不同?一个区别在于,在非关系型数据库中,这个键值并非唯一。但这还不是全部。暂时记住这一点。

使用关系型数据库时,此键不会重复。为此,我们通常将其定义为主键。但即便它是主键,也不意味着它不会重复。你可以告诉 SQL,一个列中的值不能重复。然而,这并不意味着属于该特定列的数据或记录就构成了一组主键。

在这里,作者认为列之所以真正体现为主键,在于外键关系的存在。这就是定义和保证数据库是关系型数据库的原因。这是因为我们现在将在一个表中的键与另一个表中的另一个键之间建立关系。在构建所有记录必须唯一的数据库时,通常会使用这种方法。但最重要的是,它们之间必须以某种方式相互关联,形成类似于图形的结构,就像下图所示的那样。

或许,仅从这张图片来看,“主键”和“外键”的概念似乎并不十分清楚。但想象一下,我们创建了一个关于我们个人生活的数据库。该数据库不需要主键或外键。然而,如果我们开始将个人联系人添加到这个相同的数据库中,无论是来自社交网络还是我们身边的人,这些联系人中的每一个都将有一个主键。但总有些时候,所有这些记录都有共同之处。如果在尝试维护这个相同数据库的过程中,你复制了这些共同点,那么在进行交叉引用查询时,过程将会变得非常缓慢且困难。

然而,如果将这些共同点放在一个特殊的表格中,你可以使用另一个键(在这种情况下,是外键)来更容易地匹配信息,从而加快查询速度以及最终可能需要对数据库进行的任何更改。这就是关系型数据库的由来。也就是说,在一个地方找到的信息将与其他地方的信息相关联。


最后的想法

我知道今天这篇文章的内容可能看起来非常抽象且难以理解。然而,我想强调的是,数据库并非一夜之间出现,而是经过漫长的定义和使用过程才发展至今。它们是经过多年逐步构建和实现的。你们中的许多人可能比我更有数据库工作经验,因此可能会有不同的看法。

由于有必要解释数据库为何以这样的方式设计,以及SQL为何具有这样的形式 — 尤其是主键和外键为何出现 — 因此有些内容必须保持一定的抽象性。同样,如果仅从解释的角度来看待这个话题,它可能会显得非常抽象且缺乏合理性。

但是,由于我想展示这个主题的基础知识,以便您能够在不过多深入SQL的情况下完成某些操作,我们需要了解主键和外键这样的概念,以及它们实际是如何工作的。这是因为,在创建数据库时,即便数据库仅用于学习,对这一概念的正确理解也至关重要。

如果我们要开始使用某样东西,就必须正确使用。研究我们并不真正理解的不同观点,无助于我们作为专业人士的成长。我们已经明确指出,使用 SQL 并不能使一个文件或一组文件成为关系型数据库。你可以简单地创建一套自己的程序、指令和子程序来创建数据库,不仅可以处理现有的数据库,还可以创建新的数据库。如果你对其中涉及的一些概念不理解,那么你最终构建的系统久而久之会变得不稳定。

我之所以能理解这一点,是因为长期以来我一直忽视了使用 SQL 或现有的实现方式。我总是坚持自己创造解决方案,但即使它们奏效,过了一段时间后,我还是不得不使用 SQL 中已有的方法。如果我当初直接使用现有的解决方案,那么所有这些努力和时间本可以更有效地利用。

在下一篇文章中,我们将实际探讨如何在数据库中使用这些键。或许通过这种方式,这个目前还比较抽象的概念会变得更加具体和易于理解。

文件描述
Experts\Expert Advisor.mq5
演示 Chart Trade 与 EA 之间的交互(交互需要 Mouse Study)。
Indicators\Chart Trade.mq5创建一个窗口,用于配置要发送的订单(需要 Mouse Study 才能进行交互)
Indicators\Market Replay.mq5创建用于与复制/模拟服务交互的控件(交互需要 Mouse Study)。
Indicators\Mouse Study.mq5提供图形控件与用户之间的交互(这对于复制系统和实际市场都是必要的)。
Services\Market Replay.mq5创建并维护市场复制/模拟服务(整个系统的主文件)。
Code VS C++\Servidor.cpp创建并维护一个用 C++ 开发的套接字服务器(迷你聊天版本)。
Code in Python\Server.py创建并维护用于 MetaTrader 5 和 Excel 之间通信的 Python 套接字。
Indicators\Mini Chat.mq5允许通过指标实现迷你聊天(需要使用服务器)。
Experts\Mini Chat.mq5允许使用 EA 实现迷你聊天功能(需要服务器)。
Scripts\SQLite.mq5演示如何在 MQL5 中使用 SQL 脚本。
 Files\Script 01.sql演示如何创建带有外键的简单表。
 Files\Script 02.sql展示如何向表中插入数据。



链接

DB Browser - 直接访问 GitHub

本文由MetaQuotes Ltd译自葡萄牙语
原文地址: https://www.mql5.com/pt/articles/12985

附加的文件 |
Anexo.zip (571.71 KB)
最近评论 | 前往讨论 (1)
Sergey Chalyshev
Sergey Chalyshev | 11 3月 2026 在 12:47
继续写吧,但别再纠结了,是时候进入第二步了,第一步已经拖得太久了。
数据科学与机器学习(第四十五部分):利用Facebook的Prophet模型进行外汇时间序列预测 数据科学与机器学习(第四十五部分):利用Facebook的Prophet模型进行外汇时间序列预测
Prophet模型由Facebook研发,是一款稳健的时间序列预测工具,能够自动捕捉趋势、季节性与节假日效应,且几乎无需人工调整。该模型已被广泛应用于需求预测与商业规划。在本文中,我们将探讨Prophet模型在外汇交易品种波动率预测中的效果,展示其如何应用于传统商业场景之外的任务。
从基础到中级:指标(五) 从基础到中级:指标(五)
在本文中,我们将探讨如何处理用户更改图表绘制模式的请求。这是必要的,以确保为当前图表绘制模式设计的指标不会显得奇怪,或与 MetaTrader 5 用户的预期不符。
您应该了解的MQL5向导技巧(第七十二部分):MACD与OBV组合形态的监督学习应用 您应该了解的MQL5向导技巧(第七十二部分):MACD与OBV组合形态的监督学习应用
本文将承接前一篇文章,之前我们介绍了MACD与OBV指标组合,本文将探讨如何通过机器学习对这一指标组合进行优化增强。MACD属于趋势指标,OBV属于成交量指标,二者为互补指标组合。本文采用卷积神经网络机器学习方案,通过有理二次核来设定网络卷积核尺寸与通道数量,从而对这套指标组合的预测结果进行微调优化。与之前类似,所有逻辑都封装在自定义信号类文件中,可配合MQL5向导直接生成智能交易系统(EA)。
回溯搜索算法(BSA) 回溯搜索算法(BSA)
如果一款优化算法能够记住它过往的搜索路径,并利用这些记忆去找到更优解,会是怎样的效果?回溯搜索算法(BSA)正是这样做的 —— 在全局探索与重访已验证可靠区域之间取得平衡。本文将为您揭开该算法的原理奥秘,思路简洁、参数极少、结果稳定。