I need to validate data in a Table where 1 column has multiple values but 1 value can only be present in 1 row by unique key - sql

Example:
A table Keyed by Unique Name and Email Address with a column for Type
The Type column can have Original, Work, Personal
where you can have multiple work and personal emails but only 1 Original email
I am using DB2 for i SQL and I want to constrain the data using UNIQUE or CHECK constraints but not sure how I can do this data set.
Scott scott#hotmail.com Original
Scott scott#gmail.com Personal
Scott scott#live.com Personal
Scott scott#NBC.com Work
Scott scott#ABC.com Work
Scott scott#yahoo.com Original
I want to identify that I cant have yahoo as Original if I already have hotmail as original.
the rest are valid.
Let me know if I need to add more.

If you have Db2 for IBM i, then you may create a UNIQUE INDEX with the corresponding WHERE clause.
CREATE TABLE TEST_IND_EXPR
(
NAME VARCHAR (20) NOT NULL
, EMAIL VARCHAR (20) NOT NULL
, TYPE VARCHAR (20) NOT NULL
);
CREATE UNIQUE INDEX TEST_IND_EXPR1 ON TEST_IND_EXPR (NAME, EMAIL);
CREATE UNIQUE INDEX TEST_IND_EXPR2 ON TEST_IND_EXPR (NAME, TYPE) WHERE TYPE = 'Original';
INSERT INTO TEST_IND_EXPR VALUES ('Scott', 'scott#hotmail.com', 'Original');
INSERT INTO TEST_IND_EXPR VALUES ('Scott', 'scott#gmail.com', 'Personal');
INSERT INTO TEST_IND_EXPR VALUES ('Scott', 'scott#live.com', 'Personal');
INSERT INTO TEST_IND_EXPR VALUES ('Scott', 'scott#yahoo.com', 'Original');
The last statement returns SQL0803 as this row violates uniqueness of the TEST_IND_EXPR2 index.

Related

PostgreSQL to find the next available value

I have followed the example here to find the next available value on a table column: the generated value will be used by an application to insert data in another table. But, if multiple concurrent application instances run the same query, some of these instances could get the same value. How could I avoid these collisions without change the application? Is it possible write a PostreSQL function to handle this task?
You can use an IDENTITY column or a SEQUENCE.
Identity Column Example
create table t (
id int primary key not null generated always as identity,
name varchar(10)
);
insert into t (name) values ('New York');
insert into t (name) values ('Chicago');
Result:
id name
--- --------
1 New York
2 Chicago
Each INSERT statement will produce a different value for the id column, even when they are executed on separate simultaneous threads.
Sequence Example
create table u (
id int primary key not null,
name varchar(10)
);
create sequence sequ;
insert into u (id, name) values (nextval('sequ'), 'New York');
insert into u (id, name) values (nextval('sequ'), 'Chicago');
Result:
id name
--- --------
1 New York
2 Chicago
Again, each INSERT statement will produce a different value for the id column, even when they are executed on separate simultaneous threads.
See running example for both cases at DB Fiddle.

Copying two columns from a foreign table into another table

INSERT INTO Confirmed (TotalDeaths, Population)
SELECT TotalDeaths, Population
FROM Deaths
WHERE UID IS NOT NULL;
Copy the values for the columns named TotalD and Pop from the Deaths Table to the Confirmed Table (same names, both contains UID primary Key)
Failed to execute query. Error:
Cannot insert the value NULL into column 'UID', table 'dbo.Confirmed'; column does not allow nulls. INSERT fails. The statement has been terminated.
I keep running into a problem where I get compiler errors due to the primary key not allowing nulls. I'm not sure where the null keys are even coming from when it shouldn't be null to begin with.
Both tables have very similar columns, but in this case all that needs to be mentioned is that there are three columns in both tables that are crucial, which are: UID int NOT NULL, TotalDeaths int NOT NULL, Population int NOT NULL.
Seems to be UID is not null column. Use below query
INSERT INTO Confirmed (UID, TotalDeaths, Population)
SELECT UID, TotalDeaths, Population
FROM Deaths
WHERE UID IS NOT NULL;

Swap data in two columns using single sql query

User has entered data in wrong columns.
For example, I have a table with two columns applicant name and father name. Data operator has entered father name in applicant name column and applicant name in father name column. Please suggest a way to swap the data in both columns i.e data in applicant name column should move to father name column and data in father name column should move to applicant name column. Using single sql query
It may sounds funny, But you can easily alter the table and change the column name with correct labeling.
CREATE TABLE `swap_test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`x` varchar(255) DEFAULT NULL,
`y` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
INSERT INTO `swap_test` VALUES ('1', 'a', '10');
INSERT INTO `swap_test` VALUES ('2', NULL, '20');
INSERT INTO `swap_test` VALUES ('3', 'c', NULL);
Solution would be :
UPDATE swap_test SET x=(#temp:=x), x = y, y = #temp;
More info can be found here.
You can simply assign the names
update the_table
set applicant_name = father_name,
father_name = applicant_name
where ...; -- make sure to only do that for the rows that need it
The SQL standard requires that the values used on the right side are evaluated before the assignment.
This works with every modern DBMS, but not with MySQL. See dexter's answer if you need a workaround for MySQL.
Online example: https://rextester.com/RIK34525

SQL set UNIQUE only for two columns

I would like for example that user can add name JHONE and age 25, so next time he can add JHONE, 26 or ALEX 25, BUT not JHONE, 25 again.
So I'm looking for two column unique NOT separately.
P.S. I'm sorry if same question was mentioned before.
EDIT:
This is my example:
Would like to make userIdG and doWithCar will be like this
102163096246025413003 View
102163096246025413003 Buy
102163096246025413003 Let
102163096246025413003 Sell
And for Id = 102163096246025413003 you can't add any more values, BECAUSE column doWithCar will have only 4 possible choice view, buy, rent and sell
You could specify more than one column in UNIQUE:
CREATE TABLE tab(ID INT IDENTITY(1,1) PRIMARY KEY, name VARCHAR(100), age INT
,UNIQUE(name, age));
INSERT INTO tab(name, age) VALUES ('John', 25);
INSERT INTO tab(name, age) VALUES ('John', 26);
-- INSERT INTO tab(name,age) VALUES ('John', 25);
-- Violation of UNIQUE KEY constraint 'UQ__tab__CF0426FD76D3370A'.
-- Cannot insert duplicate key in object 'dbo.tab'.
-- The duplicate key value is (John, 25).
-- The statement has been terminated.
SELECT * FROM tab;
LiveDemo
Note:
You should store date of birth and not age itself (or make age calculated column and set UNIQUE(name, dob)).
this is what I do not understand) how database will know that it should be two columns as unique and not each column is unique
These are different concepts. DB "knows" it from UNIQUE constraint definition:
UNIQUE(userIdG,doWithCar) -- pair of column is unique
!=
UNIQUE(userIdG),UNIQUE(doWithCar) -- each column is unique

SQL can I have a "conditionally unique" constraint on a table?

I've had this come up a couple times in my career, and none of my local peers seems to be able to answer it. Say I have a table that has a "Description" field which is a candidate key, except that sometimes a user will stop halfway through the process. So for maybe 25% of the records this value is null, but for all that are not NULL, it must be unique.
Another example might be a table which must maintain multiple "versions" of a record, and a bit value indicates which one is the "active" one. So the "candidate key" is always populated, but there may be three versions that are identical (with 0 in the active bit) and only one that is active (1 in the active bit).
I have alternate methods to solve these problems (in the first case, enforce the rule code, either in the stored procedure or business layer, and in the second, populate an archive table with a trigger and UNION the tables when I need a history). I don't want alternatives (unless there are demonstrably better solutions), I'm just wondering if any flavor of SQL can express "conditional uniqueness" in this way. I'm using MS SQL, so if there's a way to do it in that, great. I'm mostly just academically interested in the problem.
If you are using SQL Server 2008 a Index filter would maybe your solution:
http://msdn.microsoft.com/en-us/library/ms188783.aspx
This is how I enforce a Unique Index with multiple NULL values
CREATE UNIQUE INDEX [IDX_Blah] ON [tblBlah] ([MyCol]) WHERE [MyCol] IS NOT NULL
In the case of descriptions which are not yet completed, I wouldn't have those in the same table as the finalized descriptions. The final table would then have a unique index or primary key on the description.
In the case of the active/inactive, again I might have separate tables as you did with an "archive" or "history" table, but another possible way to do it in MS SQL Server at least is through the use of an indexed view:
CREATE TABLE Test_Conditionally_Unique
(
my_id INT NOT NULL,
active BIT NOT NULL DEFAULT 0
)
GO
CREATE VIEW dbo.Test_Conditionally_Unique_View
WITH SCHEMABINDING
AS
SELECT
my_id
FROM
dbo.Test_Conditionally_Unique
WHERE
active = 1
GO
CREATE UNIQUE CLUSTERED INDEX IDX1 ON Test_Conditionally_Unique_View (my_id)
GO
INSERT INTO dbo.Test_Conditionally_Unique (my_id, active)
VALUES (1, 0)
INSERT INTO dbo.Test_Conditionally_Unique (my_id, active)
VALUES (1, 0)
INSERT INTO dbo.Test_Conditionally_Unique (my_id, active)
VALUES (1, 0)
INSERT INTO dbo.Test_Conditionally_Unique (my_id, active)
VALUES (1, 1)
INSERT INTO dbo.Test_Conditionally_Unique (my_id, active)
VALUES (2, 0)
INSERT INTO dbo.Test_Conditionally_Unique (my_id, active)
VALUES (2, 1)
INSERT INTO dbo.Test_Conditionally_Unique (my_id, active)
VALUES (2, 1) -- This insert will fail
You could use this same method for the NULL/Valued descriptions as well.
Thanks for the comments, the initial version of this answer was wrong.
Here's a trick using a computed column that effectively allows a nullable unique constraint in SQL Server:
create table NullAndUnique
(
id int identity,
name varchar(50),
uniqueName as case
when name is null then cast(id as varchar(51))
else name + '_' end,
unique(uniqueName)
)
insert into NullAndUnique default values
insert into NullAndUnique default values -- Works
insert into NullAndUnique default values -- not accidentally :)
insert into NullAndUnique (name) values ('Joel')
insert into NullAndUnique (name) values ('Joel') -- Boom!
It basically uses the id when the name is null. The + '_' is to avoid cases where name might be numeric, like 1, which could collide with the id.
I'm not entirely aware of your intended use or your tables, but you could try using a one to one relationship. Split out this "sometimes" unique column into a new table, create the UNIQUE index on that column in the new table and FK back to the original table using the original tables PK. Only have a row in this new table when the "unique" data is supposed to exist.
OLD tables:
TableA
ID pk
Col1 sometimes unique
Col...
NEW tables:
TableA
ID
Col...
TableB
ID PK, FK to TableA.ID
Col1 unique index
Oracle does. A fully null key is not indexed by a Btree in index in Oracle, and Oracle uses Btree indexes to enforce unique constraints.
Assuming one wished to version ID_COLUMN based on the ACTIVE_FLAG being set to 1:
CREATE UNIQUE INDEX idx_versioning_id ON mytable
(CASE active_flag WHEN 0 THEN NULL ELSE active_flag END,
CASE active_flag WHEN 0 THEN NULL ELSE id_column END);