move a mysql database row up or down with php - php

I have a mysql database and some php that allows you to create an entry in the database, update an entry, and view the entries as a web page or xml. What I want to do is add a function to move an entry in the database up or down by one row, or, send to the top of the database or bottom.
I've seen some online comments about doing this type of thing that suggested doing a dynamic sort when displaying the page, but I'm looking for a persistent resort. I've seen one approach suggested that would be to have a separate "sort" field in the database that is agnostic of the actual database sort key, but I'm not sure why that would be better than actually re-ordering the database
Here is a dump of the table structure:
SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
--
-- Database: `hlnManager`
--
-- --------------------------------------------------------
--
-- Table structure for table `hln_stations`
--
CREATE TABLE IF NOT EXISTS `hln_stations` (
`id` int(6) NOT NULL auto_increment,
`station_title` varchar(60) NOT NULL default '',
`station_display_name` varchar(60) NOT NULL default '',
`station_subtitle` varchar(60) NOT NULL default '',
`station_detailed_description` text NOT NULL,
`stream_url_or_playlist_url` text NOT NULL,
`link_type` varchar(25) NOT NULL default '',
`small_thumbnail_graphic_url` text NOT NULL,
`large_thumbnail_graphic_url` text NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=21 ;

Not sure what you mean by "Reordering" the database... SQL Databases typically do not make any guarantees on what order (if any) they will return records in short of an ORDER BY clause.
You need a "SortOrder" type column. I suggest you make it an int with a unique key.
You need a way to update this "SortOrder" column via the UI
Easy to program, easy to use: Implement a simple drag+drop interface in HTML using jQuery or whatever javascript library works for you. In the on-complete method (or in response to a save button), trigger an ajax call which will simply send an array of ids in the correct order. On the database side, loop over it and update the SortOrder accordingly, starting at 1, then 2, etc...
Harder to program, hard to use: Implement a classical move-up and move-down buttons. When clicked, send the id and action (eg, up, down) to the server. There are several strategies to handle this update, but I will outline a couple:
Assuming the user clicked "move up", you can swap IDs with the previous record.
Find the previous record: SELECT id FROM hln_stations WHERE SortOrder < (SELECT SortOrder FROM hln_stations WHERE id = ...) ORDER BY SortOrder DESC LIMIT 1
Run two update statements, swapping the SortOrder. Reverse for moving down. Add special code to detect top or bottom.
etc...
There are other ways, but for a web interface, I suggest you do Drag+Drop, as the users will love it.

Databases are not "stored" in any order. They are stored in whatever way is convenient for the storage subsystem. If you delete a record, a new record may use the space of the old record "inserting" itself into the database. While it may seem like the database always returns records in a particular order, you can't rely on it.
The ONLY way to assure a sort order is to have a field to sort on.

Dont know where you can find example to find example. but you can look the following code it is very basic:
Let id is your primary key and there is a column sort_order. You want to store primary keys in the following order: 5,4,3,6,8,7,9,10,2,1.
then you store them in an array:
$my_sorted = array(5,4,3,6,8,7,9,10,2,1);
then you update your table:
update `mytable` set `sort_order` = (index of $my_sorted) WHERE `id`=(array value of that index).
Instead of doing many queries you can do it in one query like:
$query = "UPDATE `mytable` SET sort_order= CASE id ";
foreach($my_sorted as $key=>$val){
$query .= " WHEN '$val' THEN $key ";
}
$query .="END";
Then you run $query in mysql.
After updating table you can select from mytable with order by sort_order asc or desc.
hope this helps.

"re-ordering" the database would require two records swapping primary keys, or most likely they would need to have all data except the primary keys be swapped. this would most likely be undesireable, since the primary key should be the one way you can consistently refer to a particular record.
The separate order field would be the way to go. Just make sure that you put an index on the order field so that things stay speedy.

There is no way to find out in which order databases stores data. When we query to database, we specify the field name that we want our data to be sorted by.
In your case, I would add a new column: sequence int(10). and write php function to change/update sequence number. when i will use select query, I will order by sequence number.

Related

MySQL "locking" table at one row only max

Here is my table
`id` int(11) NOT NULL,
`notifyroles` varchar(50) NULL,
PRIMARY KEY (`id`)
ENGINE=MyISAM DEFAULT CHARSET=utf8
I use it to store a single set of dynamic values of an array that is imploded to string such as item1,item2,item3 and when I pull the data from the db I will explode those values again.
When I initialize my software I insert row id 1 and then leave the notifyroles element as NULL until I used it.
It will and should never have any other rows but row 1 and so I chose not to use the auto increment feature. I never use INSERT I always just use UPDATE for id 1.
Since i dont want to have to write a bunch of code to check for more rows and truncate it and reset it if there is and all of that stuff my question is:
Is there a way to lock the table so that it cannot have more than 1 row? And if someone tried to INSERT another row it would fail.
ps. I am hoping that with the evolution of MySQL that maybe after all this time there is such a way.
Simplest is to manage the rights so the user your software uses has no insert rights but does have update rights on that table.
See: http://dev.mysql.com/doc/refman/5.7/en/grant.html
There's not really a way to lock a table, but you can take advantage of MySQL triggers. As the name suggest, they are activated immediately at the time the specified action is performed, in this case, an insert. Maybe try this:
CREATE TRIGGER locktable
AFTER INSERT ON mytable
FOR EACH ROW
BEGIN
IF (NEW.id != --id of the row you want protected--) THEN
DELETE FROM mytable WHERE id = NEW.id;
END IF;
END;
Why not BEFORE INSERT? some strategies suggest causing the query to fail, but I'm really not comfortable with that approach.
I hope it helps.

How to select a multiple column primary key of an inserted row?

Problem:
I have the following table in MySQL.
For this example lets say that there is (and always will be) only one person in the world called "Tom" "Bell". So (name, surname) is the PRIMARY KEY in my table. Every person has his salary, an unsigned integer.
CREATE TABLE IF NOT EXISTS `user` (
`name` varchar(64) NOT NULL DEFAULT 'Default_name',
`surname` varchar(64) NOT NULL DEFAULT 'Default_surname',
`salary` int(10) unsigned NOT NULL DEFAULT '0',
UNIQUE KEY `id` (`name`,`surname`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Whenever I insert a row using a PHP script I want my function to return the primary key of the inserted row (an array key=>value).
From PHP context I do not know what the primary key of table 'user' consists of and I do not always need to set all primary key values (example 2, very stupid, but possible).
I can add another argument to my insert function (for example I could pass the table name, in this case "user").
If this matters, I am using PDO (php data objects) to connect with my MySQL database.
Example 1:
$db->insert('INSERT INTO `user` (`name`,`surname`,`salary`) VALUES ('Tom','Bell','40');');
should return an array:
$arr = ['name' => 'Tom', 'surname' => 'Bell'];
Example 2:
$db->insert('INSERT INTO `user` (`name`,`salary`) VALUES ('Nelly','40');');
should return an array:
$arr = ['name' => 'Nelly', 'surname' => 'Default_surname'];
Disclaimer & other information:
I know this is not a well-designed table, I could use an auto_increment id column to make it much easier and probably more efficient as well. This is just an example to show the problem without having to explain my project structure.
Without loss of generality: Using functions like "getLastInsertId()" or "##identity" will return 0, I guess the reason is because the table does not have an auto_increment column.
What have I tried? Nothing (other than things stated in point 2 (which I was certain it wouldn't work) and searching for a solution).
There aren't "nice" ways around this problem. One of the reasons for having an auto_increment is to avoid having problems like you described.
Now, to avoid my answer to be one of those that take into account only half the picture - I do realize that sometimes you inherit a project or you simply screw up during initial stages and you have to fix things quickly.
To reflect on your example - your PK is a natural PK, not a surrogate one like auto_increment is. Due to that fact it's implied that you always know the PK.
In your example #1 - you inserted Tom Bell - that means you knew the PK was Tom Bell since you instructed MySQL to insert it. Therefore, since you knew what the PK was even before insert, you know how to return it.
In your example #2 you specified only a part of the PK. However, your table definition says thtat default values for both name and surname are Default_surname. That means, if you omit either part of the PK, you know it'll assume the default value. That also means you already know before insertion what the PK is.
Since you have to use a natural PK instead of a surrogate, the responsibility of "knowing" it shifts to you instead of RDBMS. There is no other way of performing this action. The problem becomes even more complex if you allow for a default value to become null. That would let you insert more than 1 Tom with null as surname, and the index constraint wouldn't apply (null is not equal to null, therefore (tom, null) is not equal to (tom, null) and insert can proceed).
Long story short is that you need a surrogate PK or the auto_increment. It does everything you require based on the description. If you can't use it then you have a huge problem at your hands that might not be solvable.

Merge several mySQL databases with equivalent structure

I would like write a php script that merges several databases, and I would like to be sure of how to go around it before I start anything.
I have 4 databases which have the same structure and almost same data. I want to merge them without any duplicate entry while preserving (or re-linking) the foreign keys.
For example there is a db1.product table which is almost the same as db2.products so I think I would have to use LIKE comparison on name and description columns to be sure that I only insert new rows. But then, when merging the orders table I have to make sure that the productID still indicates the right product.
So I thought of 2 solutions :
Either I use for each table insert into db1.x as select * from db2.x and then make new links and check for duplicate using triggers.
Either I delete duplicate entries and update new foreign keys (after having dropped constraints) and then insert row into the main database.
Just heard of MySQL Data Compare and Toad for mySQL, could they help me to merge tables ?
Could someone indicate to me what should be the right solution ?
sorry for my english and thank you !
First thing is how are you determining whether products are the same? You mentioned LIKE comparison on name and description. You need to establish a rule what says that product is one and the same in your db1, db2 and so on.
However, let's assume that product's name and description are the attributes that define it.
ALTER TABLE products ADD UNIQUE('name', 'description');
Run this on all of your databases.
After you've done that, select one of the databases you wish to import into and run the following query:
INSERT IGNORE INTO db1.products SELECT * FROM db2.products;
Repeat for the remaining databases.
Naturally, this all fails if you can't determine how you're going to compare the products.
Note: never use reserved words for your column names such as word "name".
Firstly, good luck with this - sounds like a tricky job.
Secondly, I wouldn't do this with PHP - I'd write SQL to do the work, assuming this is a one-off migration task and not a recurring task.
As an approach, I would do the following.
Create a database with the schema you want - it sounds like each of your 4 databases have small variations in the schema. Just create the schema for now, don't worry about the data.
Create a "working" database, with the same schema, but with columns for "old" primary keys. For instance:
table ORDER
order_id int primary key auto increment
old_order_id int not null
...other columns...
table ORDER_LINE
order_line_id int primary key auto increment
old_order_line_id int not null
order_id int foreign key
...other columns...
Table by table, Insert into your working database from your first source database. Let the primary keys auto_increment, but put the original primary key into the "old_" column.
For instance:
insert into workingdb.orders
select null, order_id, ....other columns...
from db1.orders
Where you have a foreign key, populate it by finding the record in the old_ column.
For instance:
insert into workingdb.order_line
select null, ol.order_line_id, o.order_id
from db1.order_line ol,
workingdb.order
where ol.order_id = o.old_order_id
Rinse and repeat for the other databases.
Finally, copy the data from your working database into the "proper" database. This is optional - it may help to retain the old IDs for lookups etc.

MySQL: UPDATEing a row with no guaranteed unique field

I am working with an old MySQL table, which serves as a log of sorts. It looks like
CREATE TABLE `queries` (
`Email` char(32) NOT NULL DEFAULT '',
`Query` blob,
`NumRecords` int(5) unsigned DEFAULT NULL,
`Date` date DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
Now, I need to be able to UPDATE the records in this table (don't ask why, I don't know). Normally, I would just do
UPDATE table SET ... WHERE unique_column = value
But in this case, I don't have a unique column to work from.
Is there a workaround for this, or am I just going to have to push to put in a nice, standard INT NOT NULL AUTO_INCREMENT?
UPDATE queries
SET ...
WHERE Email = value1
AND Query = value2
AND NumRecords = value3
AND Date = value4
LIMIT 1;
A unique identifier is the only reliable way of doing this. Just add an auto_increment column and be done with it.
For exhaustive info including some workaround approaches (none of them perfect though!) check this question, where the OP had a table without a unique identifier and no way to change it.
Update: As Doug Currie points out, this is not entirely true: A unique ID is not necessary as such here. I still strongly recommend the practice of always using one. If two users decide to update two different rows that are exact duplicates of each other at the exact same time (e.g. by selecting a row in a GUI), there could be collisions because it's not possible to define which row is targeted by which operation. It's a microscopic possibility and in the case at hand probably totally negligeable, but it's not good design.
There are two different issues here. First, is de-duping the table. That is an entirely different question and solution which might involve adding a auto_increment column. However, if you are not going to de-dup the table, then by definition, two rows with the same data represent the same instance of information and both ought to be updated if they match the filtering criteria. So, either add a unique key, de-dup the table (in which case uniqueness is based on the combination of all columns) or update all matching rows.
In case you didn't know this, it will affect performance, but you don't need to use a primary key in your WHERE clause when updating a record. You can single out a row by specifying the existing values:
UPDATE queries
SET Query = 'whatever'
WHERE Email = 'whatever#whatever.com' AND
Query = 'whatever' AND
NumRecords = 42 AND
Date = '1969-01-01'
If there are duplicate rows, why not update them all, since you can't differentiate anyway?
You just can't do it with a GUI interface in MySQL Query Browser.
If you need to start differentiating the rows, then add an autoincrement integer field, and you'll be able to edit them in MySQL Query Browser too.
Delete the duplicates first. What's the point of having duplicate rows in the table (or any table for that matter)?
Once you've deleted the duplicates you can implement the key and they your problem is solved.

Alter MySQL column with values to auto increment

I had a hard time with the title, so let me explain.
What I'm doing is using the jQuery UI to create sortable list elements on a page. Once the order is submitted, php assigns an incrementing value to the list elements based on their order, drops the existing id column, creates a new id column and inserts each list elements value WHERE title=x. This creates the proper order of ID's, and is working fine.
What I'd like to do now is change the column to auto_increment, such that if I insert a new entry, the id is assigned automatically, one number higher than the greatest number generated by the php script. I'm not using any foreign keys or anything, just this simple table.
Is this possible?
My mistake, I misread your question. You do not want to use the database itself to provide numbering based on your sort order. You can however use the SQL query itself to return an incrementing field. One sec and I'll update with that info...
Ok, here it is:
you need to use a variable like
set #n=0;SELECT
#n:=#n+1 as 'n',
col1,
col2
from table
However, i highly recommend you just create the numbering in your php code if at all possible.
----------------Original Post----------------
This is pretty easy with phpmyadmin. Let me know if your unable to install that and I'll dig up the necessary SQL.
All heck, here is the SQL:
alter table t1 modify f1 int(4) auto_increment
alter TABLE tbl auto_increment = xxx; //change xxx to be the next id it should use
you may need to run these in opposite order depending on your existing data set it will fail to add auto_increment if you don't change the value of auto_increment to be something not already in use.

Categories