Can't UNION ALL on a temporary table? - mysql

I'm trying to run the following simple test- creating a temp table, and then UNIONing two different selections:
CREATE TEMPORARY TABLE tmp
SELECT * FROM people;
SELECT * FROM tmp
UNION ALL
SELECT * FROM tmp;
But get a #1137 - Can't reopen table: 'tmp'
I thought temp tables were supposed to last the session. What's the problem here?

This error indicates that the way in which MySQL tables manages the temporary tables has been changed which in turn affects the joins, unions as well as subqueries. To fix MySQL error "can’t reopen table", try out the following solution:
mysql> CREATE TEMPORARY TABLE tmp_journals_2 LIKE tmp_journals;
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO tmp_journals_2 SELECT * FROM tmp_journals;
After this you can perform the union operation.
Useful reading
http://dev.mysql.com/doc/refman/5.0/en/temporary-table-problems.html
http://www.mysqlrepair.org/mysqlrepair/cant-reopen-table.php

Figured it out thanks to sshekar's answer- the solution in this case would be
Create an empty temp table
Insert the results we want to UNION into the table separately
Query the temp table
SQL:
CREATE TEMPORARY TABLE tmp LIKE people;
INSERT INTO tmp SELECT * FROM people; /* First half of UNION */
INSERT INTO tmp SELECT * FROM people; /* Second half of UNION */
SELECT * FROM tmp;
(See Using MySQL Temporary Tables to save your brain)

As documented under TEMPORARY Table Problems:
You cannot refer to a TEMPORARY table more than once in the same query. For example, the following does not work:
mysql> SELECT * FROM temp_table, temp_table AS t2;
ERROR 1137: Can't reopen table: 'temp_table'
This error also occurs if you refer to a temporary table multiple times in a stored function under different aliases, even if the references occur in different statements within the function.

As others may wander past this question/solution thread... if they have an older Ubuntu 16.04LTS machine or similar.
The limitation exists in Ubuntu 16.04, mysql 5.7, as documented here, like eggyal reported above. The bug/feature was logged here, and ignored for more than a decade. Similarly, it was also logged against mariadb, and was resolved in version 10.2.1. Since Ubuntu 16.04LTS uses mariadb 10.0, the feature is out of easy reach without upgrading to 18.04 etc. You have to download from external repo and install directly.

Related

duplicating a MariaDB table with a small /tmp filesystem

I am duplicating a table with this command:
CREATE TABLE new_table LIKE old_table;
INSERT INTO new_table SELECT * FROM old_table;
Unfortunately, on my system /tmp is placed on separate filesystem with only 1gb of space.
If a large query is executed, that 1gb gets filled by mariadb very quickly, making it impossible to execute large queries. It is a production server so I'd rather leave the file systems as they are and instruct mariadb to make smaller temporary files and delete them on the fly.
How do you instruct mariadb to split large query into multiple temporary files so that /tmp doesn't get jammed with temporary files that cause query termination?
You can always split the INSERT into smaller pieces.
In below example I assume that i is the primary key:
WITH RECURSIVE cte1 AS (
SELECT 1 as s, 9999 as e
UNION ALL
SELECT e+1, e+9999
FROM cte1
WHERE e<=(select count(*) from old_table)
)
select CONCAT('INSERT INTO new_table SELECT * FROM old_table WHERE i BETWEEN ',s,' AND ',e) from cte1 limit 10;
This script produces several insert statement that you can run 1 after the other...
output:
INSERT INTO new_table SELECT * FROM old_table WHERE i BETWEEN 1 AND 9999 |
INSERT INTO new_table SELECT * FROM old_table WHERE i BETWEEN 10000 AND 19998 |
INSERT INTO new_table SELECT * FROM old_table WHERE i BETWEEN 19999 AND 29997
You are, of course, free to change the 9999 to any other number.
It may be related to the table content.
As explained in the doc,
Some query conditions prevent the use of an in-memory temporary table, in which case the server uses an on-disk table instead
If you have the privileges, you can try to set another disk location using
Temporary files are created in the directory defined by the tmpdir variable
Other than that, the doc is pretty clear unfortunately :
In some cases, the server creates internal temporary tables while processing statements. Users have no direct control over when this occurs.

MySQL VIEW Incorrect key file for table try to repair it

I have a FooBar view like:
CREATE VIEW `FooBar` AS
SELECT * FROM `Foo`.`Bar`
UNION ALL
SELECT * FROM `Foo1`.`Bar`
When I SELECT * FROM FooBar I get:
Incorrect key file for table '/tmp/#sql_1234_5.MYI'; try to repair it
When I run the select statements like this:
SELECT * FROM `Foo`.`Bar`
UNION ALL
SELECT * FROM `Foo1`.`Bar`
Everything goes well. The problem is clearly with my FooBar view.
When I REPAIR TABLE FooBar I get
'WhiskerDatabase.VisualDiscrimSuperimposed_Results' is not BASE TABLE
Corrupt
I tried to DROP VIEW FooBarand reCREATE VIEW FooBar... but the problems persists.
And I can't locate the sql_1234_5.MYI file in /var/lib/mysql/MyDB/.
Found the explanation here. MySQL build a temporary file. The temporary file is too big to fit in memory.
Adjusting the system memory or using a LIMIT clause could help solve the problem.
I solve my problem by creating a procedure that create a table instead of a view. Such as:
DROP TABLE `FooBar` IF EXISTS;
CREATE TABLE `FooBar` AS SELECT * FROM `Foo`.`Bar`;
INSERT INTO `FooBar` SELECT * FROM `Foo1`.`Bar`;

Use of SELECT INTO

Is it necessary to define the new table definition before using SELECT INTO query in MYSQL.
I am getting problem to execute the query when I writ e like:
SELECT *
INTO newtable
FROM oldtable
WHERE 1=0;
the error showing is:
Undeclared variabie: newtable
if you have newtable
try :
INSERT INTO newtable SELECT ...
if you don't have newtable
try :
CREATE TABLE newtable AS SELECT ...
The MySQL manual search engine is terrible but googling for something like mysql 5.5 select into will normally take you to the right page:
MySQL Server doesn't support the SELECT ... INTO TABLE Sybase SQL
extension. Instead, MySQL Server supports the INSERT INTO ... SELECT
standard SQL syntax, which is basically the same thing.
If you read the documentation here it says:
With INSERT ... SELECT, you can quickly insert many rows into a table from one or many tables
So, yes, you need to create the new table first.
You can use CREATE TABLE new LIKE old to create a new, empty table, which is a copy of the original table structure.

How to assume a table prefix on a entire MySQL script?

I have a script to run in my database.
But the problem is this script assume the tables have no prefix on it and all databases have a prefix (let call it prefix_).
Is there a command or a way to MySQL try to run
INSERT INTO prefix_mytable ...
instead of
INSERT INTO mytable...
for all of sql queries at the script (UPDATE, INSERT and DELETE)?
There is no way in MySQL to automatically prefix tables in the way you're describing. #MichaelBerkowski is correct.
The best I can suggest is that you create a second database with updateable views, using unprefixed names, as front-ends to your prefixed table names.
Here's an example:
mysql> CREATE DATABASE test;
mysql> CREATE TABLE test.prefix_mytable (id INT PRIMARY KEY, x VARCHAR(20));
mysql> CREATE DATABASE test2;
mysql> CREATE VIEW test2.mytable AS SELECT * FROM test.prefix_mytable;
Now you can insert using the unprefixed names:
mysql> INSERT INTO test2.mytable (id, x) VALUES (123, 'abc');
And to verify that the data was inserted into your original table:
mysql> SELECT * FROM test.prefix_mytable;
Once you do that, you can run your SQL script against database test2 and all the INSERTs should get to your original tables all right.
If you have a lot of tables you need to create views for, you can automate the creation of the CREATE VIEW statements:
mysql> SELECT CONCAT('CREATE VIEW test2.', REPLACE(TABLE_NAME, 'prefix_', ''),
' AS SELECT * FROM test.', TABLE_NAME, ';') AS _sql
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA='test' AND TABLE_NAME LIKE 'prefix\_%';
Here is the guide to replace WordPress table prefix from wp_ to a different, like this you can update any mysql table. How to rename WordPress tables prefix?

Existence confirmation method of the table of MySQL

I want to confirm whether there is a certain table.
When create a table, there is an SQL sentence such as DROP TABLE IF EXISTS xxx_tb.
Will there be the method that can identify the existence of the table by SQL likewise?
Use INFORMATION_SCHEMA:
select * from INFORMATION_SCHEMA.TABLES where TABLE_NAME = 'MyTable';
Should be portable across most databases.
You want the SHOW TABLES command of MySQL:
SHOW TABLES LIKE 'xxx_tb';
Or indeed, you can just do a query like
SELECT COUNT(*) FROM tbl WHERE 1=0
Which will give an error (see documentation for exact error code, or try it) if the table doesn't exist, but succeed with no results if it does.