MYSQL: how to "reorder" a table - mysql

I have a table like the following,
| id | name | color |
------+--------+---------
| 1 | pear | green |
| 2 | apple | red |
| 3 | banana | yellow |
| 4 | grape | purple |
I'd like to reorder alphabetically using the "name" column and reset the id (autoincrement) with this new order to end up with the following
| id | name | color |
------+--------+---------
| 1 | apple | red |
| 2 | banana | yellow |
| 3 | grape | purple |
| 4 | pear | green |
QUESTION: how can I do this with MYSQL?

The cleanest way to reset the auto increment is to create another table.
MySQL provides commands such as CREATE TABLE LIKE and RENAME TABLE that are useful.
CREATE TABLE table2 LIKE table1;
INSERT INTO table2
SELECT * FROM table1 ORDER BY name;
DROP TABLE table1;
RENAME TABLE table2 TO table1;

Can I ask why you would want to do this?
If anyone modifies any of the name values or inserts new rows it will mess up your ordering scheme. Trying to store some meaning in the ordering of the PK that is already available elsewhere in the table (the name column) seems redundant and consequently a bad idea.
A much better solution is not to worry about the value of the ID column and just sort on the name column when you use the data in your app.
PS: Sorry for the non-answer type response. Normally I'd assume you had a good reason and just give an answer that directly addresses what you are trying to do, but I noticed from your other questions that you are still in the early learning stages about database design, so I wanted to help point you in the right direction instead of helping further your progress towards an ill-advised approach.

You can SELECT INTO a new table from the old table, ordering your select into as desired. Have an auto-increment ID in the new table. If needed, drop the old table and rename the new table.

Why not adding "ORDER BY name ASC" at the end of your query? My guess would be that you need the ID for some reason.

If you have a table with an autoincrement primary key (named 'id' for example), and the key is not being depended on by other tables, the way to go about this is this.
Remove the column id entirely.
alter table order by column_x, column_y;
Add the primary key column 'id' again, with autoincrement.
I did this a few times, with success and quite fast, using phpmyadmin.
Reordering a table that has a primary key as an index, is impossible. That's why u need to remove it first.
If u need to keep the 'id' column, but need to re-sort, based on other columns, u need to omit the primary key & index status of the id column & re-sort. Then you need to add a new column as primary key / index.

SELECT
RANK() Over (ORDER BY Name) As NewID
, Name
, Color
FROM Fruits
could save to a temp table then truncate then truncate the fruit table and insert, but it's probably a crappy solutions.

Related

Reduce number of joins in mysql

I have 12 fixed tables (group, local, element, sub_element, service, ...), each table with different numbers of rows.
The columns 'id_' in all table is a primary key (int). The others columns are of datatype varchar(20). The maximum number of rows in these tables are 300.
Each table was created in this way:
CREATE TABLE group
(
id_G int NOT NULL,
name_group varchar(20) NOT NULL,
PRIMARY KEY (id_G)
);
|........GROUP......| |.......LOCAL.......| |.......SERVICE.......|
| id_G | name_group | | id_L | name_local | | id_S | name_service |
+------+------------+ +------+------------+ +------+--------------+
| 1 | group1 | | 1 | local1 | | 1 | service1 |
| 2 | group2 | | 2 | local2 | | 2 | service2 |
And I have one table that combine all these tables depending on user selects.
The 'id_' come from fixed tables selected by the user are recorded into this table.
This table was crate in this way:
CREATE TABLE group
(
id_E int NOT NULL,
event_name varchar(20) NOT NULL,
id_G int NOT NULL,
id_L int NOT NULL,
...
PRIMARY KEY (id_G)
);
The tables (event) look like this:
|....................EVENT.....................|
| id_E | event_name | id_G | id_L | ... |id_S |
+------+-------------+------+------+-----+-----+
| 1 | mater1 | 1 | 1 | ... | 3 |
| 2 | master2 | 2 | 2 | ... | 6 |
This table get greater each day, an now it has about thousunds of rows.
Column id_E is the primary key (int), event_name is varchar(20).
This table has, in addition of id_E and event_name columns, 12 other columns the came from the fixed tables.
Every time than I need to retrieve information on the event table, to turn more readable, I need to do about 12 joins.
My query look like this where i need to retrieve all columns from table event:
SELECT event_name, name_group, name_local ..., name_service
FROM event
INNER JOIN group on event.id_G = group.id_G
INNER JOIN local on event.id_L = local.id_L
...
INNER JOIN service on event.id_S = service.id_S
WHERE event.id_S = 7 (for example)
This slows down my system performance. Is there a way to reduce the number of joins? I've heard about using Natural Keys, but I think this is not a good idea to form my case thinking in future maintenance.
My queries are taking about 7 seconds and I need to reduce this time.
I changed the WHERE clause and this caused not affect. So, I am sure that the problem is that the query has so many joins.
Could someone give some help? thanks a lot...
MySQL has a great keyword of "STRAIGHT_JOIN" and might be what you are looking for. First, each of your lookup tables (id/description) I have to assume already have an index on the ID column since that is primary key.
Your event table is the one you are querying as the primary basis of the details and joining to the lookups per their respective IDs. As long as your WHERE clause applicable to the EVENT table is optimized, such as the ID you are looking for, it SHOULD be virtually instantaneous.
If it is not, then it might be that MySQL is trying to think for you and take one of the secondary lookup tables and make it a primary basis of the query for whatever reason, such as much lower record count. In this case, add the keyword and try it..
SELECT STRAIGHT_JOIN ... rest of your query
This tells MySQL to do the query in the order you gave it, thus the Event table first and it's where clause on the ID. It should find that one thing, then grab all the corresponding lookup descriptions from the other tables.
Create indexes, concretely use compound indexes, for instance, start creating a compound index for event and groups:
on table events create one for (event id, group id).
then, on the group table create another one for the next relation (group id, local id).
on local do the same with service, and so on...

MySQL Database Table optimization for FASTER Querying & Performance

I have 2 tables in a my MySQL Database.
Let's call 1st main, 2nd final.
TABLE `main` has the structure | TABLE `final` has the structure
|
`id` --> PRIMARY KEY (Auto Increment) | `id` --> PRIMARY KEY (Auto Increment)
| `id_main` --> ?? (Need help here)
|
id | name | info | id | id_main | name | info(changed)
--------------------- | ---------------------------------------
1 | Peter | 5,9 | 1 | 2 | Butters | 0.3,34
2 | Butters | 3,3 | 2 | 4 | Stewie | 1.2,4.4
3 | Stan | 2,96 | 3 | 1 | Peter | 5.7,0.9
4 | Stewie | 1,84 | 4 | 3 | Stan | 4.8,0.74
After analysing data in main the results get put into final.
As you can see final has an extra column (id_main) which points back to main.id
In actuality these 2 tables are 100 million+ rows each, my problem arises while performing SQL queries.
How should final especially (id & id_main) be configured so that Querying from main to final is the fastest.
Can I do away with final.id (PRIMARY KEY, Auto Increment) & keep
final.id_main (As an UNIQUE Index?)
OR
Should I keep id AS PRIMARY KEY (AI) & final.id_main AS UNIQUE Index?
I would be making calls like:
int id_From_Main= 10000;
SELECT `id_main` FROM `final` WHERE `id`='"+id_From_Main+"'
If there's a 1:1 relation between those tables, I don't see any reason why they would need two separate auto-incremented primary keys.
I would remove the final.id column and have the final.id_main as a non-auto-incremented primary key and a foreign key to the main.id column.
In general, you can also have a table without a primary key at all. It depends on if you want to be able to select specific individual rows or not.
I don't understand your query SELECT id_main FROM final WHERE id = '"+id_From_Main+"' — you're trying to select the value of ID from main by ID from main. What's the purpose, why are you trying to get the value you already have?
Anyway, you're not providing enough information to give you a qualified answer. You have to optimize you data structures according to queries you'll be doing.
Make sure you have indexes on columns which you are using in the WHERE clausule. If you're selecting by final.id_main, have an index on that column. If you're selecting by final.id_main and final.name, have a composite index on both columns, etc.
Do you really need to have the name column in both tables? It's a bad database design, unless it's some performance optimization (to avoid a join).
So, you should:
collect all queries you're currently using, set proper indexes according to them
remove any unnecessary columns (e.g. final.id, final.name)
use the EXPLAIN on your queries to get execution information (you can also use the Explain analyzer to help you interpret the results)
you can try query profiling
In mysql, you have to define id as PK because it is auto_increment. Define id_main as UNIQUE.

How to reorder the column data values in a table alphabetically

I have mysql table like following
id,sort,enabled,font,store
1,1,1,Adlib,0
2,2,1,Arial,0
3,3,1,"Arial Bold",0
4,4,1,"Arial Black",0
----------
----------
40,40,1,Harlow,0
41,41,1,"Hobby Headline",0
42,42,1,"Hobby Horse",0
----------
----------
85,85,1,"Wild West",0
86,86,1,"Zap Chance",0
87,87,1,Helvetica,0
id column is primary key. If I add a new font entry it is stored in the last row of table
How can I reorder the font column values that they are in ascending order of their name?
NOTE: I do not want select statement, I want to reorder data in the table itself.
Update : If it is not possible in MySQL(I was just curious to know), I can solve my problem with alternate approach when displaying data. Thanks for help.
I want to reorder data in the table itself
The only actual physical order which would exist for your table would be whatever the clustered primary key is on disk. This would be the id column, and not the font name. But, in any case, in general you should proceed at the SQL level under the assumption that tables are modeled after unordered sets of records.
So, if you want the font column ordered a certain way, you should use ORDER BY:
SELECT *
FROM yourTable
ORDER BY font;
I should add that if you want a structure which can quickly search your table by the font name, then you may add an index on that column. Then, there would be a physical structure which is ordered by font, but it wouldn't be your actual table, it would be a B-tree.
One thing I learned the hard way with MySQL is that anything that doesn't have a relatively straight-forward and well documented way to be done, doesn't have it for a reason
There's no such thing in MySQL. That said, you could spend a lot of resources and force this (keeping in mind it'll probably mess with your indexes and definitely with your primary key, so whatever app you have that depends on the table will behave unexpectedly) by having a process (stored procedure, script in any programming language, etc) that:
Selects the data from the table and sorts it with an order by clause
Dumps the data on a temp table
Truncates the original table
Dumps the temp table into the recently truncated original table with a regular insert
While this would work, it's definitely not advisable to do it. Plus, it's messy and expensive. There's no real reason for something like this ever to be done. It's better to index the table appropriately and sort at query-time
The order in which the rows are stored on the disk is determined by the primary key, at least for InnoDB:
InnoDB tables arrange your data on disk to optimize queries based on primary keys.
When you move the primary key from your Id column to your font name column, the rows gets sorted by the font name column:
CREATE TABLE foobar(Id INT PRIMARY KEY, Name VARCHAR(30));
INSERT INTO foobar(Id, Name) VALUES (1, 'middle');
INSERT INTO foobar(Id, Name) VALUES (3, 'east');
INSERT INTO foobar(Id, Name) VALUES (5, 'west');
INSERT INTO foobar(Id, Name) VALUES (7, 'up');
INSERT INTO foobar(Id, Name) VALUES (2, 'down');
INSERT INTO foobar(Id, Name) VALUES (4, 'left');
INSERT INTO foobar(Id, Name) VALUES (6, 'right');
SELECT * FROM foobar;
+----+--------+
| Id | Name |
+----+--------+
| 1 | middle |
| 2 | down |
| 3 | east |
| 4 | left |
| 5 | west |
| 6 | right |
| 7 | up |
+----+--------+
ALTER TABLE foobar DROP PRIMARY KEY;
ALTER TABLE foobar ADD PRIMARY KEY(Name);
SELECT * FROM foobar;
+----+--------+
| Id | Name |
+----+--------+
| 2 | down |
| 3 | east |
| 4 | left |
| 1 | middle |
| 6 | right |
| 7 | up |
| 5 | west |
+----+--------+

Query to Re-index Primary Key of MySQL Database

I've got a table in MySQL that has a Primary Key Column.
Lets say:
ID | Value
1 | One
2 | Two
6 | Three
8 | Four
9 | Five
How do I get it to be:
ID | Value
1 | One
2 | Two
3 | Three
4 | Four
5 | Five
There are no other tables. Just the one.
I just want the ID to be in a proper series.
Any suggestion??
A Query perhaps.. :)
There is even a simple way to accomplish the result by writing this query
SET #newid=0;
UPDATE tablename SET primary_key_id=(#newid:=#newid+1) ORDER BY primary_key_id;
This query will reindex the primary key starts from 1
Seems to me you have two options.
1) create a new table and copy the existing data over.
2) add another autoincrement field to the existing table, then delete the original column.
ALTER TABLE tableName ADD NewIdn INT NOT NULL AUTO_INCREMENT KEY
I did this in phpmyadmin by unchecking the A_I box (Auto Increment setting), clicking save, and then checking it again, and clicking save again.

Keeping page changes history. A bit like SO does for revisions

I have a CMS system that stores data across tables like this:
Entries Table
+----+-------+------+--------+--------+
| id | title | text | index1 | index2 |
+----+-------+------+--------+--------+
Entries META Table
+----+----------+-------+-------+
| id | entry_id | value | param |
+----+----------+-------+-------+
Files Table
+----+----------+----------+
| id | entry_id | filename |
+----+----------+----------+
Entries-to-Tags Table
+----+----------+--------+
| id | entry_id | tag_id |
+----+----------+--------+
Tags Table
+----+-----+
| id | tag |
+----+-----+
I am in trying to implement a revision system, a bit like SO has. If I was just doing it for the Entries Table I was planning to just keep a copy of all changes to that table in a separate table. As I have to do it for at least 4 tables (the TAGS table doesn't need to have revisions) this doesn't seem at all like an elegant solution.
How would you guys do it?
Please notice that the Meta Tables are modeled in EAV (entity-attribute-value).
Thank you in advance.
Hi am currently working on solution to similar problem, I am solving it by splitting my tables into two, a control table and a data table. The control table will contain a primary key and reference into the data table, the data table will contain auto increment revision key and the control table's primary key as a foreign key.
taking your entries table as an example
Entries Table
+----+-------+------+--------+--------+
| id | title | text | index1 | index2 |
+----+-------+------+--------+--------+
becomes
entries entries_data
+----+----------+ +----------+----+--------+------+--------+--------+
| id | revision | | revision | id | title | text | index1 | index2 |
+----+----------+ +----------+----+--------+------+--------+--------+
to query
select * from entries join entries_data on entries.revision = entries_data.revision;
instead of updating the entries_data table you use an insert statement and then update the entries table's revision with the new revision of the entries table.
The advantage of this system is that you can move to different revisions simply by changing the revision property within the entries table. The disadvantage is you need to update your queries. I am currently integrating this into an ORM layer so the developers don't have worry about writing SQL anyway. Another idea I am toying with is for there to be a centralised revision table which all the data tables use. This would allow you to describe the state of the database with a single revision number, similar to how subversion revision numbers work.
Have a look at this question: How to version control a record in a database
Why not have a separate history_table for each table (as per the accepted answer on the linked question)? That simply has a compound primary key of the original tables' PK and the revision number. You will still need to store the data somewhere after all.
For one of our projects we went the following way:
Entries Table
+----+-----------+---------+
| id | date_from | date_to |
+----+--------_--+---------+
EntryProperties Table
+----------+-----------+-------+------+--------+--------+
| entry_id | date_from | title | text | index1 | index2 |
+----------+-----------+-------+------+--------+--------+
Pretty much complicated, still allows to keep track of full object's lifecycle. So for querying active entities we were going for:
SELECT
entry_id, title, text, index1, index2
FROM
Entities INNER JOIN EntityProperties
ON Entities.id = EntityProperties.entity_id
AND Entities.date_to IS NULL
AND EntityProperties.date_to IS NULL
The only concern was for a situation with entity being removed (so we put a date_to there) and then restored by admin. Using given scheme there's no way to track such kind of tricks.
Overall downside of any attempt like that is obvious - you've to write tons of TSQL where non-versioned DBs will go for something like select A join B.