Table is read only although primary key is present - mysql

I'm not able to update values on tables present on my database using MySQL Workbench (or equivalent software such as Toad Edge):
The tables are read-only although primary key is present.
Only very few times the "read only" label is not present and MySQL Workbench lets me update table fields values, but if this occurs, as soon as I run another query (or if I run the same query twice), the "read only" label appears again.

This is all depends of the kind of query that you execute. If it's a simple one table query with simple WHERE command, then it should not be marked as "Read Only". However if the query contains an aggregation, group by or joins, then it will be marked as read only as trying to update the showed rows should be considered ambiguous.
At least Workbench allows editing on simple WHERE filters by default. Other IDEs, like SQLYog, marks any manually queried results as Read Only. However it could be overridden and it does an evaluation if it's safe to direct edit the data, if not, it stays as Read Only.
If this is not case, then it could be that the user that you are using to connect do not have UPDATE or INSERT rights.

Related

Save MySql 'Show' result in db

So I'm kind of stumped.
I have a MySql project that involves a database table that is being manipulated and altered by scripts on a regular basis. This isn't so unusual, but I need to automate a script to run (after hours, when changes aren't happening) that would save the result of the following:
SHOW CREATE TABLE [table-name];
This command generates the ready-to-run script that would create the (empty) table in it's current state.
In SqlWorkbench and Navicat it displays the result of this SHOW command in a field in a result set, as if it was the result of a SELECT statement.
Ideally, I want to take into a variable in a procedure, and change the table name; adding a '-mm-dd-yyyy' to end of it, so I could show the day-to-day changes in the table schema on an active server.
However, I can't seem to be able to do that. Unlike a Select result set, I can't use it like that. I can't get it in a variable, or save it to a temporary, or physical table or anything. I even tried to return this as a value in a function, from which I got the error that a function cannot return a result set - which explains why it's displayed like one in the db clients.
I suspect that this is a security thing in MySql? If so, I can totally understand why and see the dangers exposed to a hacker, but this isn't a public-facing box at all, and I have full root/admin access to it. Hopefully somebody has already tackled this problem before.
This is on MySql 8, btw.
[Edit] After my first initial comments, I need to add; I'm not concerned about the data with this question whatsoever, but rather just these schema changes.
What I'd really -like- to do is this:
SELECT `Create Table` FROM ( SHOW CREATE TABLE carts )
But this seems to be mixing apples and oranges, as SHOW and SELECT aren't created equal, although they both seem to return the same sort of object
You cannot do it in the MySQL stored procedure language.
https://dev.mysql.com/doc/refman/8.0/en/show.html says:
Many MySQL APIs (such as PHP) enable you to treat the result returned from a SHOW statement as you would a result set from a SELECT; see Chapter 29, Connectors and APIs, or your API documentation for more information. In addition, you can work in SQL with results from queries on tables in the INFORMATION_SCHEMA database, which you cannot easily do with results from SHOW statements. See Chapter 26, INFORMATION_SCHEMA Tables.
What is absent from this paragraph is any mention of treating the results of SHOW commands like the results of SELECT queries in other contexts. There is no support for setting a variable to the result of a SHOW command, or using INTO, or running SHOW in a subquery.
So you can capture the result returned by a SHOW command in a client programming language (Java, Python, PHP, etc.), and I suggest you do this.
In theory, all the information used by SHOW CREATE TABLE is accessible in the INFORMATION_SCHEMA tables (mostly TABLES and COLUMNS), but formatting a complete CREATE TABLE statement is a non-trivial exercise, and I wouldn't attempt it. For one thing, there are new features in every release of MySQL, e.g. new data types and table options, etc. So even if you could come up with the right query to produce this output, in a couple of years it would be out of date and it would be a thankless code maintenance chore to update it.
The closest solution I can think of, in pure MySQL, is to regularly clone the table structure (no data), like so:
CREATE TABLE backup_20220618 LIKE my_table;
As far as I know, to get your hands on the full explicit CREATE TABLE statement, as a string, would require the use of an external tool like mysqldump which was designed specifically for that purpose.

If I update a SQL table Scheme. Do I have to update all users DBs linked tables?

I updated the SCHEMA of a live table in MySQL for use in my multi-user database. Each user has their own db and links to the production tables through ODBC.
I have been receiving a write error while trying to test my schema updates. I cannot find the core reason. I hypothesized that because the other users are in the production table but have not been relinked to update the table SCHEMA; That it is causing a conflicting write error on my relinked table.
I added a TINYINT with No NULLS and default value of 0
I double checked all datatypes for incompatibility & have tested the "non relinked" tables in a older version of the DB and confirmed it is working as intended with no errors
I expect/want to be able to edit records without a write error, but am hesitant to update the other users to the new table if it is currently having write errors
After changing the schema of a linked table, it's required to refresh the link on all Access databases connected to it.
You can do this on the ribbon through external data -> linked table manager.
Unfortunately, either all users that have a database need to do this manually, unless you automate the task on startup through vba.
You have two separate issues. To "see" new columns, then yes, you must re-link the tables.
(so above is separate question and separate issue). You thus as a general rule can add new columns to the database (even while in use). However, the client side linked tables will not see the new columns until such time you re-link. This approach (adding new columns, but not yet re-linked from Access) is certainly ok and fine - the only downside is end users can't see nor use the new columns until such time you link. From a developer point of view, this good - since your users will not see nor find new columns until such time you roll out a new front end to each work station.
Ok, now problem and issue number two.
As for adding a new column, then re-linking, and THEN having some issue is really a separate issue. In most cases, if you attempting to use a tiny int as a Boolean (and I think that is your case), then you need to ensure several things:
Do not allow nulls (you seem to have this ok).
Make sure you set a default of 0 (server side) for this column. (you might have not allowed nulls, but without a default, then Access likely will still complain. And this default is important during creating time - since the new column needs to be "filled" with zeros.
Make sure the table has a PK defined.
Consider adding a row version column (I think mySQL has these, not sure but they can help immensely).

How to toggle a read-only view in mysql workbench

I am the superuser of a particular database schema. Therefore I have all privileges on the tables in this schema, including ALTER DELETE UPDATE and INSERT.
I am administrating this database using the GUI MySQL Workbench 6.3. I used to select rows and to obtain a read-only result grid, which was convenient because it prevented me from accidentally editing data in my table.
This was indicated by a 'read only' flag in the bottom right corner of the result grid (see below).
However, I did not change anything in the structure of the table, and now when I select rows I am able to edit data and the 'read only' flag has disappeared.
I find it a bit unsecure because it would mean I could accidentally edit data in the table by mistyping.
How could I revert to a read-only result display?
The rules that allow editing a result set are very strict. The select query must be a plain one - no aggregate functions, no joins, no unions. There must be a primary key which is used to address the records to be changed.
Update: it wasn't necessary to worry about accidentally editing records in the table while not being in read-only mode.
Indeed, if you change a record in the table (in the screenshot below, I changed a year from 2010 to 2020), for this change to be actually committed in the database, you would need to click the "apply" button in the bottom right corner.
Moreover, upon closing the tab, you are asked whether or not you want to save changes. Consequently, if you accidentally edited a record, you just have to click "Don't save" upon closing the tab.

Deleting/Editing rows in MySQL ODBC linked table results in error in MS Access

I am using MS Access 2003 under Windows 7 (64bit), with external linked table at MySQL server (5.0.51a-24+lenny5), connected via MySQL ODBC connector (using 5.1.10, because the newest 5.1.11 is buggy). When I open this table in MS Access and try to delete some records from it, I get following error:
The Microsoft Jet engine stopped the process because you and another
user are attempting to change the same data at the same time.
When I try to edit some records in the table, I get following error:
This record has been changed by another user since you started editing
it. If you save the record, you will overwrite the changes the other
user made.
Copying the changes to the clipboard will let you look at the values
the other user entered, and then paste your changes back in if you
decide to make changes.
However, when I do it via deletion or update query in MS Access, it works fine! I just cannot delete the records directly from the table.
I found out (see the detailed analysis below), that the problem is present when there are double fields with values with a lot of decimal digits. See:
CREATE TABLE `_try4` (
`a` int(11) NOT NULL default '0',
`b` double default NULL,
PRIMARY KEY (`a`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci;
insert into _try4 values (1, NULL),(2, 4.532423),(3,10),(4,0),
(5,6.34324),(6, 8.2342398423094823);
The problem is only present when you try to delete/edit the last record (a = 6), otherwise it is OK!
The issue is documented:
http://support.microsoft.com/kb/280730 , proposing these 3 workarounds:
Add a timestamp column to the SQL table. (JET will then use only this field to see if the record has been updated.)
Modify the data type that is in SQL Server to a non-floating point data type (for example, Decimal).
Run an Update Query to update the record. You must do this instead of relying on the recordset update.
However, these 3 workarounds are not satisfactory. Only first could be, but this workaround didn't work - as expected. It probably works only with MS SQL Server.
Are there any other solutions/workarounds for this problem?
Additional details:
The MySQL server is just for me, nobody else is accessing it.
Insertion of new records was working fine.
Primary key is well defined for this table.
Restart of MS Access didn't help.
Deleting the link to the ODBC table and linking it again didn't help either.
Linking the table from brand new Access database didn't help.
Changing the MySQL database engine from MyISAM to InnoDB didn't help either.
There is no problem with permissions, there are all permission for this user#host.
I can normally delete the records from the MySQL console at the server without problem.
Trying to set MySQL Connector ODBC options didn't help: Allow big results, Enable automatic reconnect, Allow multiple statements, Enable dynamic cursors, Force use of forward-only cursors, Don't cache results of forward-only cursors.
I turned on debugging in MySQL ODBC connector, it created myodbc.sql log, but it didn't contain any corresponding queries when editing/deleting (don't know why).
More details about the structure of the linked table would be helpful, but I'll hazard a guess.
I've had a similar problem in both MS Access 2003 and 2010 when I included nullable boolean fields in the SQL Server linked table. Seems JET databases have a problem with nullable nit fields. Check out this answer for more information: https://stackoverflow.com/a/4765810/1428147
I fixed my problem by making boolean fields non-nullable and setting a default value. If your problem is the same as mine, but with MySQL, try doing the same.
I solved here the same issue. The solution was to remove Default Values from decimal fields in the table. I was able to keep decimal data type but just remove the default value I already defined before with 0.0000 and now I set to null and bug fixed.
My workaround was to copy the table data into excel, then use phpadmin to clear the table, then do the editing in excel and copy the 'new' data (ie, all of it, after editing) back to access.

Add only new records in MySQL via script

I have a large database which I am trying to update via perl. The information to be added comes from a csv file which I do not control (but which is trusted—it comes from a different part of our company). For each record in the file, I need to either add it (if it does not exist) or do nothing (if it exists). Adding a record consists of the usual INSERT INTO, but before that can run for a particular entry a specific UPDATE must be run.
Let's say for the sake of concreteness that the file has 10,000 entries, but 90% of them are already in the database. What is the most efficient way to import the records? I can see a few obvious approaches:
Pull all records of this type from the database, then check each of the entries from the file for membership. Downside: lots of data transfer, possibly enough to time the server out.
Read in the entries from the file and send a query for just those records with an RLIKE 'foo|bar|baz|...' query (or a stuff = 'foo' || stuff = 'bar' || ... query, but that seems even worse). Downside: huge query, probably enough to choke the server.
Read in the file, send a query for each entry, then add it if appropriate. Downside: tens of thousands of queries, very slow.
Apart from the UPDATE requirement, this seems like a fairly standard issue that presumably has a standard solution. If there is, it can probably be adapted to my case with appropriate use of tests on the auto_increment primary key.
The standard solution is to use INSERT IGNORE which won't raise an error if the insertion would fail because of a constraint. This isn't much use to you as it doesn't give you a chance to do the UPDATE before you know the INSERT is going to work. If you can do the update afterwards, however, this is ideal: just INSERT IGNORE each record and then do the UPDATE if it succeeded.
If a record already exists that means a record with a matching unique key is already in the database, so I don't understand the RLIKE proposal which is bound to be slow.
I would use Perl to grep the CSV file using SELECT count(*) FROM table WHERE key = ? for each record, and removing anything where the result is non-zero.
Then just do your UPDATE and INSERT for everything left in the filtered CSV data.
There is no need to timeout the server if you keep flushing data while iterating the list.