I am having a table with the composite key
emp_tbl(
companyId int not null,
empId int not null auto_increment,
name varchar2,
....
...
primary key(companyId,empId)
);
In mysql whats happening is while i starts inserting the data
Emp_tbl
companyId empId
1 1
1 2
1 3
2 1
2 2
Note that when the companyId changes the auto_increament value is resetted to 1 again. I want to disable that. I mean i don't want to reset the auto_increament. I am expecting the result like this.
companyId empId
1 1
1 2
1 3
2 4
2 5
Is it possible to do it?
Thanks
This is what happens with a composite primary key that incorporates a auto_increment. Recreate the primary key so that it's purely your auto_increment field (empId) then create a unique index on companyId and empId
EDIT
Note that this only applies to MyISAM and BDB tables. If you used InnoDB for your tables, then it would also work as you wanted
If you do not want empId to reset then just reverse the order of primary definition
primary key(companyId,empId)
note that composite key order matters.
Related
I'm having a problem with thinking of the way to connect two tables.
I have one table with actions (RAD):
CREATE TABLE RAD (
rad_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
spec_id INT NULL,
predp_id INT NULL,
predf_id INT NULL,
strp_ID INT NULL,
strf_ID INT NULL,
---more fileds---
FOREIGN KEY (spec_id) REFERENCES SPEC(spec_id) ON DELETE SET NULL,
FOREIGN KEY (strp_ID) REFERENCES STRANKEP(strp_ID) ON DELETE CASCADE,
FOREIGN KEY (strf_ID) REFERENCES STRANKEF(strf_ID) ON DELETE CASCADE,
FOREIGN KEY (predp_id) REFERENCES PREDMETIP(predp_id) ON DELETE CASCADE,
FOREIGN KEY (predf_id) REFERENCES PREDMETIF(predf_id) ON DELETE CASCADE
) ENGINE=InnoDB COLLATE utf8_general_ci;
And one table of specifications (SPEC) based on whom bill will be made:
CREATE TABLE SPEC (
spec_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
---more fileds---
) ENGINE=InnoDB COLLATE utf8_general_ci;
As you can see action rad_id(RAD) row will be deleted if any client (strp_ID or strf_ID) will be deleted. The same goes for case(predp_id and predf_id).
Now I want to restrict delete of action rad_id(RAD row) if its included in specification. Therefore, when specification is made it inserts spec_id(SPEC) in spec-id(RAD) filed.
When specification is deleted field goes back to null and that works. BUT it allows me to delete the action rad_id(RAD) when it was included in specification(SPEC) and has that foreign key spec_id included in RAD table. And I can not let that happen. It should delete only when its null and specification key is not present.
The problem is specification will contain MULTIPLE actions rad_id's(RAD) so I can not tie it with one more column rad_id(RAD) as foreign key.
I don't know how to approach this problem.
RAD TABLE
rad_id spec_id
1 1
2 1
3 1
4 null
SPEC TABLE
spec_id rad_id-reference
1 1,2,3
As seen above SPEC table row will be made out of 3 rad_id's, I need a way to say rad_id's 1,2 and 3 can not be deleted if spec_id 1 exists. rad_id 4 can be deleted.
The problem is that I can not make rad_id-reference on SPEC table a FOREIGN KEY made out of 3 rad_id's.
I have found a way to do this.
http://sqlfiddle.com/#!9/50de2/1 If you change a delete value into 1 it will fail.
RAD TABLE
rad_id-PK
1
2
3
4
SPEC TABLE
spec_id-PK
1
2
RESTRICTDEL TABLE
res_id-PK spec_id-FK rad_id-FK
1 1 1
2 1 2
3 2 2
4 2 3
5 2 3
I have made another table that will contain both PK id's in one column, and they are FK's. one is PK and it will be unique just like spec_id From SPEC table. second is rad_id that can be double. I just have to set SET foreign_key_checks = 0; and back 1 when I'm done with inserting a new specification.
Also will need to loop with php and for every rad_id make new resdel_id entry.
This way multiple rad_id wont be deleted if there is one spec_id connecting them.
I'm sure this is simple stuff to many of you, so I hope you can help easily.
If I have a MySQL table on the "many" side of a "one to many" relationship - like this:
Create Table MyTable(
ThisTableId int auto_increment not null,
ForeignKey int not null,
Information text
)
Since this table would always be used via a join using ForeignKey, it would seem useful to make ForeignKey a clustered index so that foreign keys would always be sorted adjacently for the same source record. However, ForeignKey is not unique, so I gather that it is either not possible or bad practice to make this a clustered index? If I try and make a composite primary key using (ForeignKey, ThisTableId) to achieve both the useful clustering and uniqueness, then there is an error "There can only be one auto column and it must be defined as a key".
I think perhaps I am approaching this incorrectly, in which case, what would be the best way to index the above table for maximum speed?
InnoDB requires that if you have an auto-increment column, it must be the first column in a key.
So you can't define the primary key as (ForeignKey, ThisTableId) -- if ThisTableId is auto-increment.
You could do it if ThisTableId were just a regular column (not auto-increment), but then you would be responsible for assigning a value that is at least unique among other rows with the same value in ForeignKey.
One method I have seen used is to make the column BIGINT UNSIGNED, and use a BEFORE INSERT trigger to assign the column a value from the function UUID_SHORT().
#ypercube correctly points out another solution: The InnoDB rule is that the auto-increment column should be the first column of some key, and if you create a normal secondary key, that's sufficient. This allows you to create a table like the following:
CREATE TABLE `MyTable` (
`ForeignKey` int(11) NOT NULL,
`ThisTableId` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`ForeignKey`,`ThisTableId`),
KEY (`ThisTableId`)
) ENGINE=InnoDB;
And the auto-increment works as expected:
mysql> INSERT INTO MyTable (ForeignKey) VALUES (123), (234), (345), (456);
mysql> select * from MyTable;
+------------+-------------+
| ForeignKey | ThisTableId |
+------------+-------------+
| 123 | 1 |
| 234 | 2 |
| 345 | 3 |
| 456 | 4 |
+------------+-------------+
Suppose we have the following chunk of data (SQL table):
Col-A Col-B Col-C Col-D
1 1 1 1
1 1 1 2
1 1 1 3
2 2 2 4
2 2 2 5
In MySQL the table is defined as:
CREATE TABLE `my_table` (
`Col-A` INT(10) UNSIGNED NOT NULL DEFAULT '0',
`Col-B` INT(10) UNSIGNED NOT NULL DEFAULT '0',
`Col-C` INT(10) UNSIGNED NOT NULL DEFAULT '0',
`Col-D` INT(10) UNSIGNED NOT NULL DEFAULT '0',
PRIMARY KEY (`Col-A`, `Col-B`, `Col-C`),
KEY `my_index` (`Col-D`) USING BTREE
);
I need to convert MySQL database to SQL Server. Here is my initial attempt:
CREATE TABLE my_table (
Col-A INT NOT NULL DEFAULT(0),
Col-B INT NOT NULL DEFAULT(0),
Col-C INT NOT NULL DEFAULT(0),
Col-D INT NOT NULL DEFAULT(0),
CONSTRAINT my_pk PRIMARY KEY NONCLUSTERED (Col-A, Col-B, Col-C)
)
CREATE INDEX my_idx ON my_table(Col-D)
When I try to import data (I use bcp), the following error occurs:
Cannot insert duplicate key ... The duplicate key is (1, 1, 1)
I suspect that something is wrong with my_pk and my_idx definitions. Any pointers or suggestions?
You know the definition of a primary key?
http://en.wikipedia.org/wiki/Primary_key
In the relational model of database design, a unique key or primary key is a set of attributes whose values uniquely define the characteristics of each row.
When the combination of Col-A + Col-B + Col-C is not unique you violate the primary key constraint and thus SQL server won't allow it.
Your options are:
Extend the PK to include Col-D
Drop the PK and use a (clustered or not) Index on Col-A, Col-B and Col-C
Fix the data so it doesn't violate the PK constraint (either drop records or alter/correct incorrect records)
Add a synthetic (or surrogate) key (see mrjoltcola's answer)
Which option to choose is up to you and depends on your requirements. We can't answer that for you based only on the information in your question.
Why MySQL allowed this data to get in there in the first place... *shrugs* MySql is a "funny" beast. Maybe the PK constraint was added after the data was already in the table, maybe it's a really old version, maybe you're using MyISAM instead of InnoDB. I'm not sure which but each of these reasons (or combination of them) are a good guess or, at least, were decent guesses some time / versions ago. Either way: it shouldn't have been possible (even if the PK constraint was added later; MySQL should've denied adding it since the data in the table was conflicting) but MySQL had, and does have, it's own weird ways of reasoning about these kind of things. Strict mode helps if I recall correctly but I can't remember if that only works on InnoDB tables or also on MyISAM etc. Either way; they made a nice mess of it back in the day; I (or you) shouldn't have to worry about remembering the differences in underlying MyISAM/InnoDB/Whatevs etc. or which specific version allows what (not) to happen or if you need strict mode or not for this-or-that for basic stuff like PK's to work correctly*
* Each RDBMS has it's quirks; I'm sure there's a good reason for some switches/toggles/settings/whatevs to tweak some details, I'm saying PK's should be PK's no matter what.
For your data requirement, you cant use cols (A,B,C) as primary key. You need to either add (D) to the key, or add a surrogate key. See RobIII's answer https://stackoverflow.com/a/24703970/257090 for why.
I recommend you go with the latter, add an ID primary key so you have a single field key:
CREATE TABLE my_table (
ID INT IDENTITY PRIMARY KEY,
ColA INT NOT NULL DEFAULT(0),
ColB INT NOT NULL DEFAULT(0),
ColC INT NOT NULL DEFAULT(0),
ColD INT NOT NULL DEFAULT(0),
UNIQUE(ColA,ColB,ColC,ColD)
)
INSERT INTO my_table(cola, colb, colc, cold) VALUES(1,1,1,1)
INSERT INTO my_table(cola, colb, colc, cold) VALUES(1,1,1,2)
INSERT INTO my_table(cola, colb, colc, cold) VALUES(1,1,1,3)
INSERT INTO my_table(cola, colb, colc, cold) VALUES(2,2,2,4)
INSERT INTO my_table(cola, colb, colc, cold) VALUES(2,2,2,5)
SELECT * FROM my_table
ID ColA ColB ColC ColD
----------- ----------- ----------- ----------- -----------
1 1 1 1 1
2 1 1 1 2
3 1 1 1 3
4 2 2 2 4
5 2 2 2 5
(5 row(s) affected)
Now I can identify each row by a single key value.
delete from my_table where ID = 5
This is much more practical for any code you write against the database or ORMs you use.
NOTE: with surrogate (or synthetic keys) it is still important that you add any additional constraints to enforce data integrity of the actual data. A surrogate key doesn't keep you from inserting 1,1,1,1 multiple times, so add a unique constraint/index to those fields in addition to the primary key ID.
this is my DB structure.
this is the script I used to create the tables
use for_stkoverflow;
CREATE TABLE UserGroup (
groupid MEDIUMINT NOT NULL AUTO_INCREMENT,
groupname VARCHAR(100),
PRIMARY KEY (`groupid`)
);
CREATE TABLE User_det (
Usrid MEDIUMINT NOT NULL AUTO_INCREMENT,
usrname VARCHAR(255),
groupid MEDIUMINT,
PRIMARY KEY (`Usrid`),
Foreign Key (groupid)
references UserGroup (groupid)
);
CREATE TABLE Accounts (
acid MEDIUMINT NOT NULL AUTO_INCREMENT,
groupid MEDIUMINT,
acname VARCHAR(255),
PRIMARY KEY (`acid`),
Foreign Key (groupid)
references UserGroup (groupid)
);
create table Ledger (
ledgerid MEDIUMINT NOT NULL AUTO_INCREMENT,
ledgername VARCHAR(255),
acid mediumint,
Usrid mediumint,
PRIMARY KEY (ledgerid),
Foreign Key (acid)
references Accounts (acid),
Foreign Key (Usrid)
references User_det (Usrid)
);
I have the following data entered
UserGroup
----------
- groupid groupname
--------------------
- 1 Group1
- 2 Group2
User_det
--------
- Usrid usrname groupid
-----------------------
- 1 User1 1
- 2 User2 2
Accounts
--------
- acid groupid acname
---------------------
- 1 1 ac1
- 2 2 ac2
Ledger
--------
-ledgerid ledgername acid Usrid
--------------------------------
- 1 ledger1 1 1
- 2 ledger2 2 2
- 3 ledger3 1 2
- 4 ledger4 2 1
SELECT t1.ledgerid, t1.ledgername,t2.acname,t3.usrname
FROM Ledger AS t1
INNER JOIN Accounts AS t2 ON t1.acid = t2.acid
Inner join User_det AS t3 ON t1.Usrid = t3.Usrid;
The current table structure permits insertion of data that violates DB integrity.
The entry ledgerid 3 is invalid
---------------------------------- because acname ac1 belongs to group1 to which User2 is not part of. The entry ledgerid 4 is
invalid
because acname ac2 belongs to group2 to which User1 is not part of.
How can I prevent the insert of such data?
Right now in the application I am doing this check via PHP in the BL layer.
Can I enforce this at the DB level because I do some import from the backed also without using the PHP front end.
Use identifying relationships, similar to this:
Note how UserGroup PK migrates from the top of this "diamond", down both "sides" and merges at the "bottom". Since a row at the bottom contains only one field identifying the top, it cannot be related to multiple rows at the top.
You can still keep your other keys if you need them for other purposes and/or make the keys above alternate (i.e. UNIQUE constraints)...
BTW, use naming more consistently - I'd recommend always using singular and prefixing PK fields with unabbreviated table names...
Side note :I believe you gave too many details in your question, so I apologize if I misunderstood it.
Taking into account you use mysql which doesn't have materialized views that could be used to enforce desired constraint, I see two options.
First, you can mimic materialized view with trigger[s] and a new table with unique constraint (it will work, but it's quite hard to implement in general - you have to make sure all INSERT/UPDATE/DELETE on 3 tables are handled properly by corresponding triggers).
Another way is to denormalize your schema by adding groupId to Ledger , and "extra" unique constraint on Users (userId, groupId) and Accounts (acid,groupId), and changing FKs in Ledger so it refers not to userId in Users, but to userId,groupId and not to acid, but to acid,groupId.
I hope that helps.
Say I have
ID | PRODUCT
1 | Apples
1 | Oranges
1 | Bananas
2 | Walnuts
2 | Almonds
3 | Steak
3 | Chicken
Is this possible to have this type of setup in MySQL? I created a test table, and made an ID column with primary index and auto incrementing. When I try to insert a couple rows all having the same ID, mysql returns an error.
Is this possible to do in mysql?
How did the duplicate records (ID) INSERTED when you set ID as Primary Key? Basically, it will not. Primary Keys are UNIQUE. If you want records to be like that, make another column which served as your primary key
CREATE TABLE sampleTable
(
ID INT NOT NULL AUTO_INCREMENT,
GROUP_ID INT NOT NULL,
PRODUCT VARCHAR(25),
CONSTRAINT pk_name PRIMARY KEY (ID),
CONSTRAINT uq_name UNIQUE (GROUP_ID, PRODUCT)
)
a UNIQUE constraint was added so to avoid duplicated rows.
That is possible, but it is not normalized as you have a repeating primary key. Primary keys must be unique, which means 1 can only occur once. If you have custom ID's for each product, then either use a compound primary key (id, product) or a surrogate key. A surrogate key would be an auto incrementing column that uniquely identifies the row. Your table would then look like this:
CREATE TABLE fruits (
auto_id int AUTO_INCREMENT PRIMARY KEY,
id int,
product varchar(15))
You mustn't create a primary key for the ID column, as this implies that it's unique.
Just take a normal index for your example.
On the other hand, in most cases, it makes sense to have a primary key, so I'd recommend adding a 3rd row (GENRE?) with a normal INDEX on it and leaving the primary key as it is.
When inserting data, just insert the GENRE and the PRODUCT, the ID will be automatically filled.