Is it possible to make a script without else/if that deletes the oldest row for a user if the new row is the 4 row for that specific user?
I have a table called points_history. Fields are:
date(datetime),
fk_player_id(int),
points(int)
Here is my insert:
mysqli_query($mysqli,"INSERT INTO points_history (date,fk_player_id,points) VALUES (NOW(),$player,$points)");
The reason for this taht I want to be able to go back in the players history and check points, but only the last 3 points and don't want a table with a million of rows.
Can it be done in one sql query?
Hoping for help and thanks in advance :-)
This is quite easy to do if you add a primary key to your table points_history.
Part 1:
Use the following script to add a primary key called points_history_id to your table:
ALTER TABLE points_history RENAME TO points_history_old;
CREATE TABLE points_history
(
`points_history_id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`date` datetime NOT NULL,
`fk_player_id` int(11) NOT NULL,
`points` int(11) NOT NULL,
PRIMARY KEY (`points_history_id`)
);
INSERT INTO points_history (date, fk_player_id, points)
SELECT date, fk_player_id, points
FROM points_history_old;
-- Drop table if migration succeeded (up to you)
-- DROP TABLE points_history_old;
This needs to be run only once!
Part 2:
Now you can use the following SQL script to add a new record and delete the outdated:
-- First insert the new record
INSERT INTO points_history (date,fk_player_id,points)
VALUES (NOW(),:player,:points);
-- Create temporary table with records to keep
CREATE TEMPORARY TABLE to_keep AS
(
SELECT points_history_id
FROM points_history
WHERE fk_player_id = :player
ORDER BY date DESC
LIMIT 3
);
SET SQL_SAFE_UPDATES = 0;
-- Delete all records not in table to_keep
DELETE FROM points_history
WHERE points_history_id NOT IN (SELECT points_history_id FROM to_keep);
SET SQL_SAFE_UPDATES = 1;
-- Drop temporary table
DROP TEMPORARY TABLE to_keep;
If you use a database supporting transactions, I strongly recommend to wrap this script in a transaction. I tested it on MySQL 5.5.29 and it runs fine.
Related
I am trying to find a method for inserting the last primary key from Table1 as a foreign key into Table2.
So far, I have tried SELECT max(‘id‘) FROM table1 as foreign_key blablablablablabla
It works if one user registers at that current time; however, if 5 users register at the same time, the foreign key is wrong.
Multiple ways you can do this.
Creating a trigger
You can create a trigger after insert of table1 into table2. For example;
CREATE TRIGGER `add to other table` AFTER INSERT ON `table1`
FOR EACH ROW INSERT INTO table2 SET user_id=NEW.id, name=NEW.username;
Using PHP
You can do this using mysqli::insert_id, for example; (You would bind and sanitize input, but for the sake of illustration, I won't)
$mysql->query("INSERT INTO `table1` SET `username`='pokrenz'");
$intForeignKey = $mysql->insert_id;
$mysql->query("INSERT INTO `table2` SET `id` = ". $intForeignKey);
Hi i know this question has been asked before but i'm asking it differently, what i want is to reset the auto_increment column, after deleting a row in a table. if i have table with 51 rows and i delete row 48, i want row 49 to reset to 48,50 to 49 etc.
i have tried using alter table but that insert data where the row was deleted, i want something that will shift the order.
-- Table structure for table torrents
CREATE TABLE IF NOT EXISTS `torrents` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`Title` varchar(250) NOT NULL,
`Kat_Link` varchar(250) NOT NULL,
`Tpb_Link` varchar(250) NOT NULL,
`Lime_Link` varchar(250) NOT NULL,
`ImgUrl` varchar(250) NOT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB;
what i want is to run a select from table where ID = $id lmit 8 if the ID doesn't exists i get less than 8 rows.
It's going to be difficult to achieve that just use limit with your select statement, what you want is to get number of rows(e.g 8 rows) by ID, if that ID doesn't exists, your select statement is going to give you less rows than you want.
SELECT * FROM table LIMIT $r,$s // here you are guaranteed that you'll get 8 rows all the time
If you insist on filling the gap, there's a way around to shift the later records on the table you provided.
SQL = "UPDATE torrents SET ID=ID-1 WHERE ID > 48";
To alter the table in order to reset the AI,
ALTER TABLE `torrents ` AUTO_INCREMENT =51
Try a trigger, I haven't touched a MySQL database in a long time, so the syntax below might be incorrect, but it presents the idea of what it's trying to achieve well enough.
CREATE OR REPLACE updateTableTrigger
AFTER delete on 'torrents'
FOR EACH ROW
BEGIN
SET #id = old.ID
UPDATE torrents SET ID = (#id-1) WHERE ID > #id;
END
Essentially it just deducts the row's ID by one after the deleted row.
So if you delete row with an ID of 5 it'll affect all rows after row of ID 5 and decrement their values by 1 to fill in the gap.
I have this SQL code which inserts into a database named daily. I regularly update the daily database like this:
INSERT INTO daily
(SELECT * FROM dailytemp
WHERE trim(`Point`) <>''
AND trim(`Point`) IN (Select trim(`Point`) FROM `data`));
I believe I am getting the error because both tables have id primary columns.
I want the data inserted, but a new id generated for any duplicate found.
I tried to list the columns names, but it's about 20 columns, which might make the process cumbersome.
What is my best option?
Edit
The table defination of daily and daily_temp are the same, all the folumns are varchar(100) with and id of (bigint)
id bigint
col1 varchar(100)
col2 varchar(100)
col3 varchar(100)
etc..
A possible solution might be to use a BEFORE INSERT trigger and a separate table for sequencing (if you don't mind).
Sequence table
CREATE TABLE daily_seq(id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY);
Now the trigger
DELIMITER $$
CREATE TRIGGER tg_daily_insert
BEFORE INSERT ON daily
FOR EACH ROW
BEGIN
INSERT INTO daily_seq VALUES(NULL);
SET NEW.id = LAST_INSERT_ID();
END$$
DELIMITER ;
Now you can insert whatever you want to daily, id value will replaced with unique auto incremented one.
Here is SQLFiddle demo
Indeed, you are certainly trying to insert a row with an id that already exists in daily.
If this does not pose any referential integrity issue, you could regenerate the id's in dailytemp so that they do not overlap with any one in daily. This might do the trick:
SET #offset = (SELECT MAX(id) FROM daily) - (SELECT MIN(id) FROM dalytemp) +1;
UPDATE dailytemp SET id = id + #offset;
Then try your INSERT.
If rows can be inserted into daily by another process than the one you described, or if for any reason a id is skipped in this table (eg. if the column is AUTO_INCREMENT), then the problem will reoccur. You may want to include this preliminary UPDATE in your daily procedure.
i decided to use a stored proceedure to perform the action, listing all colums name instead of this headache
thanks to all those who helped. Another reason i did that was that i needed to insert a date for the daily table for each set of data inserted, so i created a date column for the dail table only
INSERT INTO daily (col1, col2, etc..., created)
SELECT col1, col2, etc..., 'mydate' from daily_temp WHERE
trim(`Point`) <>'' AND trim(`Point`) IN
(Select trim(`Point`) FROM `data`));
thanks all
I thought i was in the right track. I forgot that a user can do multiple activities. What I did was it's only one activity. What can i do with this? I came up with a solution that might work, come up with an sql statement that updates the activity column without overwriting the text. But that seems stupid. Pretty sure theres a better solution?
I made some adjustment but I think this will improve your database. See this in action via http://sqlfiddle.com/#!2/c6546/9/0
CREATE TABLE workers
(
id_workers int primary key,
username varchar(30),
type varchar(30)
);
CREATE TABLE activities
(
id_activities int auto_increment primary key,
activity varchar(30)
);
CREATE TABLE timesheet
(
id_timesheet int auto_increment primary key,
id_workers int,
id_activities int,
start_time datetime,
end_time datetime
);
INSERT INTO workers
(id_workers, username, type)
VALUES
('1','Danice', 'Administrator'),
('2','Micheal', 'Administrator');
INSERT INTO activities
(activity)
VALUES
('Edit Employee'),
('Edit Employee Information'),
('Edit Department');
INSERT INTO timesheet
(id_workers, id_activities,start_time, end_time)
VALUES
('1', '1', '2013-03-14 13:15:00','2013-03-14 13:20:00'),
('2', '2', '2013-03-14 13:00:00','2013-03-14 14:00:00'),
('1', '2', '2013-03-14 13:21:00','2013-03-14 13:23:00'),
('1', '3', '2013-03-14 13:24:00','2013-03-14 13:45:00');
SELECT a.id_activities, w.username, w.type, a.activity, t.start_time, t.end_time
FROM (timesheet AS t LEFT JOIN activities AS a ON t.id_activities = a.id_activities ) LEFT JOIN workers AS w ON t.id_workers = w.id_workers;
BTW you could use MYSQL workbench if you want to get a good overview from you database layout. Set up a schema inside workbench for reference when coding. Or just use pen and paper. ;-)
With regard to you audit trail, you could give workers the option to delete there activity from the timesheet by adding and extra column (e.g. audittrail) to timesheet. By default the column audittrail is set to 0 and if an worker deletes his entry you give this column the value 1. Then add to you SELECT query "WHERE audittrail = 0" to display all the timesheet entries. And in the case you require an audit trail you leave out the WHERE clause.
http://www.c-sharpcorner.com/uploadfile/nipuntomar/normalization-and-its-types/
What you're trying to do is called database normalization. You want meta data against one particular record. So just 'glancing' at your problem. Make a table for storage, X, and a have a foreign key constraint to the data record you want to describe. In this case, it looks like the users table, and then have fields in this X table which stores the 'multiple data' type which is related to users table.
Tables
users -- table
id
username
password
status
updation_date
creation_date
x -- table
id
users_id -- foreign key constraint
part1_of_multiple_data -- meta log data you are wanting
part2_of_multiple_data -- meta log data you are wanting
part3_of_multiple_data -- add more fields as you need in the table.
updation_date
creation_date
I have two MySQL database tables that are meant to hold data for eshop orders. They're built as such (extremely simplified version):
CREATE TABLE `orders` (
`id` int(11) NOT NULL auto_increment
PRIMARY KEY (`id`)
);
CREATE TABLE `order_items` (
`id` int(11) NOT NULL auto_increment,
`orderID` int(11) NOT NULL,
PRIMARY KEY (`id`)
)
The relationship between the two is that orders.id corresponds to order_items.orderID.
I'm using a transaction to place a new order, however have a problem preserving the above relationship. In order to get the new order id. I have to commit the orders INSERT query, get the autoincremented id and then start another transaction for the order items. Which pretty much defeats the point of using transactions.
I could insert the new order in the orders table and then try something like
INSERT INTO order_items(orderID) VALUES(LAST_INSERT_ID())
which I assume would work. However after the first order item is inserted LAST_INSERT_ID() would stop returning the order id and instead return the order item id making it impossible to use this query to insert another order item.
Is there a way to make this whole thing work within a single transaction or should I give up and use a procedure instead?
WOuld this work?:
INSER QUERY;
SET #insertid = LAST_INSERT_ID();
INSERT INTO `order_items` SET `OrderID` = #insertid;
All in one statement. You will have to double check the syntax
You can't count on LAST_INSERT_ID() because it also changes when you insert values to order_items because it inserts its id which is also auto_imcrement.
Maybe you can try this.
INSERT INTO order_items(orderID) VALUES((SELECT id FROM orders ORDER BY id desc LIMIT 1))