How to define a deferred constraint in MySQL - mysql

is it possible to create a primary key in a existing table on a column that have repeated value? I want is previous record not validate but new record will validate with this.Is it possible in mysql. I know it is possible in Oracle (here is an example) but don't have idea about mysql.

The link you posted as a comment to Nerd-Herd's answer uses deferred constraints. Those constraints are checked at the end of the transaction rather than at the time the statement is executed.
MySQL does not support deferred constraints
If you absolutely need deferred constraints and want to stick with an open source database you will need to migrate to PostgreSQL.

No it can not be. It violates what Primary Key means. But if you want to have a composite primary key, it may be possible

A primary key is always a unique identifier, if you make it non unique it stops being an identifier, why do you want to repeat it? If you have multiple entries that have a field that repeats, that field is not your primary key, however, you can combine it with another field that will give you a primary key (not very recommendable, but you can make this field plus a timestamp field your combined primary key).
In this case what I would recommend is make an autoincrement key and just use this field that repeats as a normal field, maybe ad an index to it to improve searches. You can still look for records on any field, just because it's not your primary key it doesn't mean you are not going to be able to search and get it. The idea of a primary key is that it will get you 1 and only 1 record, not 1 or more.

Related

Create MySQL table without Primary Key

I have a table that does not require a primary key. It consists of 4 columns which are email,date,time,message. Each time a user logs in, logs out, or does any particular action that is important, I log the email, date, time and action (message). Currently the table is setup with email as the Primary Key but I am unable to insert more than one record with the same email. I suppose I could use time as the PK but there is the possibility that two actions fall on the same time. How can I just use the table without a PK? I have tried turning it off for the email column but it does not allow me to.
Yes as you have defined email field as your primary, it can hold unique data only and no duplication allowed.
So you have two options:
1: Remove email field as a primary key
2: Add new integer field as a Primary key with auto increment (I would prefer this one)
You could use a natural primary key that would be a combination of Email + Date + Time + Action. That combination would be unique. It is impossible for the same user to do 2 different actions at the same time. That will help you to keep integrity of your information.
Hope this helps you.
To make a decision on a table' primary key one may start with considering these points (applicable to innodb):
How the data is going to be accessed after it is written (if you don't query it, why store it?). If you care about read performance you should query your data by the primary key, since for innodb primary key is the only possible clustered index.
The data is stored ordered by the primary key, so if you care about write performance, you should write data ideally ordered by your primary key, which always happens automatically if you have an auto_increment. Also table for which you don't explicitly specify a primary key are going to have a hidden auto_increment field which you won't be able to access, i.e. you get less for the same cost.

Choose primary key

I'm creating a table to track income and outcome. I have the following rows
type [can assume 3 values]
date [date of the transaction]
incomeAmout
incomeDescription
outcomeAmount
outcomeDescription
If I have date as primary then I won't be able to have multiple transaction in the same date. I could make all the rows as primary key but I'm not sure this is the best way to proceed. What would you suggest me to do? I read some topics about creating an auto incremental index but I'm wondering if I can make it without adding another attribute.
Thanks
Make an id column as a primary key. This will be your immutable record identifier.
You'll probably want to have some kind of randomized transaction identifier as well, something like a UUID or a value derived from the SHA256 hash of something. That way you can share these identifiers without revealing too much about your database structure or how many records there are in the database.
Then, if you need another key, add it as a UNIQUE index, or define whatever unique constraints you want to enforce as a compound key.
Your question should be: Surrogate Key vs. Natural Key
In your case, you have no choice but to use Surrogate Key: create a new field named "ID" and set it as Integer, Autoincrement, Primary Key.
BTW, Microsoft recommends use of Surrogate key as a good practice.

Does MySQL require a primary key for a many-to-many link table?

Note to Mod: I read through about a dozen posts that seemed to pertain to this issue, but none of them answered my question. Please do not flag this post for deletion; this is not a duplicate question.
I am building a database for a web-gallery that will contain many-to-many relationships. For example, tags and images. Obviously, to accomplish this a third, link, table will be created. I can see a use for having a primary key column in the tags table and the images table, but I can't imagine a use for it in the links table. It would just take up server space. So, I'm thinking of just not having a primary key column in the links table. Does MySQL allow this? Or, would there be any compelling reason to have a primary key in the links table? Thanks.
Link Table:
+--------------+---------+-----------+
| primary key? | tag ids | image ids |
+--------------+---------+-----------+
Clarification
Will not having a primary key in a table break the database?
There is no requirement that you have a primary key.
However, there is also no requirement that a primary key be only one field. In this case you might declare your primary key to be (tag_id, image_id).
You've got a question in reply to another post that gives me the idea that maybe you're thinking you should concatenate the two fields to make the primary key. Don't. Define the key as
alter table link add primary key (tag_id, image_id);
Do NOT say
alter table link add primary key (tag_id + image_id);
(I think "+" is the concatenation operator in MySQL. It's been a while. The SQL standard is "&" but MySQL uses that for something else.)
There's a big difference between the two, namely, in the first case, 25,34 and 253,4 are two different values, while in the second case they both get turned into 2534.
Will you always go from tag to image, or will you also want to go from image to tag? If you need to go in both directions, then you should create two indexes, or a primary key and an index, with the fields in both directions. Like:
create index link_tag_image on link(tag_id, image_id);
create index link_image_tag on link(image_id, tag_id);
If you make only the first (for example), then consider this query:
select tag.name
from image
join link on image.image_id=link.imagae_id
join tag on tag.tag_id=link.tag_id
where image.foo='bar'
This seems plausbile enough: find all the tags that match images that meet a certain condition. But without the second index, this query could take a very long time, because the db will have to read the entire link table sequentially to find all the records with a given image_id.
There is no need for primary key in the link table. Although a compound key is a good idea. Uniqueness can be achieved by using UNIQUE ( tag_ids, image_ids)
Yes, your primary key should be a compound/composite key of tag_id and image_id, i.e. PRIMARY KEY (tag_id, image_id). There's no need for an extra autoincrement column in this case.
When working with MySQL Workbench it's highly advisable because without a primary key it won't allow any access to your tables other than read only, which is a pain when trying to test your database. Although it does seem wasteful to have a PK that is never going to be referenced in a relationship.

Deal with table that's composite primary key I wanted to include a nullable column

Assume a table that may look like this:
userId INT (foreign key to a users table)
profileId INT (foreign key to a profiles table)
value INT
Say that in this table preferences for users are saved. The preference should be loaded according to the current user and the profile that the current user has selected. That means that the combination of userId and profileId is unique and can be used as a composite primary key.
But then I want to add the ability to also save a default value that should be used if no value for a specific profileId is save in the database. My first idea would be to set the profileId column to nullable and say that the row that has null as profileId contains the default value. But then I can't use a composite primary key that involves this table, because nullable columns can't be part of a primary key.
So what's the "best" way to work around this? Just drop the primary key completely and go without primary key? Generate an identity column as primary key that I never need? Create a dummy profile to link to in the profile table? Create a separate table for default values (which is the only option that guarantees that no userId has multiple default values??)?
Update: I thought about Dmitry's answer but after all it has the drawback that I can't even create a unique constraint on the two columns userId and profileId (MySQL will allow duplicate values if profileId is null and DB2 will refuse to even create a unique constraint on a nullable column). So with Dmitry's solution I will have to live without this consistency check of the DB. Is that acceptable? Or is that not acceptable (after all consistency checks are a major feature of relational DBs). What is your reasoning?
Create ID autoincrement field for your primary key.
AND
Create unique index for (userId, profileId) pair. If necessary create dummy profile instead of null.
Dmitry's answer is a good one, but since your case involves what is essentially an intersection table, there is another good way to solve this. For your situation I also like the idea of creating a default user profile that you can use in your code to establish default settings. This is good because it keeps your data model clean without introducing extra candidate keys. You would need to be clear in this dummy/default profile that this is what it is. You can give it a clear name like "Default User" and make sure that nobody but the administrator has access to the user credentials.
One other advantage of this solution is that you can sign on as the default user and use your system's GUI to modify the defaults rather than having to fiddle with the data through DB access tools. Depending on the policies in your shop, direct access to the data tables by programmers may be hard or impossible. Using the tested/approved GUIs for modifying defaults removes a lot of red tape and prevents some kinds of accidental damage to the data.
Bottom Line: Primary keys are important. In a transactional system every table should have a at least one unique index one of which should be the primary key. You can always enforce this by adding a surrogate (auto increment) key to every table. Even if you do, you still generally want a natural unique index whenever possible. This is how you will generally find what you're looking for in a table.
Creating a Default User entry in your user table isn't a cheat or a hack, it's using your table structure the way it's meant to be used and it allows you to put a usable unique contraint on the combination of user ID and profile ID, regardless of whether you invent an additional, arbitrary unique constraint with a surrogate key.
This is the normal behaviour of UNIQUE constrain on a NULL column. It allows one row of data with NULL values. However, that is not the behaviour we want for this column. We want the column to accept unique values and also accept multiple NULL values.
This can be achieved using a computed column and adding a contraint to the computed column instead default null value.
Refer below article will help you more in this matter:
UNIQUE Column with multiple NULL values
I always always always use a primary auto_increment key on a table, even if its redundant; it just gives me a fantastically simple way to identify a record I want to access later or refer to elsewhere. I know it doesn't directly answer your question, but it does make the primary key situation simpler.
create table UserProfile ( int UserProfileID auto_increment primary key etc.,
UserID int not null, ProfileID int );
Then create a secondary index UserProfileIDX(UserID, ProfileID) that's unique, but not the primary key.

Unique Constraint with conditions in MYSQL

In postgres we have a constraint defined that essentially allows us to limit the number of entries in a table with a certain value to one. We created this constraint:
create unique index list$default$uk on list_group(visitor_uid) where list_type = 'default';
Which means that the unique constraint is only applied when the list_type='default' so that there can only be one 'default' list per visitor in the table.
It looks like MySql doesn't support the additional where on the unique constraint. Is there another way to support this in the database schema for MySQL?
MYSQL doesn't support such types of constraints.
You should use stored procudures for inserting data instead, so you can do some checking and validation.
Why don't you define your default as such that it must have 1 as primary key? This way a normal unique constraint on the pk would be enough already.
If nothing fits to you, you could also consider changing your data model.
Actually it exists. Most contraints depend on the table Engine.
I think InnoDB supports this.
To do it, you have to add a UNIQUE index with the unique combination:
ALTER TABLE visitor ADD UNIQUE unique_default_visitor( visitor_uid, list_type );
I supposed you'd have to write a trigger to check for it.
I never use MySQL but maybe you can create an index like this:
CREATE UNIQUE INDEX list$default$uk ON list_group ((CASE WHEN list_type='default' THEN NULL ELSE visitor_uid END));
Explanation:
A unique index should not care about NULL values. Therefore, make sure the index expression returns NULL for every row where list_type <> 'default'.
My two cents:
why don't you create a column only to store the unique value (maybe you can call it something like is_list_type_default) and another to store all the values. If you do this, you can put a unique constraint on the first column.