I am generating a data template in C#. With the help of the good people on this wonderful site, I've managed to take care of almost every issue. This should be the last problem. Because it's a template I'm working on, I want every field in the table, including nulls. I was helped on how to update nulls by adding (object)this.field ?? DBNull.Value but I have a field that's a foreign key and even though when I look in the database it says null, when I pull the records the value becomes 0. When I try to update this field it says that I am violating foreign key constraints. How can I work around this problem? I thought the null solution would work but it doesn't show as null, it shows as 0.
Thanks
Is 0 a possible valid value for the column? If not, just typecast it to null when you encounter one. If it is valid you can still do that, by wrapping it in a conditional that checks the foreign row exists first.
In general it's not a good idea to allow FKs to be null. Some databases (I know oracle does this) enforce this by tying FKs to primary keys rather than columns in other tables. Could you refactor your tables not to need nulls for that column?
Related
Let's say I have a table like this:
CREATE TABLE dept (
id VARCHAR(255) NOT NULL PRIMARY KEY,
code VARCHAR(255) NOT NULL,
active BIT NOT NULL,
...
);
Problem:
I want to add a unique constraint on code column. But it should be applied only if active is set to true (uniqueness should be checked only among active records). There can be many records with active = false and the same code so I can't use constraint on multiple columns.
What I tried:
I haven't found any references in the documentation proving that such constraint is possible, but I know it is possible in other databases using unique function-based indexes.
Of course I can write a trigger that will check the invariant on every add/update operation, but I hope there is more efficient solution.
I'm using MySQL 5.7.15.
This simply isn't possible in MySQL, I'm afraid.
I have come "close" to solving this in the past by having a uniquely constrained column which is nullable (replacing both the active and code fields). When NULL - it's "inactive", when anything other than NULL - it has to be unique.
But that doesn't precisely solve the problem you're asking. (Perhaps something better can be suggested if you could update your question to include the bigger picture?)
Otherwise read/write to the table through a stored procedure or - as you've suggested yourself - do something inelegant with triggers.
To solve your problem you need use CHECK clause but it MySQL don't support it. From doc:
The CHECK clause is parsed but ignored by all storage engines. See Section 13.1.18, “CREATE TABLE Syntax”. The reason for accepting but ignoring syntax clauses is for compatibility, to make it easier to port code from other SQL servers, and to run applications that create tables with references.
So you can do this only by check data on application level or insert/update rows in this table by stored procedures.
I sorry this does not really a direct answer your question but:
Maybe you are better off with a different table design? The fact that something you want to do is not supported by your RDBMS is always a strong evidence that you are using it wrong.
Have you thought about creating a dept and an dept_history table, dept containing only the active records? That would solve your problem with the unique constraint.
I am creating two tables in a database in MySQL just so I can play around with SQL and learn more, as I am a novice. I have read several questions on Stack relating to inserting a new row, and updating an existing row. My question is a little different, hopefully it won't be considered a dupe as none of the other answers I read gave me the full explanation I need because I think it's the auto-increment part that's confusing me. I don't think I can just go in and assign a new value for the primary keys in one of the tables with auto-increment set up, can I?
I have two tables: english_words and spanish_words. Their primary keys are respectively eng_id and span_id, and are set up to auto-increment. My hope had been to practice SQL and eventually get things set up enough so that I can practice my joins later on. For now, in english_words, I entered a duplicate row by mistake, with the ID 7. I deleted that row, and of course it now goes "6...8..." ..... and when I created my spanish_words table, I forgot all about the missing row 7. I'd hoped to keep everything very simple and aligned between the two tables until I'm ready for more complex endeavors later. Is there a way I can either:
Bump row 7 (and all subsequent rows) down by one in my spanish_words (so 7 becomes 8, 8 becomes 9, etc)
OR
Pull up everything after row 6 in english_words?
OR
Is there a better solution than either of those that you could suggest?
It's possible there's not a way. Originally I'd thought of trying to UPDATE the row 7 data in english_words or maybe insert a new row, but in my research I found an answer on Stack that said you can't insert data into a specific row in the table...and then I realized that's not going to fix anything anyway.
Do those of you more experienced with SQL have any ideas? (Aside from not making such silly mistakes anyway).
Additionally, I'm open to scrapping my tables and starting again, if there's a best-practice that I'm missing. Would setting up a foreign key to correspond between the two tables be a way to fix this? I'm pretty sure you have to do that anyway to perform the joins, but I was going to cross that bridge when I get there. What is best practice amongst database admins - set up foreign keys early on, or later when you need them?
Thanks in advance for your guidance.
A better way to set this up is to create a relation table:
CREATE TABLE translation (
eng_id int,
span_id int,
FOREIGN KEY (eng_id) REFERENCES english_words (eng_id),
FOREIGN KEY (span_id) REFERENCES spanish_words (span_id)
)
This is better than using a foreign key in the original tables, because you can't have bidirection foreign keys (you have to create the referenced row before the referencing row, so whichever table you insert into first can't have a foreign key pointing to the other one).
I can see that there are similar questions and answers on SO regarding this problem.
I need to create a unique constraint on 7 columns together.
alter table ga_data_model add constraint uq_1234596 unique (portal_id,date,dimension,country,os,os_version,theme);
there has been various answers to use prefix keys to solve this issue. However, because of the nature of my data, simply using the first one or two character to create the index is dangerous as this might result in having duplicate results. So such a solution won't work for me:
alter table ga_data_model add constraint uq_1234596 unique (portal_id,date(2),dimension(2),country(1),os(2),os_version(1),theme(2));
I was thinking of creating a new column in my table that contains the calculated hash of these columns and I create my constraint on this one. But this means that every time I want to insert something into db, I need to first do a select for this column, calculated the hash for the new values, compare them and save/or not save. I think this is a bit too expensive, considering that I will be having a lot of write operations.
Has anyone had the same problem and have a better solution as I explained above?
Thanks!
I want to insert something into db, I need to first do a select for this column, calculated the hash for the new values, compare them and save/or not save
No - you save it, and if you get a unique key violation then you already have the data. Also, implement the hash calculation as a table trigger - that way there's no backdoor for amending the data.
How to rearrange primary key column values after deleting some rows from a table in MySQL?
Foe example; a table with 4 row of data with primary key values 1,2,3,4. When delete 2nd and 3rd rows, then the key value of 4th row change to 2.
Please help me to find solution.
Why do this? You don't need to rearrange your key since it's only number, identifier for record. It has no actual meaning - so let DBMS handle that. This is a very common mistake - trying to take DBMS role.
However, I'll answer your question for common case. In MySQL you can rearrange column with:
update t cross join (select #cur:=0) as init set t.col=#cur:=#cur+1
-this, however, can't be used with column under UNIQUE (so primary key as well) restriction since during update you'll possibly get duplicate records. You should drop restriction first before do that (and create it again after update).
One method is THIS ONE.
Other then that, you can simply drop the table which is primary and then again create it. This will do the job
Why do you want to change primary keys for your data? In general this is bad idea to do that, especially when integrity contstraints comes into the game. If you need to do such thing, I would say you have bad DB desing and you should take closer look on that aspect.
When I am using Foreign Keys in MySQL, I will get an error if the source value is 0 (because there is no target record with ID 0). Therefore, I am changing the source column to be NULL, and then it works. However, I am not sure if this is the right way this should be done. Is it the right way, or can I somehow keep the source ID set to 0 instead of NULL?
Foreign keys are constraints. This means that if the value of the column that has the foreign key is set to anything (and "anything" does not include NULL), that value must exist in the referenced table or MySQL will throw an error.
So, in short, you can either set the value to NULL, remove the foreign key constraint and set the value to whatever you desire, including 0, or add a record with a 0 in the referenced table. Of these options setting the value to NULL seems the cleanest.
It is the right way. 0 is a value and null says that there is nothing in the column.
Yes, this is the right way. The whole point of an FK is to enforce that a record with the referenced ID actually exists. So if you set the FK column to 0, there must be a record with ID 0.
The only way around this is to make the FK column NULLable, as you did.
At any rate, why would you want to set the FK column to 0? The canonical value for "does not exist" in SQL is NULL.
using a NULL is better than zero for two reasons. first, it's clearer that it's a "special" value (there's nothing that forces table ids to always be non-zero, although it is often true for auto-generated ids), and second it works in SQL with the foreign key constraint.
so what you are doing is common practice - many people use NULL as a marker that says "missing value", and that's what SQL's foreign key constraint expects.
another way to handle missing values is to use a third "link" table that has an entry only if there is a connection between the two classes (as you would do in a many-to-many relation). this avoids the need for a NULL, and so is preferred by some database purists, but makes everything more complex. see Nullable Foreign Key bad practice? for more discussion.
Yes, this is the right way and the correct pattern to use in those cases.
As stated, what is indicated in those structures is to leave the column as null, indicating the line would not be linked to any counterpart in the foreign table. It whould not be considered "right" in database teories, but is a very used pattern, so, its not actualy considered "wrong" by the most of database designers. I gues you could say its the kind of pattern you try not to look to when trying to find mistakes in the structure.
The pattern is considered incorrect because it is expected to use a non-null column in a primary key and in this sense the columns in the table that will receive the key must be identical to the primary column of the table, that is, they would never be null. However, in most databases physically, there are no impediments to creating a different column, which makes the null value possible.
The problem with this architecture is when the table gets too big, when, p. eg, it have more than 1000 lines (yes, the "big" would be that low!), in these situations, specially in a small infrastructure, the answer time starts to get too long and "questionable". It happens that null records can not be part of indexes and the algorithm ends up doing a full scan. Therefor this type of pattern is implemented when we know the table will always be verry, verry small! Otherwise, I recommend use the pattern creating an external table where the "null" option in your case would be a "not found" in this other table.