I have two MySQL tables and want to insert multiple records instead of creating one by one, get id and insert related records
here are the tables:
CREATE TABLE `visit` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`ip_address` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`)
)
CREATE TABLE `visitmeta` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`page_visit_id` int(11) NOT NULL,
`key` varchar(255) NOT NULL,
`value` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
)
Currently I insert one record on visit, get its id and insert records on visit meta. Is there a way to create a new record into visit and in the same query create visit meta records?
It's not possible to insert records in two tables with a single query, but you can do it in just two queries using MySQL's LAST_INSERT_ID() function:
INSERT INTO visit
(ip_address)
VALUES
('1.2.3.4')
;
INSERT INTO visitmeta
(page_visit_id, key, value)
VALUES
(LAST_INSERT_ID(), 'foo', 'bar'),
(LAST_INSERT_ID(), 'baz', 'qux')
;
Note also that it's often more convenient/performant to store IP addresses in their raw, four-byte binary form (one can use MySQL's INET_ATON() and INET_NTOA() functions to convert to/from such form respectively).
Related
I'm learning SQL.
I'm trying to insert data. My MySQL database looks like this.
CREATE TABLE category (
category_id CHAR(100),
category_name VARCHAR(120) NOT NULL,
PRIMARY KEY (category_id)
)
I ran this command
INSERT INTO category (category_name) VALUES ("test");
But I got this error
ERROR 1364 (HY000): Field 'category_id' doesn't have a default value
Thank you in advance.
If you want to have an incrementing ID it would need to be an int. You Generally want to make ID's integers not chars to speed up lookup regardless.
CREATE TABLE IF NOT EXISTS category (
`category_id` INT NOT NULL AUTO_INCREMENT,
`category_name` VARCHAR(120) NOT NULL,
PRIMARY KEY (`category_id`)
) ENGINE=InnoDB DEFAULT CHARSET = utf8mb4 COLLATE utf8mb4_unicode_ci;
That will let you insert without adding your own ID, and automatically generate unique ID's for the records.
Issue was you set your category_id field to not have a default value and also not allow null, which means you -have- to set a value for it in the insert. If you wanted to use your existing table you would need to do this:
INSERT INTO category (category_id, category_name) VALUES ("someid", "test");
I´m creating a restApi with PHP over the courses I have studied. When it comes to the database I´m not sure whats the best practise for this problem ->
I have data over the languages each course had, to normalize data I have languages in a separate table and a bridge to connect them.
So one table for Courses, one for Languages and one bridge table to connect them.
CREATE TABLE `Courses`
(`Course_ID` INT(11),
`Education_ID` INT(11),
`CourseName` VARCHAR(100) NOT NULL,
`Points` VARCHAR (5),
`Grade` VARCHAR(3),
PRIMARY KEY (`Course_ID`)
);
CREATE TABLE `Language` (
`Language_ID` INT(11),
`Language` VARCHAR(100) NOT NULL,
`Img_url` VARCHAR (200),
PRIMARY KEY (`Language_ID`)
);
CREATE TABLE `Bridge_language` (
`Course_ID` INT(11) NOT NULL,
`Language_ID` INT(11) NOT NULL,
KEY `PKFK` (`Course_ID`, `Language_ID`)
);
ALTER TABLE Courses MODIFY Course_ID INTEGER AUTO_INCREMENT;
ALTER TABLE Language MODIFY Language_ID INTEGER AUTO_INCREMENT;
When adding a new course, in the SQL I know the id of the languages, (i will have a function in the admin page where you add new languages) then when you create a new course you just click add languages and the id for the language is added.
But what I don't have is the ID for the course which is created with auto_increment. Is there a smart way you with a function/procedure in SQL, can grab the id that auto_increment has generated and use it to add that into the bridge table?
Or do I need to make a query to the database and grab the latest ID and add one and send that into the bridge table?
In MySQL, you can use last_insert_id() to retrieve the auto-generated id of the last insert query that you executed. You don't give much details about your code, but the logic is like:
insert into course (education_id, coursename, points, grade)
values (?, ?, ?, ?);
insert into bridge_language (course_id, language_id)
values (last_insert_id(), ?);
I am using the INSERT function to try and add new values to a table. While there is no error when I run the query, it is not showing the new attributes added to the table. I have no idea why. I also have safe updates turned off. The values entered also match the value type for each column of the table.
CODE ENTERED:
INSERT INTO productlines
VALUES
('Jet Packs', 'Futuristic flying machines that only exist in prototype.', NULL, NULL),
('Jet Skis', 'Much more realistic things that very much exist already.', NULL, NULL),
('Wheelbarrows', 'I cannot believe we actually stock these.', NULL, NULL);
SELECT *
FROM productlines;
CREATE TABLE `productlines` (
`productLine` varchar(50) NOT NULL,
`textDescription` varchar(4000) DEFAULT NULL,
`htmlDescription` mediumtext,
`image` mediumblob,
PRIMARY KEY (`productLine`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
INSERT INTO
[name of your **TABLE**](col1, col2, col3)#NAME OF YOUR COLUMNS
VALUES
('value for col1','value for col2','value for col3'),
You didn't add the column names for which you are performing the insert
I have a table in which there is a column name with SP varchar(10) NOT NULL. I want that column always to be unique so i created unique index on that column . My table schema as follows :
CREATE TABLE IF NOT EXISTS `tblspmaster` (
`CSN` bigint(20) NOT NULL AUTO_INCREMENT,
`SP` varchar(10) NOT NULL,
`FileImportedDate` date NOT NULL,
`AMZFileName` varchar(50) NOT NULL,
`CasperBatch` varchar(50) NOT NULL,
`BatchProcessedDate` date NOT NULL,
`ExpiryDate` date NOT NULL,
`Region` varchar(50) NOT NULL,
`FCCity` varchar(50) NOT NULL,
`VendorID` int(11) NOT NULL,
`LocationID` int(11) NOT NULL,
PRIMARY KEY (`CSN`),
UNIQUE KEY `SP` (`SP`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=10000000000 ;
Now i want that if anybody tries to insert duplicate record then that record should be inserted into a secondary table name tblDuplicate.
I have gone through this question MySQL - ignore insert error: duplicate entry but i am not sure that instead of
INSERT INTO tbl VALUES (1,200) ON DUPLICATE KEY UPDATE value=200;
can i insert duplicate row into another table ?
what changes needed to be done in main table scheme or index column ?
**Note : Data will be inserted by importing excel or csv files and excel files generally contains 500k to 800 k records but there will be only one single column **
I believe you want to use a trigger for this. Here is the MySQL reference chapter on triggers.
Use a before insert trigger. In the trigger, check if the row is a duplicate (maybe count(*) where key column value = value to be inserted). If the row is a duplicate, perform an insert into your secondary table.
I have two tables one is master table and other is just for cache. From time to time I check whether cache table is up to date and there is no missing data. Cache table is using MyISAM engine and master table is using InnoDB engine.
To explain it in more detail I give you an example
Cache table contains fields from following two tables
product_categories (cat-id, cat_name, parent_cat_id DEFAULT NULL, parent_cat_name DEFAULT NULL)
products (product_num, product_name, product_desc, price, image, product_date, availability)
It may be possible cache table does not contain products or it may contain products data but it may not be accurate.
In this question Compare two MySQL databases a tool Toad for MySQL has mentioned but I want to do it using PHP.
Cache table schema
products_cache | CREATE TABLE `products_cache` (
`product_num` int(10) unsigned NOT NULL AUTO_INCREMENT,
`cat_id` int(10) unsigned NOT NULL,
`parent_cat_id` int(10) unsigned DEFAULT NULL,
`cat_name` varchar(50) NOT NULL,
`parent_cat_name` varchar(50) DEFAULT NULL,
`product_desc` text NOT NULL,
`price` float(10) unsigned NOT NULL,
`image` varchar(65) NOT NULL DEFAULT '',
`product_date` DATE DEFAULT NULL,
`availability` tinyint(1) NOT NULL DEFAULT '1',
PRIMARY KEY (`product_num`),
) ENGINE=MyISAM
Possible solution
Compute the md5 of the fields and store it in cache table and then next time check the md5 in cache table if data is changed. It will work fine except there will be performance issue (I run cache fixer every month, so I think I can compromise with that). Please comment on this.
Instead of computing MD5 sums for all of your data every month you could simply record changes to a table using triggers.
CREATE TABLE changes (
table char(30) NOT NULL, -- TODO use an enum for better performance
id int NOT NULL,
UNIQUE KEY tableId (table, id),
)
CREATE TRIGGER insert_products AFTER INSERT ON products FOR EACH ROW INSERT IGNORE INTO changes (table, id) values ("products", OLD.id);
CREATE TRIGGER update_products AFTER UPDATE ON products FOR EACH ROW INSERT IGNORE INTO changes (table, id) values ("products", OLD.id);
CREATE TRIGGER delete_products AFTER DELETE ON products FOR EACH ROW INSERT IGNORE INTO changes (table, id) values ("products", OLD.id);
CREATE TRIGGER insert_product_categories AFTER INSERT ON product_categories FOR EACH ROW INSERT IGNORE INTO changes (table, id) values ("product_categories", OLD.id);
CREATE TRIGGER update_product_categories AFTER UPDATE ON product_categories FOR EACH ROW INSERT IGNORE INTO changes (table, id) values ("product_categories", OLD.id);
CREATE TRIGGER delete_product_categories AFTER DELETE ON product_categories FOR EACH ROW INSERT IGNORE INTO changes (table, id) values ("product_categories", OLD.id);
-- do this for every involved table
once in a while, you could than update changed rows (in a nightly batch job) (pseudo code):
for {table,id} in query(select table, id from changes) {
cacheRow = buildCacheRow($table, $id)
doInTransaction {
query(replace into product_cache values $cacheRow)
query(delete from changes where table = $table and id = $id)
}
}