track multiple identical entries - mysql

I got a table that I am allowing identical entries (duplicates, triplecates etc.) but I also got a column that I want everytime that an entry is being made to be updated with the how many times that entry exists.
So I thought to write a trigger, I can already find the duplicate entries by doing
select count(pid) from items group by pid having count(*);
but the thing is that this query returns less columns that the orinal table (cause there are many duplicates)
so there is no 1 to 1 relation between the query and the table so I can use update. How could I modify this to get the desired result
thank you in advanced.

The main problem that you'll face here is that MySQL will not allow you to modify the items table using an AFTER INSERT ... trigger following a modification to the items table itself (think of how this could lead to a circular reference).
One solution is to store the counts in a separate table altogether (say items_pid_info). The primary key of this table would be pid and it is this table that would be updated by the triggers on the main items table. When you need to access the pidCount for a given pid simply join onto this table and you will have up-to-date pid counts for your given pid. Hence:
create table items_pid_info
(pid int unsigned not null primary key,
pidCount int unsigned not null);
Now create INSERT, UPDATE and DELETE triggers on your items table to update the items_pid_info table:
DELIMITER &&
CREATE TRIGGER items_pid_count_ins_trg
AFTER INSERT ON items
FOR EACH ROW BEGIN
DECLARE c int;
set c := (select count(*) from items im where im.pid = NEW.pid);
insert into items_pid_info values (NEW.pid,c) on duplicate key update pidCount = c;
END&&
CREATE TRIGGER items_pid_count_upd_trg
AFTER UPDATE ON items
FOR EACH ROW BEGIN
DECLARE c int;
set c := (select count(*) from items im where im.pid = NEW.pid);
insert into items_pid_info values (NEW.pid,c) on duplicate key update pidCount = c;
END&&
CREATE TRIGGER items_pid_count_del_trg
AFTER DELETE ON items
FOR EACH ROW BEGIN
DECLARE c int;
set c := (select count(*) from items im where im.pid = OLD.pid);
insert into items_pid_info values (OLD.pid,c) on duplicate key update pidCount = c;
END&&
DELIMITER ;
Hope this helps.

Related

Insert a record and also update existing records

hi there i was trying to right a Proc for a DataLoad when you want to insert records on a Table1 based on Table2
This is what i came of with
it has 2 condition
1) if the record does not exist create a new row of record
2) if the record already exist update the record based on keys
this is my proc need some help thanks
DECLARE #TableKey INT --(it is passed by the user proc param),
DECLARE #TableCount INT,
DECLARE #CLassKey INT,
SELECT #TableCount= COUNT(*) FROM Table1 WHERE Tablekey= #TableKey
INSERT INTO #CLassKey
SELECT Distinct c.PK_ClassKey FROM CLASS as c
INNER JOIN BOOK as B ON B.FK_ClassKey=C.PK_ClassKEy
IF ((SELECT COUNT(*) FROM #ClassKey) > 0 AND #TableCount= 0)--- this will check
BEGIN
Insert into NOTE
n.note
Select
c.note
FROM Class where c.FK_Note = n.PK_Note.
END
---- this will just insert for the first time..
How do i update it any idea as the records are only inserted for the first time put does not update using the same format thanks a lot
try this one
INSERT INTO table_name (id,col2,col3)
VALUES (value_id,value2,value3)
ON DUPLICATE KEY UPDATE
col2=value2,
col3=value3;

Script/workflow insert not exist and auto increment

I create a script/workflow exportation/importation from 2 system.
I have Table1 {id, name, description}
I want to create a script (not a procedure). I could (I didnt succed) adding procedure into my workflow. (create and delete at the end)
id is auto increment
I cant change the table
I can be sure that between the time I start execution of my script and the end, there will not be an insertion of one of my items into the database.
The script insert {name,description} but I want to NOT insert if the element (name or name and description) is there.
BASE QUERY :
INSERT INTO TABLE1 (name,description) VALUES ('itemX','this is item X')
BASE Script :
Use database1;
BEGIN;
SELECT * FROM TABLE1 ;
SELECT * FROM TABLE3 ;
INSERT INTO TABLE1 (name,description) VALUES ('itemX','this is item X');
set #idTable1 = LAST_INSERT_ID();
INSERT INTO TABLE3 (idTable1,idTable2) VALUES (#idTable1,1);
INSERT INTO TABLE3 (idTable1,idTable2) VALUES (#idTable1,2);
SELECT * FROM TABLE1 ;
SELECT * FROM TABLE3 ;
ROLLBACK;
I want to protect the multiple insertion on TABLE1. But without changing the table.
Maybe I did it wrong
I tried IF but not working outside procedure.
I tried IGNORE (valid only if id is the same, but never the same, its
auto increment)
I tried WHEN
I tried ON DUPLICATE KEY
Because of #idTable1, I will need change the " set #idTable1 = LAST_INSERT_ID();" if I doesnt have if else. But if my item is the only one with the same "name", I can get this instead of last_insert_id.
I opted for creating procedure before my "BEGIN" and removed them at the end of the script.
Just create the table with name as primary key, then be sure that you take care of the key capitalization (uppercase or lowercase) to avoid duplicates.
CREATE TABLE TABLE1(
id INT AUTO_INCREMENT,
name CHAR(30),
description CHAR(100),
PRIMARY KEY (name)
)
create unique constraint on name field if possible.
Otherwise, create trigger before insert in order to ignore duplicate insertion.
Trigger for checking duplicate on two fields a and b:
delimiter //
drop trigger if exists aborting_trigger //
create trigger aborting_trigger before insert on t
for each row
begin
set #found := false;
select true into #found from t where a=new.a and b=new.b;
if #found then
signal sqlstate '45000' set message_text = 'duplicate insert';
end if;
end //
delimiter ;
The trigger here provides feature similar to unique constraint. After creation you should use INSERT IGNORE or INSERT ...ON DUPLICATE KEY UPDATE

MYSQL How to create a UNIQUE constraint on two columns any combinations (in both directions)

If I have mySQL table with two row, how can I make make a constraint that same value can't be on both cols to the same time and prevent creating doubles of any combinations of both columns?
For example, if I insert the following :
col1 col2
a b ok
c a ok
c b ok
c a not ok sure it's already in the table
a c not ok because it's already in the table in other combination (c a)
f f not ok because same value in both columns
Long time ago, I found this on net.
Lets say, you have table, named tableName then you have to create a primary key which includes both column.
create table tableName
(
col1 int not null,
col2 int not null,
primary key (col1,col2)
);
But creating primary key does not solve your problem for checking vice versa combination. For that, you have to create a trigger which check uniqueness for both side.
DELIMITER $$
CREATE TRIGGER tableName_bi BEFORE INSERT ON tableName FOR EACH ROW
BEGIN
DECLARE found_count,newcol1,newcol2,dummy INT;
SET newcol1 = NEW.col1;
SET newcol2 = NEW.col2;
SELECT COUNT(1) INTO found_count FROM tableName
WHERE col1 = newcol2 AND col2 = newcol1;
IF found_count = 1 THEN
SELECT 1 INTO dummy FROM information_schema.tables;
END IF;
END; $$
DELIMITER ;
Note : Change your table and column name according to yours.

SQL Trigger: New row :tableA to new col in :tableB

I have a database with a couple of tables. I need to add a column in one table after the insertion of a new row in another table.
Table A: id | Type | Category | ShortDesc | LongDesc | Active
Row 1 int(11), varchar, varchar,varchar,varchar,int
Row 2
Row 3
Table B: id | Row1-ShortDesc | Row2-ShortDesc | Row3-ShortDesc
Row 1 int(11), tiny(1), tiny(1), tiny(1) etc...
Row 2
Row 3
When I occasionally add a new row (item) to TableA, I want a new column in TableB. TableA is a long evolving collection. A Row in TableA can not be removed for obvious legacy reasons.
So when I insert a row to TableA I need to have another column inserted/appended into TableB.
Any help would be appreciated.
TIA.
Answer derived from training in SQL
I was finally able to derive and create my trigger solution utilizing a class in SQL Server at MAX TRAINING in CINCINNATI OHIO.
--SQL CODE
-- Create a table called TableA that just holds some data for the trigger
-- This table has a primary Key seeded with 1 and incremented by 1
CREATE TABLE TableA(
id int identity(1,1) PRIMARY KEY,
name varchar(60) NOT NULL,
shortDesc varchar(60) NOT NULL,
longDesc varchar(60) NOT NULL,
bigDesc TEXT NOT NULL
)
GO
-- Create a table TableB that only has a ID column. ID as a primary key seeded with 1, incremented by 1
CREATE TABLE TableB(
id int identity(1,1) PRIMARY KEY
)
GO
-- Just to see the two tables with nothing in it.
select * from TableA
select * from TableB
GO
-- The actual trigger in TableA based upon an insert
CREATE TRIGGER TR_myInserCol
ON TableA
AFTER INSERT
AS
BEGIN
-- Don't count the trigger events
SET NOCOUNT ON;
-- Because we are making strings we declare some variables
DECLARE #newcol as varchar(60);
DECLARE #lastRow as int;
DECLARE #sql as varchar(MAX);
-- Now fill the variables
-- make sure we are looking at the last, freshly inserted row
SET #lastRow = (SELECT COUNT(*) FROM TableA);
-- Make a SELECT statement for the last row
SET #newcol = (SELECT shortDesc FROM TableA WHERE id = #lastRow);
-- Adds a new column in TableB is inserted based on a
-- TableA.shortDesc as the name of the new column.
-- You can use any row data you want but spaces and
-- special characters will require quotes around the field.
SET #sql = ('ALTER TABLE TableB ADD ' + #newcol + ' char(99)');
-- And run the SQL statement as a combined string
exec(#sql);
END;
GO
--Insert a new rows into TableA
--The trigger will fire and add a column in TableB
INSERT INTO TableA
(name,shortDesc,longDesc,bigDesc)
VALUES ('attract','Attraction','Attractions','Places to go see and have
fun');
GO
INSERT INTO TableA
(name,shortDesc,longDesc,bigDesc)
VALUES ('camp','Camp','CAMP GROUND','Great place to sleep next to a creek');
GO
(name,shortDesc,longDesc,bigDesc)
VALUES ('fuel','GasStation','Fueling Depot','Get gas and go');
GO
INSERT INTO TableA
(name,shortDesc,longDesc,bigDesc)
VALUES ('petstore','PetStore','Pet Store','Get a friend');
GO
-- See the newly created rows in TableA and the new Columns created in TableB
select * from TableA
select * from TableB
GO
-- Do not execute unless you want to delete the newly created tables.
-- Use this to delete your tables
-- Clean up your work space so you can make changes and try again.
DROP TABLE TableA;
DROP TABLE TableB;
GO
Thanks again to those that tried to help me out. And yes, I still understand this may not be the best solution but for me this works as I will only insert rows in TableA maybe a couple of times a year and will more than likely max out with less than 300 rows over the next several years as the data I am working with doesn't change that frequently and have a single row to access with a single bit (T/F) allows me to now quickly assign TableB's to locations and people for their search criteria and to generate a nice SQL query string without multiple reads across potentially several pages. Thanks again!
And if someone wants to add or modify what I have done, I'm all ears. It's all about learning and sharing.
Michael

remove gaps in auto increment

Say I have a MySQL table with an auto incrementing id field, then I insert 3 rows. Then, I delete the second row. Now the id's of the table go 1,3. Can I get MySQL to correct that and make it 1,2 without having to write a program to do so?
MySQL won't let you change the indexing of an Auto-Index column once it's created. What I do is delete the Auto-Index column and then add a new one with the same name, mysql will index the newly generated column with no gaps. Only do this on tables where the Auto-Index is not relevant to the rest of the data but merely used as a reference for updates and deletes.
For example I recently did just that for a table containing proverbs where the Auto-Index column was only used when I updated or deleted a proverb but I needed the Auto-Index to be sequential as the proverbs are pulled out via a random number between 1 and the count of the proverbs, having gaps in the sequence could have led to the random number pointing to a non-existant index.
HTH
Quoting from The Access Ten Commandments (and it can be extensible to other RDBMS: "Thou shalt not use Autonumber (or Auto Incremental) if the field is meant to have meaning for thy users".
The only alternative I can think of (using only MySQL) is to:
Create a trigger that adds the row number to a column (not the primary key)
Create a procedure to delete rows and update the row number (I couldn't make this work with triggers, sorry)
Example:
create table tbl_dummy(
id int unsigned not null auto_increment primary key,
row_number int unsigned not null default 0,
some_value varchar(100)
);
delimiter $$
-- This trigger will add the correct row number for each record inserted
-- to the table, regardless of the value of the primary key
create trigger add_row_number before insert on tbl_dummy
for each row
begin
declare n int unsigned default 0;
set n = (select count(*) from tbl_dummy);
set NEW.row_number = n+1;
end $$
-- This procedure will update the row numbers for the records stored
-- after the id of the soon-to-be-deleted record, and then deletes it.
create procedure delete_row_from_dummy(row_id int unsigned)
begin
if (select exists (select * from tbl_dummy where id = row_id)) then
update tbl_dummy set row_number = row_number - 1 where id > row_id;
delete from tbl_dummy where id = row_id;
end if;
end $$
delimiter ;
Notice that you'll be forced to delete the records one by one, and you'll be forced to get the correct primary key value of the record you want to delete.
Hope this helps