I have a table with references from two of it's columns to two other tables PK's. Is there a way I can restrict both of those columns from having values set?
I only want one of them to have a value set, while the other is NULL
Favorites:
id
table_1_id
table_2_id
Table_1:
id
Table_2:
id
In SQL, you'd ideally handle this with a CHECK constraint.
In MySQL, there is not a direct mechanism to impose such a CHECK constraint. If you try to include one, the MySQL Reference Manual states (since it's part of the standard):
The CHECK clause is parsed but ignored by all storage engines.
Related
Is it possible to write a query like the one below?
UPDATE sale SET sale_order='123456789' WHERE **COLUMN_1** = 2
where I don't explicitly pass the column name? Only its position?
I could get the column names but I am trying to avoid querying the database only to get them.
Thanks.
To answer your question, no, there is no syntax in SQL to reference the column by its position. This goes back to relational theory, in the sense that a table is a set of columns, and members of a set are unordered.
You will either have to know the column name, or else query it from the database:
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA=SCHEMA() AND TABLE_NAME='sale'
AND ORDINAL_POSITION=1;
It looks like you are trying to design a query that updates a row by primary key, by assuming the first column is the primary key. The primary key isn't necessarily the first column. It isn't necessarily an integer. It isn't necessarily a single column.
So you are already making assumptions about the table definition. You might as well assume the primary key column is named id or some other convention.
When doing an INSERT INTO {tableA} SELECT a,b,c FROM {tableB} ON DUPLICATE KEY UPDATE x=y
What is the precedence on how the duplicate keys are evaluated? I assume that MySQL first checks to see if a tuple from tableB exists clashes with a unique/primary key in tableA. If the SELECT doesn't include a primary key, or if no other duplicate key exists, then each subsequent UNIQUE INDEX "group" is evaluated and the same checking is performed. But what happens if your tableB has multiple sets of unique, multi-column indexes? Are they evaluated top-to-bottom, as described by SHOW INDEXES FROM tableB ?
Here's my SHOW INDEXES FROM <table>:
Table,Non_unique,Key_name,Seq_in_index,Column_name,Collation
daily_metrics,0,PRIMARY,1,id,A
daily_metrics,0,unique_lineItem_creative_y_m_d,1,line_item_id,A
daily_metrics,0,unique_lineItem_creative_y_m_d,2,creative_id,A
daily_metrics,0,unique_lineItem_creative_y_m_d,3,year,A
daily_metrics,0,unique_lineItem_creative_y_m_d,4,month,A
...
Imagine there are additional sets of unique indexes similar to unique_lineItem_creative_y_m_d
The docs don't seem to illustrate this behavior.
https://dev.mysql.com/doc/refman/8.0/en/insert-on-duplicate.html
I also assume that the first matching unique index is used, if a match exists, without any attempt to match subsequent unique indexes that could match. In other words, the first unique index that matches is used, without regard for trying to find the best possible match across all indexes.
You are correct: as soon as MySQL detects a duplicate in any UNIQUE index, it abandons the INSERT and does the update.
The order in which MySQL evaluates the unique indexes does not change the outcome. There's no such thing as a better match for some unique index over another. Because they're unique indexes, any combination of column values that shows up as a duplicate is enough to completely specify the row to be updated.
MySQL's query planner, hopefully, chooses the index that's least costly to evaluate. But, formally speaking, the index it uses for this purpose is unpredictable. This unpredictability is an attribute of declarative languages like SQL. MySQL can do its work any way that works, and it doesn't have to tell you. It can be hard for programmers to grasp, because we're used to procedural languages.
If any primary or unique keys exist in tableB, that's irrelevant. The only thing that matters for INSERT...ON DUPLICATE KEY UPDATE are the primary or unique keys of the table you're inserting into — tableA in your example.
If the values you insert to tableA are already found in any of tableA's primary or unique keys, that triggers the UPDATE part of the IODKU.
It's about the values being inserted, not the constraints of the source table.
You can also trigger the UPDATE without using any source table -- just by inserting a VALUES() clause with a set of constants.
I have A table with almost 20 fields which several of those are Foreign Key that already has been indexed by Mysql, now I want to create a multi-indexes index that it contains 3 FK field,
First tried was based on Fields
ALTER TABLE `Add`
Add INDEX `IX_Add_ON_IDCat_IDStatus_IDModeration_DateTo_DateAdded`
(`IDCategory`,`IDStatus`,`IDModeration`,`DateTo`,`DateAdded`);
But I think it's better to have an index on indexes instead of fields but my following effort faced with error: Error Code: 1072. Key column 'FK_Add_Category' doesn't exist in table
ALTER TABLE `Add`
Add INDEX `IX_Add_ON_IDCat_IDStatus_IDModeration_DateTo_DateAdded`
(`FK_Add_Category`,`FK_Add_AddStatus`,`FK_Add_AddModeration`,
`IX_Add_DateTo`,`IX_Add_DateAdded`);
My question is is it possible to add an index on exists Indexes ( FK index in my case ) or not and there is the only way to create an index on Columns? if yes How I create that?
An index is an ordered list of values. It is used to make it more efficient to find rows in the table.
Think about the common, real-life, example of INDEX(last_name, first_name). It makes it easy to look up someone if you have their last name and first name. And sort of easy if you have only their last name.
But it is useless if all you have is their first name.
FOREIGN KEYs necessitate a lookup. Apparently you have a FK to AddStatus, since I see FK_Add_AddStatus. That FK generated a lookup for AddStatus. Think of that as being like a separate index on first_name. It is totally separate from the index on last_name & first_name.
5 columns is usually too many to put into a single index.
MySQL uses only one index for a given SELECT.
So, now, I ask, what SELECT might use that 5-column index? Please show us it. We can discuss whether it is useful, and whether the columns are in the optimal order.
I created Unique Compound Index:
Alter Table TableX Add Unique Index `UniqueRecord` (A,B,C,D)
The issue is that sometimes C can be NULL.
I noticed that
`Insert IGNORE`
Was still in some cases adding duplicate records and this turned out to be when those incoming records had C as NULL.
I tested the hypothesis that this was an issue by doing:
Select concat(A,B,C,D) as Index from TableA where C is NULL
And Index in each of those cases was in fact NULL. Once I remove the null field from the select:
Select concat(A,B,D) as Index from TableA where C is NULL
I get the expected string values vs nulls.
So the question is, other than doing an update like set C='' where C is NULL is there some way to set up the Index so that it works? I am loathe to simply make the Index A,B,D as that might introduce unwanted dupes when C in fact is not NULL.
Update:
I did try using IfNull in the Index creation but Mysql did not like that:
Alter Table TableA Add Unique Index UniqueLocator (A,B,IfNull(C,''),D
Mysql said:
[Err] 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 'C,''),D)' at line 1
Yes MySQL allows NULLs in unique indexes, which is the right thing to do. But you can define column C as NOT NULL if you don't like that.
MySQL -- but not all databases -- allow duplicate NULL values in unique indexes. I believe the ANSI standard is rather ambiguous on this point (or perhaps even contradictory). You basically have two choices.
The first is to define a default value for the column. This may not be appealing in terms of code, but it will at least generate an error on duplicate insert. For instance, if "C" is a foreign key reference to an auto-incremented id, then you might use -1 or 0 as the default value. If it is a date, you might use the zero date.
The other solution is a trigger, where you manually check for the duplicate values before doing an insert (or update).
Here is my problem:
The Key "idx_SR_u_Identity_FingerPrintProfile" is meant to constrain the fields "c_r_Fingerprint" and "c_r_Profile" to be unique.
It seems that I have done something wrong because all 4 entries in the table have identical values for those two fields. It is okay if two records have the same Fingerprint OR the same Profile, but not BOTH.
How can I correctly specify this unique key, so that such duplicates are not allowed?
(source: Rigel222.Com)
I think your key is correct, but MySQL does not apply it to NULL values. The MySQL Docs for CREATE TABLE state:
a UNIQUE index allows multiple NULL values for columns that can contain NULL.
While entries like (1,2) can occur only once, entries like (1,NULL) can occur several times, they are not considered to be duplicates because of the NULL.
Dependent on your use case, you may forbid NULL for the two columns to circumvent the problem.