mysql insert and update table with max 3 - php

I have a php script that logs inputs from a form into a mysql database table. I'm looking for a way to insert this data untill 3 rows are created, after which it has to update the existing rows so that the first one updates to the new input, the second one to the former first input and the third one to the former second input.
Table:
CREATE TABLE IF NOT EXISTS inputlog (
id int(11) NOT NULL auto_increment,
userid int(11) NOT NULL default '0',
name text,
value text,
PRIMARY KEY (id)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;`
For the first three rows i use:
insert into inputlog (userid,name,value) values('$userid','$name','$value')
After that is has to become:
update inputlog set value = '$value' where userid = '$userid' and name = '$name'
where it has to update all the successive rows.
How can i accomplish this?

Too long for comments, so...
Looks like you want to have only 3 rows in your table because you want the data to be sorted by the id. So id=1 will be the latest value, then id=2 and finally id=3.
In short, do not do that, the id field can be any value. Do not code for that. The danger is if you use the id in another table as a foreign key, you will loose referential integrity. What I propose is:
Add an timestamp column for each row.
Every time you insert a new value, set the timestamp column to NOW()
When selecting, sort on the timestamp and limit to 3 results
If you MUST have only 3 rows, you can then delete the row except for the 3 most recent timestamps.
But... if you must do that...
perform a SELECT with the first 2 lines
truncate the table (delete all rows)
insert the new line, then the 2 stored lines
You will then ahve your 3 rows in the order you want. But without seeing the entire reasoning for your application, my "spider sense" tells me you will hit a wall later on...
And check the comments for other things to worry about.

Related

Insert Into on Duplicate Update creates me an unwanted row

I have a SQL query as follows-
"INSERT INTO users(id, rank) SELECT v.user, v.vote FROM votes v WHERE
v.assertion = '$ID' ON DUPLICATE KEY UPDATE
rank = ( CASE WHEN v.vote = '1' THEN rank+50 WHEN v.vote = '-1'
THEN rank-200 WHEN v.vote = '3' THEN rank+100 ELSE rank END)"
applied on a database with a table users with and id and rank field, and a votes table with a user and vote field. I have to update the rank of the users in the users table based on their vote.
I really like this kind of query, but I've noticed a problem: every time I execute this from my PHP script the query adds a row to the users table completely empty (with only an ID, which is A_I, and a rank of 1, when usually there would be other field as well). I can't really wrap my head around why this happens.
Any help/idea?
Your table does not have a primary key first provide a primary key to id
run this sql query
alter table user add primary key (id)
and than try it will work
There are two possible reasons :
The id column is not the primary key, and probably you table doesn't have a primary key at all.
Create a primary key like this :
alter table user add primary key (id)
If you insert an value of 0 in an auto increment column, a new id is generated. An auto incremented column must not contain the value 0.
There is also a more general problem with your approach : in fact you only insert the user id and the rank, other compulsory fields in the table (username) are missing. The insert part does not seem to be valid for this reason. If you use an insert on duplicate key update, you must make sure that the result is correct which ever of insert and update is executed.

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

Unique Identifier Mixed Format with Date Prefix (Php / MySQL)

I am creating a ticketing system that will keep track of tickets that a customer creates. The ticket's basic information will be stored in a table 'tickets' who's structure is as follows:
Primary Key (int 255)
Ticket_Key (varchar)
Ticket Number (varchar 500)
Label
Date Created
Delete
and so on..
The issue is that there will eventually be a large amount of tickets and we need a more uniform way of identifying tickets. I would like PHP to create a Ticket Number in the ticket number that will contain mixed values. The date (in format 20111107), followed by a auto incremented value 1001. 1002, 1003, ...). So the Ticket Number will be 201111071001 for an example.
The issue is how do I program this in PHP to insert to the MySQL database? Also, how do I prevent the possibility of duplicate values in the Unique Id in PHP? There will be a very large amount of customers using the table to insert records.
What about using an auto-increment and combining this with the date field to generate a sequence number for that date and hence a ticketId.
So your insert process would be something like this:
INSERT INTO table (...ticket info...)
You would then retrieve the auto-increment for this row and run a query like this
UPDATE table SET sequence = (SELECT ($id-MAX(auto_increment)) FROM table WHERE date_created=DATE_SUB(CURDATE(),INTERVAL 1 DAY)) WHERE auto_increment=$id
You could then easily create a ticketId of format YYYMMDDXXXX. Assuming you never retro-add tickets in the past this would only ever require these two queries even under heavy usage.
[EDIT] Actually, after looking into this there is a much better way to do this natively in MySQL. If you define two columns (date and sequence) and make them a primary key (both columns) with the sequence field as an auto-increment then MySQL will update the sequence column as an auto-increment per date (i.e. it will start with value 1 for each date).
[EDIT] A table structure along these lines would do the job for you:
CREATE TABLE IF NOT EXISTS `table` (
`created_date` date NOT NULL,
`ticket_sequence` int(11) NOT NULL auto_increment,
`label` varchar(100) NOT NULL,
[other fields as required]
PRIMARY KEY (`created_date`,`ticket_sequence`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
When retrieving the data you could then do something like
SELECT CONCAT( DATE_FORMAT(created_date,'%Y%m%d'),LPAD(ticket_sequence,4,'0')) AS ticket_number, other fields.... FROM table
as i understand that you want to make one result of two different fields like datefield and ticketnumfield
in mysql you do this through the command:
SELECT concat( datefield, ticketnumfeild ) FROM `tbl_name`
this query return the result like 201111071001
I did something like this before where I wanted to refresh the counter for each new day. Unfortunately I do not speak PHP so you will have to settle for explanation and maybe some pseudo code.
Firstly, create a couple of fields in a config file to keep track of your counter. This should be a date field and a number fields...
LastCount (Number)
LastCountDate (Date)
Then you make sure that your ticket number field in your database table is set to only unique values, so it throws an error if you try to insert a duplicate.
Then in your code, you load your counter values (LastCount and LastCountDate) and you process them like so...
newCount = LastCount;
if LastCountDate == Today
increment newCount (newCount++)
else
reset newCount (newCount = 1)
you can then use newCount to create your ticket number.
Next, when you try to insert a row, if it is successful, then great. If it fails, then you need to increment newCount again, then try the insert again. Repeat this until the insert is successful (put it in a loop)
Once you have successfully inserted the row, you need to update the database with the Count Values you just used to generate the ticket number - so they are ready for use the next time.
Hope that helps in some way.

Mysql reset auto_increment not for new ids but for all (also old ids)

Hi all is there any SQL function to reset all auto_increment ids?
I mean , i have this situation (id =1 , id2 = 2, id3 =3)
once i delete id i would like to be returned this situation (id2 = 1, id3 = 2) and so on.
Need i a script to do that?
You can reset the AUTO_INCREMENT for the whole table:
ALTER TABLE table AUTO_INCREMENT=1;
But you cannot really go back to fill in values in individual rows that have been deleted. The auto_increment values are intended to be unique, but aren't guaranteed to remain sequential if deletions happen or new rows are inserted with an explicit value set for the auto_increment column.
If you needed to modify them to be sequential again, it would have to be done in code, probably looping over all rows and performing UPDATE statements individually.
Id is Id which means it must never change! At least in good database design. Id is something you are born with and you die with.

Insert all rows from one table to another + time stamp at the end

I'm creating a change log db that's the exact same as my active db except it has a changedate DATE field at the end.
The db is basically one primary key id, and about 50 other columns of various data types. The script I have in php is it tries to insert new ids and if it gets the error message for duplicate primary key, then it should get that row, insert it into my backup db with a curdate() call as the final date value, delete the entry from my first db, then insert the new entry.
I have all the other parts of the script finished except the part where I have to insert everything from the first table + an extra column for curdate(). Or if there's a better solution to my problem of inserting into a backup database when a duplicate primary key comes in when there's a fairly high amount of rows please share that.
You could do an INSERT INTO SELECT:
INSERT INTO `backupTable` SELECT *, NOW() FROM `originalTable` WHERE id = '$id';
You have to specify the ID for the entry you wish to copy to your backup db. You have also to be sure, that the IDis not already in your backup table. You can use REPLACE INTO to workaround this case.
REPLACE INTO `backupTable` SELECT *, NOW() FROM `originalTable` WHERE id = '$id';
basicly, you can create a TIMESTAMP column with CURRENT_TIMESTAMP as default value.
when you insert a row to that table, the current date/time will be automaticly inserted.
is that what you were looking for ?
BTW: i would recommend to kill the problem at it source and make sure a duplicate primary key will not be inserted to the datatable..
to do that, you can use the SELECT LAST_INSERT_ID();

Categories