Check uniqueness for multiple attributes in SQL - mysql

I am having a table of the form ID, MID,PID. Now, for the table ID is the primary key. and I might come across inserting same combination of MID,PID , but I shouldn't add them. Here ID is something which needs to be generated and can't be obtained or crawled. Is there any mechanism in SQL to check for uniqueness of the combination.
I an thinking of generating ID with auto increment, so it being primary key can't help here,another option I am thinking is, concatenate MID and PID and then set them as primary key. Else I could check if the data exists with a select command and then do the same. But all these kind of defeats the purpose, or to say the least not elegant. Are there any other methods?
Will creating a constraint serve it?

Yes, adding a (composite) uniqueness constraint is exactly what you want:
ALTER TABLE my_table ADD UNIQUE (MID, PID)

Related

How do I make a field reference another field which is not a primary key in MySQL?

I know that foreign keys need not reference only primary keys but they can also reference a field that has a unique constraint on it. For my scenario, I am setting up a quiz where for each test, I have a set of questions. My table design is like this
The point is, in my 2nd table where I will put all the answer options, I want the question number field to link to the first table question number. How do I do this? Or is there an alternative to this design?
Thank you
Ideally there should be a question_id primary key column in the test_question table, and you would use this as the foreign key in the test_answer table.
With your composite primary key in the test_question table, you should make a corresponding composite foreign key:
CONSTRAINT FOREIGN KEY (test_id, question_no) REFERENCES test_question (test_id, question_no)
This is in addition to the foreign key just for the test_id column.
Add another table purely for answers, and link them via the question_no field.
A DB table should hold information on one sort of item. Questions and answers are separate sorts of information so should be in separate tables. Adding a separate table also allows changes to questions and answers independently. Additionally, if they are separate, you could add a language field to each table and have a multi-lingual quiz
Short answer:
You can JOIN on any columns or expressions. There is no "requirement" for a FOREIGN KEY, PRIMARY KEY, UNIQUE, or anything else.
Long answer:
However,... For performance (in large tables), some things make a difference.
If you are JOINing to a PK, Unique key, or even an indexed column, the query cold run faster.
Why have a FOREIGN KEY? An FK is two things:
A "constraint" that says that the value must exist in the other table. Also, with things like ON DELETE CASCADE, it can provide actions to take if the indicated row is removed. The constraint requires looking in the other table each time a write occurs (eg INSERT).
An Index. That is, specifying a FK automatically adds an INDEX (if not already present) to make the constraint faster.
Getting the id
Here is the "usual" way to do a pair of inserts, where you need the second to 'point' to the first:
INSERT INTO t1 ... -- with an AUTO_INCREMENT id
grab LAST_INSERT_ID() -- that id
INSERT INTO t2 ... -- and include the id from above
For AUTO_INCREMENT to work it must be the first column of some key. (Note: a PRIMARY KEY is a UNIQUE is a key (aka INDEX).)
Optionally you can specify a FK on the second table to point out the connection between the tables.
And, as spelled out in other answers, a FK could involve more than one column.
Entities and Relations
Sometimes, a set of tables like yours is best 'designed' this way:
Determine the "entities": users, tests, questions, answers
Relations and whether they are 1:1, 1:many, or many:many... Users:test is many-to-many; tests:questions is 1:many (unless you want questions to be shared between tests).
Answers is more complex since each 1 answer depends on the user and question.
1:1 -- rarely practical; may as well merge the tables together.
1:many -- a link (FK?) in one table to the other.
many:many -- need a bridge table with (usually) 2 columns, namely ids linking to the two tables.

is it possible to allow delete query only if there is primary key in where clause?

My use-case is to delete a row from the table only with the unique key (or Primary key) to assure that the right data is getting deleted.
I want to prevent delete queries if there are fields other than the Primary key or unique key.
Let's say 'id' is the auto-incremented primary key in my table than,
delete from my_table where id = 10
This should work but,
delete from my_table where first_name = "John"
this should be blocked for all users of MySQL. can we achieve this just with MySQL? I know, I can add multiple checks with my backend language in my logic part but I want to check if it is possible to handle on MySQL part?
Your approach is flawed because I can trick MySQL into thinking that I am using a primary key like so --
DELETE FROM table WHERE id <> 0;
In fact, MySQL does almost have such a mode. It is implemented using sql_safe_updates. Specifically:
If this variable is enabled, UPDATE and DELETE statements that do not use a key in the WHERE clause or a LIMIT clause produce an error.
The definition of "key" here may not match your definition of a key.
You can refer to the documentation for more information.
You can set this when you start the MySQL client using --safe_updates or by running:
set sql_safe_updates=1;

Faster selects when using GUID vs. Select WHERE?

I have a table with thousands of records. I do a lot of selects like this to find if a person exists.
SELECT * from person WHERE personid='U244A902'
Because the person ID is not pure numerical, I didn't use it as the primary key and went with auto-increment. But now I'm rethinking my strategy, because I think SELECTS are getting slower as the table fills up. I'm thinking the reason behind this slowness is because personid is not the primary key.
So my question, if I were to go through the trouble of restructuring the table and use the personid as the primary key instead, without an auto-increment, would that significantly speed up the selects? I'm talking about a table that has 200,000 records now and will fill up to about 5 million when done.
The slowness is due indirectly to the fact that the personid is not a primary key, in that it isn't indexed because it wasn't defined as a key. The quickest fix is to simply index it:
CREATE UNIQUE INDEX `idx_personid` ON `person` (`personid`);
However, if it is a unique value, it should be the table's primary key. There is no real need for a separate auto_increment key.
ALTER TABLE person DROP the_auto_increment_column;
ALTER TABLE person ADD PRIMARY KEY personid;
Note however, that if you were also using the_auto_increment_column as a FOREIGN KEY in other tables and dropped it in favor of personid, you would need to modify all your other tables to use personid instead. The difficulty of doing so may not be completely worth the gain for you.
You can to create an index to personid.
CREATE INDEX id_index ON person(personidid)
ALTER TABLE `person ` ADD INDEX `index1` (`personid`);
try to index your coloumns on which you are using where clause or selecting the coloumns

Getting underlying Primary Key in MySQL (InnoDB)

It is my understanding that when I make a table without a primary key that MySQL creates a sort of underlying primary key that it uses internally.
I am working with a table that does not have a primary key, but it would be very useful for my application if I could somehow access this value, assuming it does in fact exist and is retrievable.
So, I am wanting to know if I am correct in believing that such a value exists somewhere and also if it is possible to get that value.
Edit: just to make it clear, it would be very useful for my application for this table to have an incrementing int attribute. Unfortunately, it was not implemented that way. So, I am sort of grasping at straws to find a solution. What I am trying to do is select every nth row in the table (n changes). So, as you can see if there was this key, this would be very simple.
If a table has no primary key then there's no way of specifying a specific row within it because there is no way to uniquely identify an item. Even if you use a query that specifies a specific value for every column that still wouldn't be certain to only return a single row as without a primary key there's nothing to prevent duplicate rows.
However, a primary key is simply a unique index. If a table has a unique index on one or more of its columns and those columns don't accept NULLs then this is the primary key for the table in all but name.
If you table has no unique columns then you've got nothing to go on. You'll have to either make one column or combination of columns (for a composite key) unique, or add a column that serves as the primary key for the table. Fortunately it's relatively easy to add columns to a MySQL table, just add a primary key autoincrement column to the existing table.

MySQL INSERT/UPDATE without ON DUPLICATE KEY

I may have either misunderstood how to use the ON DUPLICATE KEY syntax, alternatively my database structure needs some work but here goes.
I have a table (bookings-meta) which represents meta data associated with another table (bookings) , different rows in the bookings table may or may not have specific meta data associated with them in the other table.
The bookings-meta table has the following columns, meta_id (primary key), booking_id, key and value.
From my understanding, to use ON DUPLICATE KEY I need to know what in this case is the meta_id, often this isn't the case, I'm trying to simply push a key, value pair to the table using the booking_id, so if the particular key exists then its replaced otherwise its inserted.
At the moment I have a seperate query to try to select the row, if its found then I UPDATE, if not then its an INSERT.
Is there a way of doing an insert/update in one query without using ON DUPLICATE KEY or have I missed a trick with this one?
If possible, I'd drop the meta_id column entirely and turn booking_id and key into a composite primary key. That'll save space in your table, allow use of ON DUPLICATE KEY, and be cleaner in general.