Getting the affected rows when altering a table in mysql - mysql

I need to retrieve a report of the affected rows when a table has been altered with the following commands:
1.- Changing the engine:
ALTER TABLE <table> ENGINE=INNODB;
2.- Adding constraints:
ALTER TABLE nombre_tabla ADD PRIMARY KEY símbolo_clave_foránea;
ALTER TABLE nombre_tabla DROP PRIMARY KEY símbolo_clave_foránea;
ALTER TABLE nombre_tabla ADD FOREIGN KEY símbolo_clave_foránea;
ALTER TABLE nombre_tabla DROP FOREIGN KEY símbolo_clave_foránea;
3.- Adding a UNIQUE constraint.

Primary or Unique Key failure is look for duplicates, if you have nulls in there you'll need to sort them first.
E.g given MyTable(KeyField int not null) then
Select KeyField From MyTable
inner join (Select KeyField,Count() as NumberOfTimes Group By KeyField) Duplicates
Where NumberOfTimes > 1
Then you'll have to come up with something to do with them. Delete or rekey.
Foreign Keys just a outer join query with where key is null
e.g Given MyTable (KeyField int not null, ForeignKeyField int not null) and
MyLookUpTable(LookUpkey int not null, Description VarChar(32) not null) then
Select KeyField From MyTable
Left Join MyLookUpTable On MyTable.LookUpField = MyLookUpTable.LookUpKey
Where MyTable.LookUpField Is Null
Again you'll have to decide what to do with them. You could delete them, but this might help.
One way is to insert a "Missing" Record in the look Up Table, grab it's key, then do an update with join. So given that key is 999
Update m
Set LookUpField = 999
From MyTable m
Left Join MyLookUpTable On m.LookUpField = MyLookUpTable.LookUpKey
Where m.LookUpField Is Null
Now you can dig out 999s and deal with them at your leisure.

Related

Unique Column in mysql database

I m facing a probem and i don't believe that it can accept a solution so I hope if anyone knows a solution suggest it, please.
I have a column in my table that contains a certain records; some of those records are duplicated and I want to insert some new records into my table, but I wish for the new records to not be duplicated. So, basically I want to control when the data can be duplicated and when not.
I ve tried this but it does not work:
ALTER TABLE MyTable DROP PRIMARY KEY
ALTER TABLE MyTable
ADD PRIMARY KEY (`S.No`),
ADD UNIQUE KEY `PCID_uk` (`PCID`),
ADD UNIQUE KEY `USERNAME_uk` (`USERNAME`)
some of those records are duplicated and I want to insert some new records into my table, but I wish for the new records to not be duplicated
Constraints are meant to guarantee integrity over the whole table, so what you ask for is not not straight forward, but still possible.
The idea is to create a new column with a default value of 1, and then feed it using row_number() (available in MySQL 8.0). Assuming that the primary key of your table is id, and that you want to enforce partial uniqueness on column col, that would look like:
alter table mytable add col_rn int default 1;
update mytable t
inner join (
select id, row_number() over(partition by col order by id) rn
from mytable
) t1 on t1.id = t.id
set t.col_rn = t.rn;
With this set up at hand, you can create the following unique constraint
alter table mytable add constraint unique_col_rn unique (col, col_rn);
Now you can insert new records in your table, not providing values for col_rn, so it defaults to 1. If a record already exists for col, the unique constraint raises an error.
insert into mytable (col) values (...);

Set foreign key values based on existing column data

I am in the middle of migrating an old (unnormalized) database to its new version.
Right now I have this intermediate result:
CREATE TABLE recipient(
id int NOT NULL AUTO_INCREMENT,
email VARCHAR(255),
PRIMARY KEY (id),
UNIQUE INDEX (`email`),
) ENGINE=INNODB;
CREATE TABLE comment(
# Right now this is always NULL:
fk_recipient INT,
# Temporary solution. Note that this field is NOT UNIQUE:
tmp_email VARCHAR(255) NOT NULL,
# ...
FOREIGN KEY (`fk_recipient`) REFERENCES recipient(id);
) ENGINE=INNODB;
Both tables are filled with correct data:
some million comments with the right tmp_email and fk_recipient = null in table comment (note: emails are not unique)
some hundred thousand UNIQUE email adresses in table recipient.
What I need to do:
I want to get rid of the comment.tmp_email column and instead point comment.fk_recipient to the appropriate row in table recipient.
My current approach (using PHP):
get all comments
iterate over all comments:
look up the right row in recipient table
set right foreign key
... DROP COLUMN tmp_email
This takes forever and made me wonder if there is no native MySQL way to do that?
The following workaround will do the job:
Create temporary foreign key on comment.tmp_email:
ALTER TABLE comment
ADD CONSTRAINT `tmpMailKey` FOREIGN KEY (`tmp_email`)
REFERENCES `recipient`(`email`);
Join the two tables on the temporary key and use the information to set the real foreign key:
UPDATE comment c
INNER JOIN recipient r
ON
c.tmp_email = r.email
AND c.tmp_email IS NOT NULL
SET c.fk_recipient = r.id;
Get rid of temporary foreign key (and the tmp column too):
ALTER TABLE `udw_v3`.`travelogue_guestbookentry`
DROP COLUMN `tmp_email`,
DROP INDEX `tmpMailKey`,
DROP FOREIGN KEY `tmpMailKey`;

How to count amount of rows referring to a foreign key in MySql?

Let's say a table like
CREATE TABLE `testdb`.`test` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
there are other tables may have foreign key referring to test.id column. The interesting thing is I don't know what table has such a foreign key and how many rows the table has.
now I want to calculate amount of rows dispersing in tables that have foreign key to test.id. Is it possible?
I think it's theoretically possible, otherwise MySql cannot do operations like ON DELETE CASCADE, DELETE SET NULL ...
Displays all referenced tables with row counts
SELECT rc.table_name, t.TABLE_ROWS
FROM `REFERENTIAL_CONSTRAINTS` rc
INNER JOIN `TABLES` t ON t.TABLE_NAME = rc.TABLE_NAME
WHERE rc.REFERENCED_TABLE_NAME = "test"
Displays sum of all referenced tables row count
SELECT SUM(t.TABLE_ROWS) AS allReferencedTablesRowCount
FROM `REFERENTIAL_CONSTRAINTS` rc
INNER JOIN `TABLES` t ON t.TABLE_NAME = rc.TABLE_NAME
WHERE rc.REFERENCED_TABLE_NAME = "test"
if you have foreign-key-constraints defined you can read them from the database schema to see which columns in which tables are linked to your primary key.
edit: check this (on the left side select "Database metadata" -> "Find child tables")

Why don't I get any output from my relation table?

I have created 'students' table where 'sid' is the primary key and I have inserted many values into sid. I have created a second table called 'courses' and it has a primary key 'cid' I have entered values for cid as well. Now, I want to create a relation table called 'enroll' which I have done like-
create table enroll(
grade char(2),
sid int not null,
cid int not null,
primary key(sid,cid),
foreign key (cid) references courses(cid) on delete cascade,
foreign key (sid) references students(sid) on delete cascade
);
Now, when I try to view the table using select * from enroll;
I don't get any output. It says "0 rows returned". Why is this? Isn't it supposed to have all the values of sid and cid from the other tables?
In Order to create a new table from values in your other table you can do something like this:
CREATE TABLE new_table AS (SELECT * FROM old_table);
The select statement will be the fields that will be pulled.
You can rename the columns like: Select [field name] as [what you want field name to be]
For More information read this article
Anyway for your particular case:
Create table enroll AS (Select s.sid AS 'Sid', c.cid AS 'Cid' from courses c inner join students s on c.something = s.something)
replace '.something' with the id of the student
you just created the table structure, the schema, your table is empty, so you dont get any results.

Optimizing this MySQL Query

Table Schema
For the two tables, the CREATE queries are given below:
Table1: (file_path_key, dir_path_key)
create table Table1(
file_path_key varchar(500),
dir_path_key varchar(500),
primary key(file_path_key))
engine = innodb;
Table2: (file_path_key, hash_key)
create table Table2(
file_path_key varchar(500) not null,
hash_key bigint(20) not null,
foreign key (file_path_key) references Table1(file_path_key) on update cascade on delete cascade)
engine = innodb;
Objective:
Given a file_path F and it's dir_path string D, I need to find all those
file names which have at least one hash in the set of hashes of F, but
don't have their directory names as D. If a file F1 shares multiple hashes
with F, then it should be repeated that many times.
Note that the file_path_key column in Table1 and the hash_key column in Table2 are indexed.
In this particular case, Table1 has around 350,000 entries and Table2 has 31,167,119 entries, which makes my current query slow:
create table temp
as select hash_key from Table2
where file_path_key = F;
select s1.file_path_key
from Table1 as s1
join Table2 as s2
on s1.file_path_key join
temp on temp.hash_key = s2.hash_key
where s1.dir_path_key != D
How can I speed up this query?
I do not understand what is the purpose of temp table, but remember that such table, created with CREATE .. SELECT, does not have any indexes. So at the very least fix that statement to
CREATE TABLE temp (INDEX(hash_key)) ENGINE=InnoDB AS
SELECT hash_key FROM Table2 WHERE file_path_key = F;
Otherwise the other SELECT performs full join with temp, so it might be very slow.
I would also suggest using a numerical primary key (INT, BIGINT) in Table1 and reference it from Table2 rather than the text column. Eg:
create table Table1(
id int not null auto_increment primary key,
file_path_key varchar(500),
dir_path_key varchar(500),
unique key(file_path_key))
engine = innodb;
create table Table2(
file_id int not null,
hash_key bigint(20) not null,
foreign key (file_id) references Table1(id)
on update cascade on delete cascade) engine = innodb;
Queries joining the two tables may be a lot faster if integer columns are used in join predicate rather than text ones.