Coexistence of two columns SQL - mysql

I am new in SQL (Yes, just 1 week) and I am learning this on my own. So, I really need help in solving this problem:
How do I set a column (in a table) to be NULL when another column is also NULL?
Example:
A person table with Name and Gender as its columns. In order to have a gender, the 'Name' column must also have an entry. If the Name is NULL, then do not allow insertion under Gender.
Oh and yes, this is related to my homework question but I have modified the example above to be different. I don't want answers (although they're welcomed, but I want to learn), I just want guidance. Thanks in advance.

SQL supports a feature called "check constraints" so that you can declare an expression that must be true or else the row is invalid and can't be inserted. I.e. CHECK Name IS NULL AND Gender IS NULL OR Name IS NOT NULL AND Gender IS NOT NULL.
But unfortunately, MySQL doesn't support check constraints. Many features of SQL are optional from the standard's perspective and not all RDBMS implementations support all features. There are even a few features of SQL that none of the brands of RDBMS support.
The only way to do this in MySQL is to use a trigger. Before insert or update, if Name is null, then force the Gender to be null as well.
If Name is not null and Gender is null, then I assume the row is invalid, so you'll have to use a signal to abort the insert or update.

A stored procedure written to insert values into table can help you with this. Please see below example code:
CREATE PROCEDURE InsertIntoTable
(
#NAME NVARCHAR(20) = NULL,
#GENDER NVARCHAR(20) = NULL
)
AS
BEGIN
DECLARE #NewGender NVARCHAR(20)
IF(#NAME IS NULL)
SET #NewGender = NULL
ELSE
SET #NewGender = #GENDER
INSERT INTO Table1 VALUES(#NAME, #NewGender)
END

Related

In MySQL, when I alter a table and add a new attribute with constraint not null, it still accepts null when I use update

I am using MySQL, I have a table called student as given below,
Name Idnumber
'tony' 1
'jimmy' 2
I am going to add one more column using the below query
alter table student add location varchar(20) not null;
Now, if I use the query,
update student set location=null where name='tony'
the value of null is being inserted into the table. Below was the table I got.
Name IdNumber location
'tony' 1 null
'jimmy' 2
Since I had set location as not null while altering the table, why is it still accepting null? Also, if I tried to insert null using,
insert into student(Name,IdNumber) values('robert',3);
the query is not demanding a not null value for location. 'Not Null' constraing is only working when I use the query,
insert into student (Name,IdNumber,location) values('john',8,null);
Please tell my why 'not null' constraint is not working in the other cases described above.
Thanks,
Vivek G

SSIS default value is not being set when source value in null

Problem:
OLEDB source has null value in phone.
Destination table has Phone NOT NULL DEFAULT 1234567.
OLEDB destination has Keep Nulls unchecked
According to what I read here https://msdn.microsoft.com/en-us/library/ms187887(v=sql.110).aspx
The default value for the column should be inserted if incoming value is NULL.
But it's not happening. And I don't want to do any transformation in SSIS. Can someone help?
In your Data Flow Task, in OLE_DB source, set the data access mode to 'SQL command' and write out a select statement as below
SELECT Column_A
,Column_B
,ISNULL(Phone, 1234567)
,Column_C
,Column_D etc.
FROM Source_Table
you can write CASE statement in SQL command in Data Flow Task:
select
CASE
when PhoneNumber IS NUll then '1234567' else table_name.PhoneNumber END as PhoneNumber,
from table table_name
I believe the answer is that for Keep Nulls option to work the column has to be missing from the data source.
create table #tmpdel
(
a INT NOT NULL default 0,
b INT NOT NULL default 0
)
Insert into #tmpdel(a) values(1) - WORKS
Insert into #tmpdel(a, b) values(1, null) - FAILS

MySql Basic table creation/handing

I'm trying to create a simple table where I insert field and I do some checks in MySql. I've used Microsoft SQL relatively easy. Instead, MySql give evrrytime query errors without even specifying what's going on. Poor MySql software design apart, here's what I'm trying to do:
1 table with 4 fields with an autoincremental autogenerated number to det an ID as primary key
CREATE TABLE `my_db`.`Patients_table` (
`ID_Patient` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`Patient_name` VARCHAR( 200 ) NOT NULL ,
`Recovery_Date` DATETIME NOT NULL ,
`Recovery_count` INT NOT NULL
) ENGINE = MYISAM
a simple stored procedure to insert such fields and check if something exist before inserting:
CREATE PROCEDURE nameInsert(IN nome, IN data)
INSERT INTO Patients_table (Patient_name,Recovery_Date) values (nome,data)
IF (EXISTS (SELECT Recovery_count FROM Tabella_nomi) = 0) THEN
INSERT INTO (Patients_table (Recovery_count)
ELSE
SET Recovery_count = select Recovery_count+1 from Patients_table
END
this seems wrong on many levels and MySQL useless syntax checker does not help.
How can I do this? Thanks.
There seems to be a lot wrong with this block of code. (No offense intended!)
First, Procedures need to be wrapped with BEGIN and END:
CREATE PROCEDURE nameInsert(IN nome, IN data)
BEGIN
...[actually do stuff here]
END
Second, since your table is declared with all fields as NOT NULL, you must insert all fields with an INSERT statement (this includes the Recovery_Date column, and excludes the AUTO_INCREMENT column). You can add DEFAULT CURRENT_TIMESTAMP to the date column if you want it to be set automatically.
INSERT INTO Patients_table (Patient_name,Recovery_Date) values (nome,data)
Third, what exactly is your IF predicate doing?
EXISTS (SELECT Recovery_count FROM Tabella_nomi) = 0
If you want to check if a row exists, don't put the = 0 at the end. Also, Tabella_nomi isn't declared anywhere in that procedure. Also, your SELECT statement should have a WHERE clause, since I'm assuming you want to select a specific row (this is going to select a result set of all recovery_counts).
Fourth, the second INSERT statement seems a little messy. It should look more like the first INSERT, and keep the point I made above in mind.
INSERT INTO (Patients_table (Recovery_count)
Fifth, the ELSE statement
SET Recovery_count = select Recovery_count+1 from Patients_table
Has some problems too. SET is meant for setting variables, not values in rows. I'm not 100% sure what your intent is from this statement, but it looks like you meant to increment the Recovery_count column of a certain row if it already exists. In which case, you meant to do something like this:
UPDATE Patients_table SET Recovery_count = Recovery_count+1 WHERE <conditional predicate>
Where the conditional predicate is something like this:
Patients_name = nome
Try these things, and look at the errors it gives you when you try to execute the CREATE STATEMENT. I bet they're more useful then you think!

Mysql restrict value of a field to be one of the defined ones

I am using mysql database.
I have a field user_type in USER table. I would like to restrict the values in this field to be one of ('ADMIN','AGENT','CUSTOMER').
The insert statements should fail if they tried to insert anything else than the above possible values. Also, I need defaulting to 'CUSTOMER' is none is specified in the insert statements.
The possible solution I could think of is use of triggers, but I would like to know How this could be handled more efficiently (possibly in the create table ddl itself?).
Any ideas, How to do this?
This is what the column type "enum" is for. You treat it like a string, and behind the scenes it is stored as an int, and must be one of the values defined in the DDL:
CREATE TABLE users (
id int unsigned NOT NULL auto_increment primary key,
user_type enum('ADMIN', 'AGENT', 'CUSTOMER') NOT NULL default 'CUSTOMER'
)
Then insert like so:
INSERT INTO users (user_type) VALUES ('ADMIN'); // success
INSERT INTO users (user_type) VALUES ('ANONYMOUS'); // failure (or '' if not "strict" mode)
INSERT INTO users (user_type) VALUES (default(user_type)); // uses default
INSERT INTO users () VALUES (); // uses default
INSERT INTO users (user_type) VALUES (NULL); // failure
note
Note that for the query to actually fail, you must use "SQL strict mode". Otherwise, an "empty string" value (which is slightly special in that it has the numeric value of 0) is inserted.
Quoting this docs page:
When this manual refers to “strict mode,” it means a mode where at least one of STRICT_TRANS_TABLES or STRICT_ALL_TABLES is enabled.
I came across this post, and as it dates somewhat back, I was thinking of others coming across it these days too and miss the (in my opinion) simpler approach of simply adding a CHECKconstraint (e.g. this for MySQL, or this for MariaDB).
In my opinion, using a CHECK constraint is much easier than using things like ENUM and / or SET as you don't need to worry about the relations to integer indexes etc. when relying on them. They for example can become weird when you try to preset allowed integer values for a column.
Example, where you want to have a column which has values ranging from 1 to 5:
CREATE TABLE myTable (
myCol INT NOT NULL
CONSTRAINT CHECK (0 < `myCol` < 5)
);

MySQL make two columns UNIQUE

Don't know if this is possible for MySQL because I know that it doesn't support check constraints, but what I want is to make two columns unique. Before you answer with
ALTER TABLE <table_name> ADD UNIQUE(<col1>, <col2>);
That's not what I want. I would like to ensure that col1 and col2 have unique values so if they are INTs, number "1" can exist only once between both columns, which means if col1 contains "1", col2 cannot contain "1" and "1" can only appear once in col1. Hopefully that makes sense.
I know I can do it from a php level, but right now there is a lot of code, and if I miss a spot, I don't want to destroy data integrity; I rather throw an error from the database. Some ideas that I've come across is using triggers. If someone can give me an example of using triggers to accomplish this, that would be great.
UPDATE
It might help if you knew what I was doing, then maybe you can propose a better way of doing this:
I have two fields, email and new_email. When someone changes their email address, I store it into the new_email field until the accept the change. Since email is unique because it's used as their login, I HAVE to ensure that the email is unique across both fields.
Solution
Create a table MakeColsUnique with one column ColumnBoth
Create a Primary Key on ColumnBoth
All all values from Col1 and Col2 to this table (if you have existing duplicates, this will fail)
Add a trigger on OriginalTable on INSERT or UPDATE to insert the value from Col1 and Col2 into the new table MakeColsUnique
If the value has already been inserted, the insert or update will fail.
I think you should try to reorganize your database. Let's say currently you have this:
Table: users
id name email new_email
102 foo foo#mail.com foo2#mail.com
103 bar bar#mail.com bar2#mail.com
104 baz baz#mail.com NULL
This could be changed to:
Table: users
id name
102 foo
103 bar
104 baz
Table: emails
user_id is_new email
102 0 foo#mail.com
102 1 foo2#mail.com
103 0 bar#mail.com
103 1 bar2#mail.com
104 0 baz#mail.com
You can then add a unique index on the final table on the column email.
You can't enforce that with a key constraint. Honestly the requirement sounds a little bit odd, and I think you're probably better off extracting col1 and col2 into a separate table, say cols.
As per you update on the question a database constraint is not a valid option, because you want to store the email for a while in both the fields and then accept it once the user accepts it. It looks more like a logic that needs to be implemented in the application business logic than the database
Have you solved your problem? I have encountered this problem too, and finally I solve my problem with trigger, following your idea. Here is my sql:
delimiter |
CREATE TRIGGER unique_AB BEFORE INSERT ON test
FOR EACH ROW
BEGIN
DECLARE msg varchar(200);
DECLARE flag int;
set flag = (select count(*) from test where A = new.A or B = new.A or A = new.B or B = new.B);
IF flag > 0 THEN
set msg = "column duplicate!!!";
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = msg;
END IF;
END;
|
my table is as follow:
CREATE TABLE `test` (
`A` varchar(255) DEFAULT NULL,
`B` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
in the trigger, I made a select first and judge if there is already a value that is equals to my new line, and this worked for me.