Composite keys with AUTO_INCREMENT and CURRENT_TIMESTAMP working together - php

Similarly to many other questions about composite keys with AUTO_INCREMENT, I am receiving the following error:
Incorrect table definition; there can be only one auto column and it must be defined as a key
What I'm doing is making a history trail of all changes in the table. Every time a change is made, a new row is inserted with a new timestamp, leaving previous modifications untouched.
My DDL in concern is this:
DROP TABLE IF EXISTS personnel;
CREATE TABLE IF NOT EXISTS personnel
(
modified TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
id INTEGER UNSIGNED AUTO_INCREMENT NOT NULL,
...
PRIMARY KEY (modified, id),
...
) ENGINE=InnoDB;
I presume that I'm getting this error because I am using both CURRENT_TIMESTAMP and AUTO_INCREMENT. So is there a way to resolve this without making PHP do the timestamp generation (so my model can just insert as if it were any other table, letting the controller do the dirty work).

MySQL's error message has more to be desired...
The autoincrementing column has to be at the beginning of an index. In your case you need to add another index - KEY id(id).

Related

How to limit number of entries in MySQL database?

how to limit the number of entry in inserting data in mysql database using php to 1
Any suggestions? Thanks .
You probably can't get it right in PHP since the trip back and forth to the database leaves room for another part of your application to create an entry. Normally we achieve this sort of thing by putting a unique index on the table that prevents duplication of data. For example:
CREATE TABLE alf_mimetype
(
id BIGINT NOT NULL AUTO_INCREMENT,
version BIGINT NOT NULL,
mimetype_str VARCHAR(100) NOT NULL,
PRIMARY KEY (id),
UNIQUE (mimetype_str)
) ENGINE=InnoDB;
If you attempt to insert a row with duplicate mimetype_str, the database will generate an exception. Catch it in your application and you'll know that your single entry for that particular row is already there.
You can create UNIQUE keys on multiple columns as well. Your primary key also represents a unique constraint and can consist of multiple columns.

Fragmenting a huge table

I currently am working on some project that insert a lot of data into some tables. To ensure that my system is fast enough, I want to fragment my huge table into some smaller tables representing the months data. I have an idea of how it will work, but I still need some more informations.
The primary keys of my tables must be continuous so I thought of an architecture that would look like this:
CREATE TABLE `foo` (
`id` bigint(11) unsigned NOT NULL AUTO_INCREMENT,
}
CREATE TABLE `foo012014` (
`id` bigint(11),
`description` varchar(255),
}
CREATE TABLE `foo022014` (
`id` bigint(11),
`description` varchar(255),
}
On every insertion, the PHP page will look if a table already exists for the month and if not will create it.
The thing is, how do I get to bind the "foo" child table primary key to the "foo" mother table? Plus, is this design a bad practice or is it good?
It's not a good pratice, and difficult your queries.
With just the id you already have an index, which allows for better indexing of your data.
If your queries are also nicely written and organized, the time to execute a query in your database will be relatively small with 1 million rows or 20.
Solutions
First
For a better maintenance I recommend the following:
Add a new field in your table food: created datetime DEFAULT CURRENT_TIMESTAMP (works in MySQL 5.6+, for other versions, or set manually in every insert, or change to timestamp)
And, just use this field for group your data basead in datetime values, like that: 2014-01-24 13:18.
It's easy to select and manipulate.
Second
Create a external table with month and year, like that:
drop table if exists foo_periods;
create table foo_periods (
id int not null auto_increment primary key,
month smallint(4) not null,
year smallint(4) not null,
created datetime,
modified datetime,
active boolean not null default 1,
index foo_periods_month (month),
index foo_periods_year (year)
);
You can change smallint in month to varchar if you feels better.
Then, just create a FK, and done!
ALTER TABLE foo
ADD COLUMN foo_period_id int not null;
ALTER TABLE foo
ADD CONSTRAINT foo_foo_period_id
FOREIGN KEY (foo_period_id)
REFERENCES foo_periods (id);
References
If you want read more about fragmentation / optimization in MySQL, this is a great post.

How to keep track of mysql database table entries by chronological insertion in php

I had originally wanted my alarmID value to be the primary key and to be Auto incremented. But I have decided to make my Title value as so.
How can I manually auto increment alarmID so that every time I insert values, the alarmID value gets incremented by exactly 1.
I want a way to keep track of entries by when they were inserted to be display chronologically later on.
Here is how I have my php code.
$sql = "CREATE TABLE IF NOT EXISTS alarms (
alarmID INT NOT NULL,
PRIMARY KEY (Title),
Title CHAR(30) NOT NULL,
Description TEXT,
DT DATETIME
)";
Something like this should work, you still get a unique indexed title and the auto increment alarmID, it's much more subtle than using a mysql function / proc.
CREATE TABLE IF NOT EXISTS alarms (
alarmID MEDIUMINT NOT NULL AUTO_INCREMENT,
Title CHAR(30) NOT NULL,
Description TEXT,
DT DATETIME,
PRIMARY KEY (alarmID),
UNIQUE KEY title (Title)
);
Your best bet here would be to make alarmID an auto incrementing primary key and, if Title has to be unique, place a unique constraint on it.
Manually computing the new incremented ID could in fact lead to issues if multiple users use your system, so it is better to leave the job to the DBMS itself.

How to make a primary key to auto increment in a database in php?

I have a database and i am putting data inside. I have one node called key , which is the primary key and other nodes. Now when i put data on my table , i put data in all the nodes except this key node. How do i make it automatically to increase from 0 when i have a new entry? If i run a script to put something in the database , i can see that the nodes have correctly all the data and the key takes the value 0. When i run my script again i get the error :
Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '0' for key 'PRIMARY''
From what i understand , because i dont pass anything to this node , the database "thinks" i am passing again a 0 argument so i have the error. How can i fix it to auto increment every time i have a new entry?
You need to set the field as autoincrement. You would need to run an ALTER TABLE statement like this:
ALTER TABLE table_name
MODIFY `key` MEDIUMINT NOT NULL AUTO_INCREMENT
id MEDIUMINT NOT NULL AUTO_INCREMENT
http://dev.mysql.com/doc/refman/5.0/en/example-auto-increment.html
Start it at 1, not 0.
So the first record is id number 1.
What database are you using?
in postgres you register a number sequence.
In my sql you just use AUTO_INCREMENT when specifying the column attributes
With MySQL, you would declare the table with the AUTO_INCREMENT keyword when defining your table to achieve this behavior
Example:
CREATE TABLE animals (
id MEDIUMINT NOT NULL AUTO_INCREMENT,
name CHAR(30) NOT NULL,
PRIMARY KEY (id)
) ENGINE=MyISAM;
http://dev.mysql.com/doc/refman/5.0/en/example-auto-increment.html
When you INSERT data, you do not specify a value for the primary key. MySQL will automatically use the next available integer value for the key.
UPDATE
You can change this directly within PHP My Admin: go to the table in question and then
Operations->Table Options->Auto-Increment

MYSQL QUERY to retrieve the data

I have the following schema with the following attributes:
USER(TABLE_NAME)
USER_ID|USERNAME|PASSWORD|TOPIC_NAME|FLAG1|FLAG2
I have 2 questions basically:
How can I make an attribute USER_ID as primary key and it should
automatically increment the value each time I insert the value into
the database.It shouldn't be under my control.
How can I retrieve a record from the database, based on the latest
time from which it was updated.( for example if I updated a record
at 2pm and same record at 3pm, if I retrieve now at 4pm I should get
the record that was updated at 3pm i.e. the latest updated one.)
Please help.
I'm assuming that question one is in the context of MYSQL. So, you can use the ALTER TABLE statement to mark a field as PRIMARY KEY, and to mark it AUTOINCREMENT
ALTER TABLE User
ADD PRIMARY KEY (USER_ID);
ALTER TABLE User
MODIFY COLUMN USER_ID INT(4) AUTO_INCREMENT; -- of course, set the type appropriately
For the second question I'm not sure I understand correctly so I'm just going to go ahead and give you some basic information before giving an answer that may confuse you.
When you update the same record multiple times, only the most recent update is persisted. Basically, once you update a record, it's previous values are not kept. So, if you update a record at 2pm, and then update the same record at 3pm - when you query for the record you will automatically receive the most recent values.
Now, if by updating you mean you would insert new values for the same USER_ID multiple times and want to retrieve the most recent, then you would need to use a field in the table to store a timestamp of when each record is created/updated. Then you can query for the most recent value based on the timestamp.
I assume you're talking about Oracle since you tagged it as Oracle. You also tagged the question as MySQL where the approach will be different.
You can make the USER_ID column a primary key
ALTER TABLE <<table_name>>
ADD CONSTRAINT pk_user_id PRIMARY KEY( user_id );
If you want the value to increment automatically, you'd need to create a sequence
CREATE SEQUENCE user_id_seq
START WITH 1
INCREMENT BY 1
CACHE 20;
and then create a trigger on the table that uses the sequence
CREATE OR REPLACE TRIGGER trg_assign_user_id
BEFORE INSERT ON <<table name>>
FOR EACH ROW
BEGIN
:new.user_id := user_id_seq.nextval;
END;
As for your second question, I'm not sure that I understand. If you update a row and then commit that change, all subsequent queries are going to read the updated data (barring exceptionally unlikely cases where you've set a serializable transaction isolation level and you've got transactions that run for multiple hours and you're running the query in that transaction). You don't need to do anything to see the current data.
(Answer based on MySQL; conceptually similar answer if using Oracle, but the SQL will probably be different.)
If USER_ID was not defined as a primary key or automatically incrementing at the time of table creation, then you can use:
ALTER TABLE tablename MODIFY USER_ID INT NOT NULL PRIMARY KEY AUTO_INCREMENT;
To issue queries based on record dates, you have to have a field defined to hold date-related datetypes. The date and time of record modifications would be something you would manage (e.g. add/change) based on the way in which you are accessing the records (some PHP-related way? it's unclear what scripts you have in play, based on your question.) Once you have dates in your records you can ORDER BY the date field in your SELECT query.
Check this out
For your AUTOINCREMENT, Its a question already asked here
For your PRIMARY KEY use this
ALTER TABLE USER ADD PRIMARY KEY (USER_ID)
Can you provide more information. If the value gets updated you definitely do NOT have your old value that you entered at 2pm present in the dB. So querying for it will be fine
You can use something like this:
CREATE TABLE IF NOT EXISTS user (
USER_ID unsigned int(8) NOT NULL AUTO_INCREMENT,
username varchar(25) NOT NULL,
password varchar(25) NOT NULL,
topic_name varchar(100) NOT NULL,
flag1 smallint(1) NOT NULL DEFAULT 0,
flag2 smallint(1) NOT NULL DEFAULT 0,
update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (uid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
For selection use query:
SELECT * from user ORDER BY update_time DESC

Categories