I'm porting some Postgres SQL to MySQL and am trying to set the starting values of three columns to specific values. The table is as follows:
CREATE TABLE ITEM (
ORDID NUMERIC(4) NOT NULL,
ITEMID NUMERIC(4) NOT NULL,
PRODID NUMERIC(6),
ACTUALPRICE NUMERIC(8,2),
QTY NUMERIC(8),
ITEMTOT NUMERIC(8,2),
CONSTRAINT ITEM_FOREIGN_KEY FOREIGN KEY (ORDID) REFERENCES ORD (ORDID),
CONSTRAINT ITEM_PRIMARY_KEY PRIMARY KEY (ORDID,ITEMID));
The code I'm trying to port is as follows:
CREATE SEQUENCE ORDID
INCREMENT BY 1
START WITH 622
;
CREATE SEQUENCE PRODID
INCREMENT BY 1
START WITH 200381
;
CREATE SEQUENCE CUSTID
INCREMENT BY 1
START WITH 109
;
However, when trying to run this I'm getting the error:
SQL query:
CREATE SEQUENCE ORDIDINCREMENT BY 1 START WITH 622 ;
MySQL said: Documentation
#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SEQUENCE ORDID
INCREMENT BY 1
START WITH 622' at line 1
I know that there is no direct equivalent to a SEQUENCE in MySQL but I can't figure out a reasonable way to achieve the same thing without it. Any ideas?
MySQL uses AUTO_INCREMENT for that purpose. Rather than making new sequence types, you apply it to an existing integer column.
Unfortunately you can only have one per table.
There can be only one AUTO_INCREMENT column per table, it must be indexed, and it cannot have a DEFAULT value.
And they must be integers, numeric doesn't work. This will probably improve your schema as 9999 orders and items seems very small.
AUTO_INCREMENT applies only to integer and floating-point types.
And if that wasn't enough, you can't have an AUTO_INCREMENT on a multi-key primary key. Only the vastly inferior MyISAM table format allows that.
So you cannot easily translate your PostgreSQL tables to MySQL verbatim.
You sure you want to convert to MySQL?
In your case, item.ordid is a reference so it will be incremented in its own table. item.prodid is probably also a reference and somebody forgot to declare it that. This leaves just item.itemid to be declared AUTO_INCREMENT, but it's part of the primary key. It probably doesn't need to be, it can just be unique.
In fact, the ITEM table seems more like it's tracking orders of products, not items... but then there's also a product ID? I don't know what an "item" is.
You wind up with something like this:
CREATE TABLE ITEM (
ITEMID INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
PRODID INTEGER REFERENCES PROD(PRODID),
ORDID INTEGER NOT NULL REFERENCES ORD (ORDID),
ACTUALPRICE NUMERIC(8,2),
QTY NUMERIC(8),
ITEMTOT NUMERIC(8,2),
UNIQUE(ORDID, ITEMID)
)
CREATE TABLE ORD (
ORDID INTEGER PRIMARY KEY AUTO_INCREMENT,
...
) AUTO_INCREMENT = 622;
CREATE TABLE PROD (
PRODID INTEGER PRIMARY KEY AUTO_INCREMENT,
...
) AUTO_INCREMENT = 200381;
You can also set the AUTO_INCREMENT starting point after the fact with ALTER TABLE. Because it's a table attribute, not a column attribute, it happens on the table itself.
ALTER TABLE CUST AUTO_INCREMENT=109;
It's largely unnecessary to set the AUTO_INCREMENT starting point if you're importing an existing data set. AUTO_INCREMENT will always use MAX(column) and it cannot be set lower than this. It doesn't matter what you start it at if the table is already populated.
You can create a table with an AUTO_INCREMENT field and set its initial value.
create table myseq(
my_id int auto_increment primary key
) auto_increment=100;
Or use ALTER TABLE to reset the value whenever you want:
alter table myseq auto_increment = 100;
You can use table with AUTO_INCREMENT key to emulate sequences:
CREATE TABLE ORDID (id INT PRIMARY KEY AUTO_INCREMENT) AUTO_INCREMENT = 622;
CREATE TABLE PRODID (id INT PRIMARY KEY AUTO_INCREMENT) AUTO_INCREMENT = 200381;
CREATE TABLE CUSTID (id INT PRIMARY KEY AUTO_INCREMENT) AUTO_INCREMENT = 109;
Each of the table represents a 'sequence'. To use one in your CREATE TABLE:
CREATE TABLE ITEM (
ORDID INT NOT NULL,
ITEMID NUMERIC(4) NOT NULL,
PRODID NUMERIC(6),
ACTUALPRICE NUMERIC(8,2),
QTY NUMERIC(8),
ITEMTOT NUMERIC(8,2),
CONSTRAINT ITEM_FOREIGN_KEY FOREIGN KEY (ORDID) REFERENCES ORDID (ID),
CONSTRAINT ITEM_PRIMARY_KEY PRIMARY KEY (ORDID,ITEMID));
You can then use INSERT to get a new value from your 'sequence':
INSERT INTO ordid VALUES (null);
SELECT LAST_INSERT_ID();
Related
I have written an application in Javascript which inserts data into two tables via a connection to a MariaDB server.
There should be a 1:1 correspondance between the rows in these tables when first running the application.
One table stores (simulated) data about properties, the other table stores data about prices. There should be 1 price for each property. At a later date, the price might change, so there could be more than one entry for the price, but this cannot happen when the application is first run. These entries also cannot be in violation of a unique index - but they are.
Perhaps I have misconfigured something in MariaDB? Here is the code which generates the tables.
drop table if exists property_price;
drop table if exists property;
create table property
(
unique_id bigint unsigned not null auto_increment primary key,
web_id bigint unsigned not null,
url varchar(256),
street_address varchar(256),
address_country varchar(64),
property_type varchar(64),
num_bedrooms int,
num_bathrooms int,
created_datetime datetime not null,
modified_datetime datetime not null
);
create table property_price
(
property_unique_id bigint unsigned not null,
price_value decimal(19,2) not null,
price_currency varchar(64) not null,
price_qualifier varchar(64),
added_reduced_ind varchar(64),
added_reduced_date date,
created_datetime datetime not null
);
alter table property_price
add constraint fk_property_unique_id foreign key(property_unique_id)
references property(unique_id);
alter table property
add constraint ui_property_web_id
unique (web_id);
alter table property
add constraint ui_url
unique (url);
alter table property_price
add constraint ui_property_price
unique (property_unique_id, price_value, price_currency, price_qualifier, added_reduced_ind, added_reduced_date);
Below is a screenshot from DBeaver showing that a select statement returns two identical rows.
I don't understand why the unique constraint appears to be violated. The constraint does sometimes work, because if I run my application again, it fails because it attempts to insert a duplicate row which already exists in the DB. (Not the same as the one shown below.)
Can anyone point me in the right direction as to how I might debug this?
MariaDB permits multiple values on columns which form part of a unique constraint.
My solution would be to put the logic for checking for duplicate rows into the application, rather than this being on the database side. Essentially this means the unique constraint is not being used.
I was about to create two tables (1st table: fooditem_tbl & 2nd table: orderitem_tbl). I was planning to create 2 foreign keys (ITEM_NAME,UNIT_PRICE) on the 2nd table. I wasn't able to run the query of the 2nd table(orderitem_tbl), due to an error which is near at "INDEX". I kept looking at my query, and I still don't know what's the cause of the error.
My first table , this one works
CREATE TABLE FOODITEM_TBL
(ITEM_ID INT AUTO_INCREMENT,
ITEM_NAME VARCHAR(50) UNIQUE,
UNIT_PRICE DOUBLE UNSIGNED,
ITEM_QUANTITY INT UNSIGNED,
IN_STOCK BOOLEAN,
PRIMARY KEY (ITEM_ID, ITEM_NAME, UNIT_PRICE));
The 2nd table, which is below fails to create
CREATE TABLE ORDERITEM_TBL(
ORDER_ID INT AUTO_INCREMENT,
ITEM_NAME VARCHAR(50) UNIQUE,
UNIT_PRICE DOUBLE UNSIGNED,
ITEM_QUANTITY INT UNSIGNED,
CUSTOMER_NAME VARCHAR(50),
ADDRESS VARCHAR(50),
CONTACT_NUMBER VARCHAR(50),
PRIMARY KEY (ORDER_ID),
INDEX (ITEM_NAME,UNIT_PRICE),
FOREIGN KEY (ITEM_NAME,UNIT_PRICE) REFERENCES
FOODITEM_TBL(ITEM_NAME,UNIT_PRICE)
) ENGINE = InnoDB;
P.S Please help
Q: What is causing the error? How can I fix it?
For InnoDB, there must be an index on the target table, on the target column(s). Datatypes of the referencing foreign key column(s) must match the datatypes of the target column(s).
Before creating the foreign key constraint, make sure a suitable index exists on the target table, e.g.
CREATE UNIQUE INDEX `FOODITEM_TBL_UX3` ON `FOODITEM_TBL` (`ITEM_NAME`, `UNIT_PRICE`) ;
Given that ITEM_NAME is unique in the target table, we know that the combination of ITEM_NAME and UNIT_PRICE will also be unique. I'm not sure why we wouldn't just define a foreign key constraint on just ITEM_NAME, but that doesn't really address the question that was asked.
Personally, I would avoid floating point datatypes (e.g. DOUBLE) for columns involved in foreign key constraints.
All,
I am trying to migrate from PostgreSQL DB to MySql DB. I have used sequence in some table to get auto increment column other than the primary key. How to create auto increment column which is the primary key in Mysql DB.
I am listing an example table below in PostgreSQL.
CREATE TABLE bills
(
id serial NOT NULL,
billname character varying(255) NOT NULL,
invoiceid character varying(255) NOT NULL DEFAULT nextval('bill_invoiceid_seq'::regclass),
CONSTRAINT combine_campaigns_pkey PRIMARY KEY (id)
)
In the example, "id" is the primary key and invoice id is not a key but getting auto increment
MySQL int auto_increment primary key should be very similar to postgreSQL serial (which does not need to be a primary key)
If you want to reserve some used sequence, you can insert a value (eg 3000) into MySQL auto_increment field, after that any new record will increase from this value i.e. 3001 onwards:
The equivalent for a SERIAL column in mysql is AUTO_INCREMENT. Define your primary key as follows:
CREATE TABLE my_table(
id int NOT NULL AUTO_INCREMENT PRIMARY KEY,
...
)
or
CREATE TABLE my_table(
id int NOT NULL AUTO_INCREMENT ,
...
PRIMARY KEY(id)
)
Be aware that in mysql you can only have one AUTO_INCREMENT per table. Also worth mentioning is that you are moving from an RDBS that is rich in features and closer to standard compliance to one that has less features and less compliant.
I am trying to add a self relation in an existing Innodb table here is table structure
Table person
person_id int (10) primary key not null auto increment,
parent_id int (10) NULL default null,
name varchar(30)
When I use this command
ALTER TABLE `person` ADD FOREIGN KEY ( `parent_id` ) REFERENCES `person` (`person_id`) ON DELETE RESTRICT ON UPDATE RESTRICT ;
I get the error data type mismatch. I think this could be due to null values in parent_id. Is there any way to skip this check?
Thanks
person_id and parent_id need to be the exact same data type. For example, if person_id is INT UNSIGNED and parent_id is INT, then you can't create the foreign key.
Run this command and compare the data types of the two columns:
SHOW CREATE TABLE `person`\G
I know how to use INDEX as in the following code. And I know how to use foreign key and primary key.
CREATE TABLE tasks (
task_id int unsigned NOT NULL AUTO_INCREMENT,
parent_id int unsigned NOT NULL DEFAULT 0,
task varchar(100) NOT NULL,
date_added timestamp NOT NULL,
date_completed timestamp NULL,
PRIMARY KEY ( task_id ),
INDEX parent ( parent_id )
)
However I found a code using KEY instead of INDEX as following.
CREATE TABLE orders (
order_id int unsigned NOT NULL AUTO_INCREMENT,
-- etc
KEY order_date ( order_date )
)
I could not find any explanation on the official MySQL page. Could anyone tell me what is the differences between KEY and INDEX?
The only difference I see is that when I use KEY ..., I need to repeat the word, e.g. KEY order_date ( order_date ).
There's no difference. They are synonyms, though INDEX should be preferred (as INDEX is ISO SQL compliant, while KEY is a MySQL-specific, non-portable, extension).
From the CREATE TABLE manual entry:
KEY is normally a synonym for INDEX. The key attribute PRIMARY KEY can also be specified as just KEY when given in a column definition. This was implemented for compatibility with other database systems.
By "The key attribute PRIMARY KEY can also be specified as just KEY when given in a column definition.", it means that these three CREATE TABLE statements below are equivalent and generate identical TABLE objects in the database:
CREATE TABLE orders1 (
order_id int PRIMARY KEY
);
CREATE TABLE orders2 (
order_id int KEY
);
CREATE TABLE orders3 (
order_id int NOT NULL,
PRIMARY KEY ( order_id )
);
...while these 2 statements below (for orders4, orders5) are equivalent with each other, but not with the 3 statements above, as here KEY and INDEX are synonyms for INDEX, not a PRIMARY KEY:
CREATE TABLE orders4 (
order_id int NOT NULL,
KEY ( order_id )
);
CREATE TABLE orders5 (
order_id int NOT NULL,
INDEX ( order_id )
);
...as the KEY ( order_id ) and INDEX ( order_id ) members do not define a PRIMARY KEY, they only define a generic INDEX object, which is nothing like a KEY at all (as it does not uniquely identify a row).
As can be seen by running SHOW CREATE TABLE orders1...5:
Table
SHOW CREATE TABLE...
orders1
CREATE TABLE orders1 ( order_id int NOT NULL, PRIMARY KEY ( order_id ))
orders2
CREATE TABLE orders2 ( order_id int NOT NULL, PRIMARY KEY ( order_id ))
orders3
CREATE TABLE orders3 ( order_id int NOT NULL, PRIMARY KEY ( order_id ))
orders4
CREATE TABLE orders4 ( order_id int NOT NULL, KEY ( order_id ))
orders5
CREATE TABLE orders5 ( order_id int NOT NULL, KEY ( order_id ))
Here is a nice description about the "difference":
"MySQL requires every Key also be indexed, that's an implementation
detail specific to MySQL to improve performance."
Keys are special fields that play very specific roles within a table, and the type of key determines its purpose within the table.
An index is a structure that RDBMS(database management system) provides to improve data processing. An index has nothing to do with a logical database structure.
SO...
Keys are logical structures you use to identify records within a table and indexes are physical structures you use to optimize data processing.
Source: Database Design for Mere Mortals
Author: Michael Hernandez
It is mentioned as a synonym for INDEX in the 'create table' docs:
MySQL 5.5 Reference Manual :: 13 SQL Statement Syntax :: 13.1 Data Definition Statements :: 13.1.17 CREATE TABLE Syntax
#Nos already cited the section and linked the help for 5.1.
Like PRIMARY KEY creates a primary key and an index for you,
KEY creates an index only.
A key is a set of columns or expressions on which we build an index.
While an index is a structure that is stored in database, keys are strictly a logical concept.
Index help us in fast accessing a record, whereas keys just identify the records uniquely.
Every table will necessarily have a key, but having an index is not mandatory.
Check on https://docs.oracle.com/cd/E11882_01/server.112/e40540/indexiot.htm#CNCPT721