简体   繁体   English

Laravel + mysql:可以创建/更新临时表,但不能从以下项中选择:

[英]Laravel+mysql: temporary table can be created/updated but not selected from:

I can create a temporary table, but then when I try to select from it it says the table doesn't exist. 我可以创建一个临时表,但是当我尝试从中选择时,它说该表不存在。 I figure its because DB::statement and DB::select have somehow got a different session with the database but I'm not sure how to fix it. 我之所以这么认为是因为DB :: statement和DB :: select在某种程度上与数据库进行了不同的会话,但是我不确定如何修复它。

How can I create a temporary table, insert into it, and select from it, in the same script? 如何在同一脚本中创建临时表,插入临时表并从中选择?

Below is output from tinker which demonstrates the issue: 以下是修补匠的输出,演示了此问题:

DB::select("select count(*) from users"); //12
DB::statement("create temporary table tempUsers like users"); //true
DB::statement("insert into tempUsers (id,email) VALUES (1, 'joe@example.com')"); //true

doesnt seem to exist on "select" session 在“选择”会话上似乎不存在

DB::select("select count(*) from tempUsers"); 

Illuminate\\Database\\QueryException with message 'SQLSTATE[42S02]: Base table or view not found: 1146 Table 'db.tempUsers' doesn't exist (SQL: select count(*) from tempUsers)' 带有消息“ SQLSTATE [42S02]:Illuminate \\ Database \\ QueryException:找不到基本表或视图:1146表'db.tempUsers'不存在(SQL:从tempUsers中选择count(*))”

still exists on "statement" session 在“声明”会话中仍然存在

DB::statement("insert into tempUsers (id,email) VALUES (2, 'bob@example.com')"); //true
DB::statement("insert into tempUsers (id,email) VALUES (1, 'joe@example.com')"); 

Illuminate\\Database\\QueryException with message 'SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '1' for key 'PRIMARY' (SQL: INSERT INTO tempUsers (id,email) VALUES (1,'bob@example.com'))' 消息为'SQLSTATE [23000]的Illuminate \\ Database \\ QueryException:违反完整性约束:1062键'PRIMARY'的重复条目'1'(SQL:INSERT INTO tempUsers(id,email)VALUES(1,'bob @ example.com' ))”

I get identical behavior using $table->temporary() with Blueprint , ie 使用$table->temporary()Blueprint ,我得到相同的行为,即

Schema::create('tempTable',function ($table) {$table->increments('id');
    $table->timestamps();
    $table->temporary();
}); 

Using Laravel 5.4, MySQL 5.6 使用Laravel 5.4,MySQL 5.6

I can manipulate and select from temp tables just fine when I am connected to the DB outside of laravel 当我连接到laravel外部的数据库时,我可以操作并从临时表中进行选择

If you create temp table inside stored procedure it gets destroyed once the stored procedure is completed. 如果在存储过程中创建临时表,则在存储过程完成后它将被销毁。

Scope of the temporary table is important, visible only to the particular user. 临时表的范围很重要,仅对特定用户可见。 Temporary tables begin with a pound symbol '#' or '@' very important as it seems that you have missed that part. 临时表以井号“#”或“ @”开头非常重要,因为您似乎已经错过了该部分。

So if you tweak your migration to: 因此,如果您将迁移调整为:

Schema::create('#tmpTest', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name');
});

Then run: 然后运行:

php artisan migrate:fresh

To insert data on temp table: 要在临时表上插入数据:

\\DB::statement("insert into #tmpTest (id,name) VALUES (1, 'joe@example.com')"); \\ DB :: statement(“插入#tmpTest (id,name)VALUES(1,' #tmpTest ')”));

To fetch those data using select: 要使用select来获取这些数据:

$a = DB::select('select * from #tmpTest '); $ a = DB :: select('select * from #tmpTest '); dd($a); DD($ a)的

It gives me the result: 它给了我结果:

在此处输入图片说明

Turns out the issue is caused by our reader-writer set up. 原来问题是由我们的读写器设置引起的。 We use one database for writes, and another for reads. 我们将一个数据库用于写操作,将另一个数据库用于读操作。 The writer database is replicated to the read database, but the temp table is not replicated , since its a temp table and its locked to the current session with the writer. writer数据库被复制到读取数据库, 但是 temp表没有被复制 ,因为它是一个temp表,并且已锁定到与writer的当前会话。

If using Laravel 5.5+, the solution is to set 'sticky' => true on the database connection. 如果使用Laravel 5.5+,解决方案是在数据库连接上设置'sticky' => true This makes the writer get treated as the reader after any writes, to bypass the issue of replication delay. 这使写程序在进行任何写操作后都被视为读程序,从而绕过了复制延迟的问题。

Since I am stick on Laravel 5.4 for now, my solution was to create a standard table, but treat it like a temp table and drop it at the end of the method. 由于我现在仍然坚持使用Laravel 5.4,因此我的解决方案是创建一个标准表,但将其视为临时表并将其放在方法末尾。

DB::select("select count(*) from users"); //12

//use uniqid to ensure a unique tablename since it is now in the global namespace
$tableName=uniqid('tempUsers'); 

DB::unprepared("create table $tableName like users"); //true
DB::statement("insert into tempUsers (id,email) VALUES (1, 'joe@example.com')"); //true
DB::select("select count(*) from $tableName"); //1
//...do stuff with temp table
//...
Schema::drop($tableName);
// return

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM