I have two mysql tables and I want to insert an email in both of them.
I need to split email to name
and domain name
and insert each part of them to one table.
My domain
table is like this:
+----+--------+
| id | domain | primary(id)
+----+--------+
and my email
table is:
+-------+----------+
| eMail | domainId | primary key(eMail, domainId)
+-------+----------+
ie: info@example.com > example.com
have to insert in domain
table and info
have to add in email
table with domainId.
domain must be unique.
My try:
foreach($emails as $email)
{
list($account,$hostname) = explode('@',$email,2);
$query = $dbh->prepare("SELECT id FROM domain WHERE domain LIKE :domain LIMIT 0,1");
$query->execute(array(':domain'=>trim($hostname)));
if($query->rowCount())
{
$id = $query->fetch();
$id = $id['id'];
}else{
$insert = $dbh->prepare("INSERT INTO domain (domain) VALUES (:domain)");
$insert->execute(array(':domain'=>trim($hostname)));
$id = $dbh->lastInsertId();
}
$name = $dbh->prepare("INSERT INTO email (eMail, domainId) VALUES (:eMail, :domainId)");
$name->execute(array(':eMail'=>trim($account),':domainId'=>$id));
}
but this way is very slow when I want to add bulk emails:
Is there any faster way or maybe I can do this in single query..?
Only insert the emails and add a trigger to the email
table that extracts the domain name and inserts that automatically into domain
DELIMITER |
CREATE TRIGGER insert_domain_trigger BEFORE INSERT ON email
FOR EACH ROW
begin
set @domainname = substring(NEW.email, instr(NEW.email, '@') + 1);
if(select count(*) from domain where domain = @domainname) = 0
then
insert into domain (domain) values (@domainname);
end if;
end
|
Since you have a lot of emails from the same domain, you can try caching the domain ids in a local php variable in order to reduce the # of queries to the db.
Also, you should prepare the $insert
and $name
statements just once outside your loop.
$domains = array();
foreach($dbh->query("SELECT id, domain FROM domain") as $domain) {
$domains[$domain['domain']] = $domain['id'];
}
$insert = $dbh->prepare("INSERT INTO domain (domain) VALUES (:domain)");
$name = $dbh->prepare("INSERT INTO email (eMail, domainId) VALUES (:eMail,:domainId)");
foreach($emails as $email)
{
list($account,$hostname) = explode('@',$email,2);
$hostname = trim($hostname);
if(!isset($domains[$hostname])) {
$insert->execute(array(':domain'=>$hostname));
$id = $dbh->lastInsertId();
$domains[$hostname] = $id;
}
else {
$id = $domains[$hostname];
}
$name->execute(array(':eMail'=>trim($account),':domainId'=>$id));
}
Maybe a simple procedure could fix this?
This would need the field domain in the database to be of type UNIQUE
for the INSERT IGNORE INTO
syntax.
DELIMITER $$
CREATE PROCEDURE `sp_InsertEmail`(IN p_Email VARCHAR(100))
BEGIN
-- Declare variables
DECLARE v_Email VARCHAR(100);
DECLARE v_Domain VARCHAR(100);
-- Set the variables
SET v_Email = SUBSTRING(p_Email,1,INSTR(p_email,'@')-1);
SET v_Domain =SUBSTRING(p_Email,INSTR(p_Email,'@'));
-- Now insert ignore into domain table
INSERT IGNORE INTO db.domain (domain) VALUES(v_Domain);
-- Then insert like this.
INSERT IGNORE INTO db.email SELECT v_Email,DomainId FROM domain WHERE domain=v_Domain;
END
Then simply call the procedure
CALL db.sp_InsertEmail('name@domain.com')
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.