Why does this table name require back-ticks? - mysql

I am seeing a curious name dependency in the following MySQL table definition. When I code the table as shown, it seems to break MySQL. When I perform "select * from dictionary_pair_join" from MySQLQueryBrowser, the status bar says "No resultset returned" -- no column names and no errors. When I insert a row into the table, the status bar says "1 row affected by the last command, no resultset returned", and subsequent selects give the same "No resultset returned" response.
When I enclose the tablename in backticks in the "select" statement, all works fine. Surely there are no mysql entities named "dictionary_pair_join"!
Here is the table definition:
DROP TABLE IF EXISTS dictionary_pair_join;
CREATE TABLE dictionary_pair_join (
version_id int(11) UNSIGNED NOT NULL default '0',
pair_id int(11) UNSIGNED default NULL,
KEY (version_id),
KEY (pair_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Here is the broken select statement:
select * from dictionary_pair_join;
Here is its working counterpart:
select * from `dictionary_pair_join`;
Why are backticks required in the select statement?
Update: This also fails in the Python mysqldb interface, which is why I started looking at it. I can put the backticks into my Python "select" generators, but I was hoping this was some stupid and easily-changed nit. I suppose I can also find a different name.

I've uprated the comments from Quassnoi and Software Guy, together they've persuaded me that it's just a bug in mysql/mysqldb/mysqlquerybrowser.
I changed the table name (to "dictionary_pair_cons") and the problem went away, in both the query browser and mysqldb.

Related

MySQL bug in the DELETE clause

Has anyone experienced a situation like this?
I accidentally typed the DELETE command in the wrong syntax (MySQL version 8.0.22). The command should never have worked, but it not only worked, it also deleted all data from the table:
Syntax: DELETE FROM test WHERE 123456;
Note that neither the column name nor the conditional operator was specified, but even so the command was executed without errors and deleted all data from the table.
The code 123456 is an example but can be any code.
Test it on any version of MySQL:
CREATE TABLE `test` (
`cod` int NOT NULL AUTO_INCREMENT,
`name` varchar(50),
PRIMARY KEY (`cod`),
KEY `ix_tmp_autoinc` (`cod`)
);
INSERT INTO `test`
(`name`)
VALUES
('MySQL bug');
INSERT INTO `test`
(`name`)
VALUES
('MySQL bug 2');
DELETE FROM test WHERE 123456;
SELECT COUNT(*) FROM test;
This is a perfectly valid statement, absolutely in accordance with the syntax for the DELETE command described at DELETE statement. On the DELETE statement page it says that WHERE must be followed by a where_condition, which is described on the SELECT statement page. There we find that a where_condition can be either a Function and Operator, or it can be an Expression. Looking at the Expression page we find the following hierarchy:
expr
|
boolean_primary
|
predicate
|
bit_expr
|
simple_expr
|
literal
So a where_condition can be a literal, which is exactly what you gave it. It may not have been what you meant, and it may not have done what you intended, but from the standpoint of MySQL syntax it's perfectly legal.
What is playing out here are MySQL complex casting rules. When you ran the following query:
DELETE FROM test WHERE 123456;
MySQL expected a boolean expression following WHERE. It didn't find that, but it did instead find an integer literal. It turns out that MySQL will treat an integer literal as being "truthy," and so it will evaluate to true.

mysql error 1062 during alter table modify column

I have a table that looks like this:
CREATE TABLE t1 (
id BIGINT AUTO_INCREMENT NOT NULL PRIMARY KEY,
col1 VARCHAR(256),
UNIQUE INDEX t1_col1_index (col1)
)
I'm trying to modify the col1 type using the following query:
ALTER TABLE t1 MODIFY COLUMN col1 varchar(191) COLLATE utf8mb4_unicode_ci;
However, I run into this duplication error:
error: ("1062", "QMYSQL3: Unable to execute statement", "Duplicate entry '+123456789' for key 't1_col1_index'")
I initially thought it could be because two or more rows might 'contain' similar value for col1 and on changing varchar length the data gets truncated but then I found out that data truncation wouldn't even allow the query to go through. Any pointers on what could be causing this?
EDIT (Resolved): Truncation does happen when ##sql_mode is not set with STRICT_TRANS_TABLES. This was causing the error.
You are reducing the length of a varchar column that is controlled by a UNIQUE constraint.
This is risky business. Oversize data will be silently trimed (unless you have the ##sql_mode set to STRICT_TRANS_TABLES in which case an error will be raised). This probably generates duplicates, which cause the error to be raised by your UNIQUE constraint.
You can check the max length of the values in your column with :
SELECT MAX(CHAR_LENGTH(col1)) FROM t1:
I am not sure if this is work.
Try to check the table t1.
select count(1) from t1 where col1 = 123456789
Now if count is greater than one then try to remove the other one and leave only one record.
Then try to run your statement again.
Reminder:
Do back up first before removing.

MySQL 8 does not detect functional dependencies in select distinct queries

I create a table using this query:
create table a (
`id` int not null auto_increment,
b varchar(10),
primary key (`id`)
);
Executing
select distinct `id` from a order by `b`;
results in this error:
ERROR 3065 (HY000): Expression #1 of ORDER BY clause is not in SELECT list, references column 'portal.a.b' which is not in SELECT list; this is incompatible with DISTINCT
But if I change the query to
select `id` from a group by `id` order by `b`;
which is logically equivalent, it succeeds.
I'm using the official Docker image for MySQL and mysql --version displays
mysql Ver 8.0.12 for Linux on x86_64 (MySQL Community Server - GPL)
It seems that MySQL does not still detect functional dependencies in select distinct queries. Am I right? Are MySQL's developers going to fix this?
The opposite behaviour was actually reported as a bug and fixed in MySQL 5.7.5:
Several issues related to the ONLY_FULL_GROUP_BY SQL mode were corrected:
With ONLY_FULL_GROUP_BY enabled, some valid queries were rejected if the accessed table was replaced by a view.
Queries of the form SELECT DISTINCT col1 ... ORDER BY col2 qualify as forbidden by SQL2003 (hidden ORDER BY columns combined with DISTINCT), but were not rejected with the ONLY_FULL_GROUP_BY SQL mode enabled.
Also, the documentation explicitly states that this is the intended behaviour:
To prevent this problem, a query that has DISTINCT and ORDER BY is rejected as invalid if any ORDER BY expression does not satisfy at least one of these conditions:
The expression is equal to one in the select list
All columns referenced by the expression and belonging to the query's selected tables are elements of the select list
without mentioning functional dependencies. In contrast to group by, the relevant error message does not reference functional dependencies either.
While the optional feature T301 Functional dependencies in the sql standard does modify the conformity rules for group by (and others), it doesn't change any restriction on order by plus distinct, which means it is still forbidden.
This comes from the introduction of a new SQL MODE from MySQL 5.7 : ONLY_FULL_GROUP_BY
The goal of this mode was to make MySQL behave as the SQL standard on GROUP BY queries.
This mode is activated on your database. You can either disable it, or adapt your queries to respect standards, which is probably the best thing to do.
This will throw your error:
SET sql_mode = 'ONLY_FULL_GROUP_BY';
drop table a;
create table a (
`id` int not null auto_increment,
b varchar(10),
primary key (`id`)
);
INSERT INTO a VALUES (NULL, 'aaaa');
INSERT INTO a VALUES (NULL, 'bbbb');
select distinct `id` from a order by `b`;
If you remove the ONLY_FULL_GROUP_BY mode, you get your results :
SET sql_mode = '';
drop table a;
create table a (
`id` int not null auto_increment,
b varchar(10),
primary key (`id`)
);
INSERT INTO a VALUES (NULL, 'aaaa');
INSERT INTO a VALUES (NULL, 'bbbb');
select distinct `id` from a order by `b`;
You can see it live on Rextester

OUTPUT Inserted.row in mysqli

I have the following sql table:
id|email|fbid
When I perform the query
INSERT INTO users(email,fbid) VALUES('randomvalue','otherrandomvalue')
I want to get the id of the inserted row. To do so, I've tried to edit the query like this:
INSERT INTO users(email,fbid) VALUES('randomvalue','otherrandomvalue') OUTPUT Inserted.id
But I'm getting:
1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use
near 'OUTPUT Inserted.id' at line 1
What could be the problem?
Unfortunately (as far as I can tell) mysql does not support output as sql-server does.
You do have an option for what you're trying to accomplish in a single row insert (assuming auto_increment primary key):
SELECT LAST_INSERT_ID();
This unfortunately would not work in the case of a batch insert - though in your case you are not (at least not in your example), so this should be fine.
I'm going to use the process i describe below to handle the same situation with a private at home (non-enterprise) application that i wrote for personal use. I know this question is a year old right now but there doesn't seem to be an adequate answer for batch processing. I can't find an adequate answer. MySQL doesn't seem to have the facilities built into it to handle this type of thing.
I had concerns about the reliability of this solution, when put into a production environment where multiple different users/jobs could access the same procedure at the same time to do the insert. I believe I have resolved these concerns by adding the connection id to the #by variable assignment. Doing this makes it so that the by has a: the connection id for the session and b: the name of the program/job/procedure doing the insert. Combined with the date AND time of the insert, I believe these three values provide a very secure key to retrieve the correct set of inserted rows. If absolute certainty is required for this, you could possibly add a third column of a GUID type (or varchar) generate a GUID variable to insert into that, then use the GUID variable along with #by and #now as your key. I feel it's unnecessary for my purpose because the process I'm going to use it in is an event (job) script that runs on the server rather than in PHP. So I am not going to exemplify it unless someone asks for that.
WARNING
If you are doing this in PHP, consider using a GUID column in your process rather than the CreatedBy. It's important that you do that in PHP because your connection can be lost in between inserting the records and trying to retrive the IDS and your CreatedBy with the connection ID will be rendered useless. If you have a GUID that you create in PHP, however, you can loop until your connection succeeds or recover using the GUID that you saved off somewhere in a file. The need for this level of connection security is not necessary for my purposes so I will not be doing this.
The key to this solution is that CreatedBy is the connection id combined with the name of the job or procedure that is doing the insert and CreatedDate is a CURRENT_TIMESTAMP that is held inside a variable that is used through the below code. Let's say you have a table named "TestTable". It has the following structure:
Test "Insert Into" table
CREATE TABLE TestTable (
TestTableID INT NOT NULL AUTO_INCREMENT
, Name VARCHAR(100) NOT NULL
, CreatedBy VARCHAR(50) NOT NULL
, CreatedDate DATETIME NOT NULL
, PRIMARY KEY (TestTableID)
);
Temp table to store inserted ids
This temporary table will hold the primary key ids of the rows inserted into TestTable. It has a simple structure of just one field that is both the primary key of the temp table and the primary key of the inserted table (TestTable)
DROP TEMPORARY TABLE IF EXISTS tTestTablesInserted;
CREATE TEMPORARY TABLE tTestTablesInserted(
TestTableID INT NOT NULL
, PRIMARY KEY (TestTableID)
);
Variables
This is important. You need to store the CreatedBy and CreatedDate in a variable. CreatedBy is stored for consistency/coding practices, CreatedDate is very important because you are going to use this as a key to retrieve the inserted rows.
An example of what #by will look like: CONID(576) BuildTestTableData
Note that it's important to encapsulate the connection id with something that indicates what it is since it's being used as a "composite" with other information in one field
An example of what #now will look like: '2016-03-11 09:51:10'
Note that it's important to encapsulate #by with a LEFT(50) to avoid tripping a truncation error upon insert into the CreatedBy VARCHAR(50) column. I know this happens in sql server, not so sure about mysql. If mysql does not throw an exception when truncating data, a silent error could persist where you insert a truncated value into the field and then matches for the retrieval fail because you're trying to match a non-truncated version of the string to a truncated version of the string. If mysql doesn't truncate upon insert (i.e. it does not enforce type value restrictions) then this is not a real concern. I do it out of standard practice from my sql server experience.
SET #by = LEFT(CONCAT('CONID(', CONNECTION_ID(), ') BuildTestTableData'), 50);
SET #now = CURRENT_TIMESTAMP;
Insert into TestTable
Do your insert into test table, specifying a CreatedBy and CreatedDate of #by and #now
INSERT INTO TestTable (
Name
, CreatedBy
, CreatedDate
)
SELECT Name
, #by
, #now
FROM SomeDataSource
WHERE BusinessRulesMatch = 1
;
Retrieve inserted ids
Now, use #by and #now to retrieve the ids of the inserted rows in test table
INSERT INTO tTestTablesInserted (TestTableID)
SELECT TestTableID
FROM TestTable
WHERE CreatedBy = #by
AND CreatedDate = #now
;
Do whatever with retreived information
/*DO SOME STUFF HERE*/
SELECT *
FROM tTestTablesInserted tti
JOIN TestTable tt
ON tt.TestTableID = tti.TestTableID
;
if You are using php then it is better to use following code :
if ($conn->query($sql) === TRUE) {
$last_id = $conn->insert_id;
echo "New record created successfully. Last inserted ID is: " . $last_id;
} else {
echo "Error: " . $sql . "<br>" . $conn->error;
}
where $conn is connection variable.

MySQL: unexpected SELECT result after INSERT into table with autoincrement column

I'm seeing a weird behavior when I INSERT some data into a table and then run a SELECT query on the same table. This table has an auto-increment primary key (uid), and this problem occurs when I try to then select results where 'uid IS NULL'.
I've golfed this down to the following SQL commands:
DROP TABLE IF EXISTS test_users;
CREATE TABLE test_users (uid INTEGER PRIMARY KEY AUTO_INCREMENT, name varchar(20) NOT NULL);
INSERT INTO test_users(name) values('foo');
SELECT uid FROM test_users WHERE uid IS NULL;
SELECT uid FROM test_users WHERE uid IS NULL; -- no output from this query
I'd expect SELECT uid FROM test_users WHERE uid IS NULL to never return anything, but it does, sometimes. Here's what I've found:
Version of MySQL/MariaDB seems to matter. The machine having this problem is running MySQL 5.1.73 (CentOS 6.5, both 32-bit and 64-bit). My other machine running 5.5.37-MariaDB (Fedora 19, 64-bit). Both running default configs, aside from being configured to use MyISAM tables.
Only the first SELECT query after the INSERT is affected.
If I specify a value for uid rather than let it auto-increment, then it's fine.
If I disconnect and reconnect between the INSERT and SELECT, then I get the expected no results. This is easiest to see in something like Perl where I manage the connection object. I have a test script demonstrating this at https://gist.github.com/avuserow/1c20cc03c007eda43c82
This behavior is by design.
It's evidently equivalent to SELECT * FROM t1 WHERE id = LAST_INSERT_ID(); which would also work only from the connection where you just did the insert, exactly as you described.
It's apparently a workaround that you can use in some environments that make it difficult to fetch the last inserted (by your connection) row's auto-increment value in a more conventional way.
To be precise, it's actually the auto_increment value assigned to the first row inserted by your connection's last insert statement. That's the same thing when you only inserted one row, but it's not the same thing when you insert multiple rows with a single insert statement.
http://dev.mysql.com/doc/connector-odbc/en/connector-odbc-usagenotes-functionality-last-insert-id.html