文章 "SQLite: MQL5 原生 SQL 数据库操纵" - 页 8

 

问题 2:

尝试使用ATTACH/DETACH 函数,使用SQLite 的内置机制在数据库之间传输数据,结果出现事务错误 5601...

在 SQLiteStudio 中运行同一事务时,一切正常。

这是故意为之还是有什么问题?

   m_db.Create("IndiTemp","indi",m_db_main.GetStruct(),true);
   string db_path=StringFormat("%s\\Files\\%s.sqlite",
                               TerminalInfoString(TERMINAL_COMMONDATA_PATH),
                               "Indi");
                               
   string query=StringFormat("ATTACH DATABASE '%s' AS X; ",db_path),
          tables[];
          
   int total=m_db.GetTables(tables);
   if(total>0)
     {
      for(int i=0; i<total; i++)
         StringAdd(query,StringFormat("INSERT OR IGNORE INTO %s SELECT * FROM X.%s; ",tables[i],tables[i]));
     }
     
   StringAdd(query,"DETACH X; ");
   m_db.TransactionExecute(query);
 
Daniil Kurmyshev 程序执行 取消),这可能是 MQL 函数内部的错误,也可能是我的程序库中的部分代码:


不幸的是,DatabaseExport 函数尚未获得导出表的功能(尽管该功能是最初打算提供的),目前仅支持查询。

关于错误 4022,你是否在测试过程中遇到过,如果是,测试仪对导出文件大小有限制--写入磁盘的数据总大小为 1GB?

 
Daniil Kurmyshev SQLite 的内置机制在数据库之间传输数据,结果出现事务错误 5601...

在 SQLiteStudio 中执行同一事务时,一切正常。

这是故意为之还是有什么问题?

查询应该有效,请检查路径是否正确
 
Ilyas #:

遗憾的是,DatabaseExport 函数从未获得表格导出功能(尽管该功能是最初打算提供的),目前仅支持查询。

关于错误 4022,你是否在测试过程中遇到过,如果是,测试仪对导出文件大小有限制--写入光盘的数据总大小为 1GB?

如果在 DatabaseExport 函数中指定查询而不是表名,则在没有测试仪的情况下会出现错误 4022。

数据库的大小不到 10 Mb,我打算使用该功能将数据从光盘上的数据库复制到内存中的数据库。
 
Ilyas #:
查询应该有效,请检查路径是否正确

谢谢,我会尝试以不同的方式提供路径,但事实上,在 SQLiteStudio 中,指定路径下的查询是有效的,我将查询输出到终端日志,然后在 SQLiteStudio 中复制并执行,没有问题。

我会把结果写出来。

 
我知道SQLite 有这种功能,但我想知道 MT5 中是否包含这种功能,谢谢。
 

测试多线程写入数据库,运行多个脚本副本,每个副本都可以用 expert_id 参数标记。

#property copyright "Aliaksandr Hryshyn"
#property link      "https://www.mql5.com/zh/users/greshnik1"
#property version   "1.00"
#property script_show_inputs

enum e_E
  {
   e_0,
   e_1,
   e_2,
   e_3,
  };
input e_E expert_id=0;
//+------------------------------------------------------------------+
//| 脚本程序启动功能|
//+------------------------------------------------------------------+
void OnStart()
  {
   int db_handle=DatabaseOpen("tmp//test.sqlite",DATABASE_OPEN_READWRITE|DATABASE_OPEN_CREATE|DATABASE_OPEN_COMMON);
   const string sql_create=
      "CREATE TABLE IF NOT EXISTS Demo("
      "Id INTEGER PRIMARY KEY AUTOINCREMENT,"
      "Expert_id INTEGER,"
      "demo_0 TEXT(2000),"
      "demo_1 TEXT(2000),"
      "demo_2 TEXT(2000),"
      "demo_3 TEXT(2000),"
      "demo_4 TEXT(2000),"
      "demo_5 TEXT(2000),"
      "demo_6 TEXT(2000),"
      "demo_7 TEXT(2000)"
      ");";
   const string sql_add=
      "INSERT INTO Demo(Expert_id,demo_%s) VALUES(%s,'%s')";
   if(!DatabaseExecute(db_handle,sql_create))//如果没有,则创建表格
     {
      DatabaseClose(db_handle);
      Print("错误:",GetLastError());
      Print("查询:",sql_create);
      return;
     }
   string s1;
   string sql;
   int err_counter=100;/记录加法错误计数器
   for(int i1=0; i1<1000; i1++)
     {
      s1="";
      for(int i2=0; i2<100; i2++)
        {
         s1+=string(MathRand());
        }
      sql=StringFormat(sql_add,string(MathRand()%8),string(expert_id),s1);
      if(DatabaseExecute(db_handle,sql))/ 向 demo_... 数据集中的随机列中添加一条记录。
        {
         err_counter=100;
        }
      else
        {
         if(err_counter==0)
           {
            DatabaseClose(db_handle);
            Print(expert_id,": end");
            return;
           }
         else
           {
            Print(expert_id,": ",err_counter);
            err_counter--;
            i1--;
           }
        }
      if(IsStopped())
         break;
      Sleep(1);// 睡一会儿
     }
   DatabaseClose(db_handle);
  }

一切都写得很正确:


但我得到了关于阻塞的错误信息:

...
2021.09.18 13:08:05.252 Test_sql (EURUSD,M1)    2: 80
2021.09.18 13:08:05.267 Test_sql (EURUSD,M1)    database error, database is locked
2021.09.18 13:08:05.267 Test_sql (EURUSD,M1)    2: 79
2021.09.18 13:08:05.283 Test_sql (EURUSD,M1)    database error, database is locked
2021.09.18 13:08:05.283 Test_sql (EURUSD,M1)    2: 78
2021.09.18 13:08:05.299 Test_sql (EURUSD,M1)    database error, database is locked
2021.09.18 13:08:05.299 Test_sql (EURUSD,M1)    1: 100
2021.09.18 13:08:05.315 Test_sql (EURUSD,M1)    database error, database is locked
2021.09.18 13:08:05.315 Test_sql (EURUSD,M1)    1: 99
...

应该有一种不返回错误的有条件记录插入机制。

 
Ilyas #:
查询应该有效,请确保路径正确

1.检查 ATTACH DATABASE 是否有效!

问题出在下面,我试图附加到在 RAM 中创建的数据库,在这种情况下,物理数据库的 ATTACH DATABASE 不起作用,但如果我们将 RAM 数据库附加到物理数据库,它就会 起作用!

这足以让我在 RAM 中创建一个基础副本,从而加快计算速度。)


2.我决定更进一步...并检查另一种可能性,即

ATTACH DATABASE 'file:memdb1?mode=memory&cache=shared' AS M;

根据设想,数据库应在 RAM 中创建,并在线程关闭后停止存在,但其行为却不同...

在 1 中,我可以从任何 MQL5 程序、智能交易系统、指标、脚本、服务中加入数据库、

在 2 中,其中的数据永远保存,即使重启后也是如此,我已经想过......也许数据库是物理创建的,但搜索 *memdb1*没有找到任何东西

附注:也许是因为我从指标中创建了基础,而且它在一个共同的线程中工作?


这是个很酷的功能,但我想知道,在下一次更新和我的相关信息发布后,它是否会保留在终端中:))))。

在这种情况下,你可以轻松地在程序间传输大量数据,不会出现问题和延迟,也不会使用受名称长度限制的全局变量....。


在此执行过程中,MQL5 程序结束后,它将被删除:

ATTACH DATABASE ':memory:?cache=shared' AS M;

ATTACH DATABASE ':memory:' AS M

 

下午好!

请问 MT 开发人员,是否有可能禁用 SQLite 库的共享属性,因为根据其他项目 的经验,这就是 出现以下错误的原因:数据库 错误,数据库被锁定

如果从不同线程访问数据库,则可在数据库本身层面解决,即在打开数据库后立即执行这两个查询:

1. PRAGMA journal_mode = WAL;

PRAGMA busy_timeout = 1000;

但只有在使基础不共享 后,锁定错误才会消失,查询 无法 做到这一点

 
Daniil Kurmyshev 项目 的经验,这就是 导致错误的原因:数据库错误,数据库已锁定

如果是从不同的线程访问数据库,则可以在数据库本身的层面上解决,即在打开数据库后立即执行这两个查询:

PRAGMA journal_mode = WAL;

PRAGMA busy_timeout = 1000;

但只有当你使基础不共享时, 锁定错误才会消失,查询 是做 不到 这一点的。

在这种情况下,查询速度会下降,内存需求也会增加....。

但一切都没问题 :-)

SQLite 是为一个线程或一个写入器和多个读取器设计的。许多写入者并不使用它,而使用其他不 "轻便 "的基础。

这与 MQL 无关 - 它就是这样,而且无处不在。