Conditionally apply a unique index - sql

I am implementing functionality for a table that when an edit/change is made it will save a copy of the pre-edit row and mark it as is_deleted=TRUE, this is inorder to create a history of changes made to a row.
The email column in the table has a unique index which is preventing this functionality from being successful.
PostgreSQL said: duplicate key value violates unique constraint "users_email_unique"
Detail: Key (email)=(TEST) already exists.
Is there a way to apply the unique index only to rows that are marked is_deleted=FALSE, thus allowing for the changes to occur.

Since version 7.2, you can use partial indexes in PostgreSql
Add a where clause to the create index statement to make it a partial index:
CREATE UNIQUE INDEX users_email_unique ON tests (email)
WHERE NOT is_deleted; -- assuming is_deleted is Boolean
Though PostgreSql supports Alter index, from what I understand from the documentation the alter is limited to either rename or setting the tablespace.
This means that you will need to drop and re-create the index in order to change it into a partial index:
DROP INDEX users_email_unique;
CREATE UNIQUE INDEX users_email_unique ON tests (email)
WHERE NOT is_deleted; -- assuming is_deleted is Boolean

Related

HANA: How to add a unique contraint on a column that is already indexed?

Having the following schema:
CREATE TABLE test_table(
cryptid varchar(255)
);
CREATE INDEX cryptid_index ON test_table (cryptid);
I am trying to a unique contraint to the column.
ALTER TABLE test_table ADD constraint crypid_unique_contraint UNIQUE(cryptid);
But this runs into an error:
Could not execute 'ALTER TABLE test_table ADD constraint crypid_unique_contraint ...'
Error: (dberror) [261]: invalid index name: column list already indexed
I can understand that the column is already indexed because I have created the index by myself. But I want the column to be unique. Is there a way to do this?
This is indeed an undocumented limitation in the current HANA versions.
The only way to create a unique constraint on this column is to first drop the single-column index present on this column.
I would consider the fact that this is not documented a (docu-)bug. However, the fact that existing indexes cannot be generally reused for uniqueness checks is not.
Single-column indexes in HANA's column store (which is what you use by default) tables are not B-tree indexes. Instead, these are inverted indexes into the column store structure of the main store-part of a column store table column.
These inverted structures cannot be checked for duplicates in the current transactional context as easily as B-tree indexes could.
This, I believe, is the reason for
a) implementing the uniqueness check only on a specific index implementation in the column store,
and
b) making the system behavior (not allowing the "conversion" of an existing index into a unique index) consistent across all table types.
As a general comment: for column store tables the benefit of single-column indexes for lookup/point-read scenarios is very often not worth the additional storage & compute resource consumption. This type of index practically doubles the memory requirement for the indexed column. So the speed-up in looking up a specific value should be worthwhile this additional permanent resource consumption.
You may check the documentation on INDEXES system view. They listed this index types:
Type of row store indexes: BTREE, BTREE_UNIQUE, CPBTREE, and CPBTREE_UNIQUE.
"Simple" index and unique index are a different index types at a build time, so there's no way to change it after the index was declared.
In other databases when you add unique constraint, it creates a new unique index (like in T-SQL or MySQL or Postgers) or reuses current index with this column (as in Oracle). But HANA doesn't allow you to create ether additional index on the same column (due to unknown reason, I didn't find it documented) or enforce constraint using existing index (due to poor implementation of mixture of uniqueness and index type).
The only way to go is to drop existing index and create it as unique (it is equivalent to unique constraint from the metadata point of view) from scratch, which you cannot due to authorizations. Sad but...

Dropping a global temp table does not drop its index

Problem summary:
I created a global temp table and then I created a clustered index (added a primary key clustered constraint) on the table. I dropped the table assuming that it will also drop the index. I then recreated the table with the same name without problems. Then, when I tried to recreate the same index with the same name I get the error:
The CREATE UNIQUE INDEX statement terminated because a duplicate key was found for the object name 'dbo.##MyTempTable' and the index name 'PK_TempSampleID'.
Problem details:
I need to create a global temp table and load records into this table in a particular order using:
SELECT FROM SomeTable INTO ##MyTempTable WHERE SomeCondition
ORDER BY does not do the job here, so I created a clustered index (primary key clustered constraint). This did the trick and my records were ordered by the respective field.
However, I encountered a different problem: I dropped the table and recreated it without problems but when I tried recreating the index I got the above mentioned error.
I tried dropping the index using:
DROP INDEX PK_TempSampleID ON ##MyTempTable
And I got this error message:
Cannot drop the index '##TempFormattedSnapshot.PK_TempSampleID', because it does not exist or you do not have permission.
I researched posts on this and other forums and all seem to advise that when dropping a temp table the index on that table is also dropped. My experience shows me otherwise.
The error message
The CREATE UNIQUE INDEX statement terminated because a duplicate key
was found for the object name 'dbo.##MyTempTable' and the index name
'PK_TempSampleID'.
means that there are duplicate values in the column(s) for which you are trying to create a unique index. In other words, not all values are unique.
It has nothing to do with the previously existed index of the same name.
When you drop a table, all indexes on that table are dropped as well.
You have another problem, which is out of the scope of this question. You said "load records into this table in a particular order". You'd better ask another question explaining what you are trying to achieve, because there is no such thing as "inserting rows into a table in a particular order". The only thing that you can do is generate IDENTITY values in a particular order when inserting rows.
Anyway, this is not the point of this question.

Removing Uniqueness from an Index

On one of my tables in SQL Server, In the Indexes folder I have a Clustered Index made from three columns of that table but there is also a Unique checkbox when I go to properties window on that index.
My question is with T-SQL commands how I tell it to drop the Uniqueness part and still keep the index? Is it even possible?
You cannot alter index from unique to non-unique. You can set index to ignore duplicates.
Docs: https://msdn.microsoft.com/en-us/library/ms188388.aspx
You can only recreate index with drop and create commands.
DROP INDEX IndexTest.ci_Test;
CREATE INDEX ci_Test ON IndexTest(Key);
But you should have clustered index on one column (for example on new autoincrement primary key). And you can force uniqueness with unique non-clustered index.

USING index clause

I saw the following statement in a db patch:
ALTER TABLE tablename ADD PRIMARY KEY (somepk_columnname) USING INDEX;
I wanted to look up what USING INDEX does here, but only got from google, that it lets me specify some storage specific stuff, etc.
My question really is, what exactly happens here? Does the db use some default values here? Creates an index for the PK in the default tablespace? I thought that an index is created for every pk per default...
http://docs.oracle.com/cd/B28359_01/server.111/b28286/clauses002.htm#SQLRF52209
Using Indexes to Enforce Constraints
When defining the state of a unique or primary key constraint, you can
specify an index for Oracle to use to enforce the constraint, or you
can instruct Oracle to create the index used to enforce the
constraint.
using_index_clause You can specify the using_index_clause only when
enabling unique or primary key constraints. You can specify the
clauses of the using_index_clause in any order, but you can specify
each clause only once.
If you specify schema.index, then Oracle attempts to enforce the constraint using the specified index. If Oracle cannot find the index
or cannot use the index to enforce the constraint, then Oracle returns
an error.
If you specify the create_index_statement, then Oracle attempts to create the index and use it to enforce the constraint. If Oracle
cannot create the index or cannot use the index to enforce the
constraint, then Oracle returns an error.
If you neither specify an existing index nor create a new index, then Oracle creates the index. In this case:
The index receives the same name as the constraint.
If table is partitioned, then you can specify a locally or globally partitioned index for the unique or primary key constraint.
The response above was very helpful but I also wanted to use a specific tablespace for my unique key. This worked for me:
alter table tablename add constraint uk_name unique (col1, col2) using index tablespace tablespace_name;

Does creation of a foreign key mean creation of an index?

If I have a column a inside table Foo, and I create a new table Bar with a column b that is a foreign key to Foo.a, is column b automatically indexed for Bar, or must I still create an index on Bar.b if I want to efficiently search for all rows in Bar with b = 1?
(If it matters, I am using SQLite.)
Foreign keys are just used to 'force exists relationships between tables', but not automatically indexed based on their related column's index. Indexing Foo.a will speed up inserts/updates on Bar.b, while indexing Bar.b will speed up selects on Bar.b.
Creating a Foreign Key in SQLite is only creating a constraint. You should create the index yourself.
From the documentation, near the end of paragraph 3:
So, in most real systems, an index should be created on the child key
columns of each foreign key constraint.
You have to create the index yourself. At least I know no DBMS that does it automatically.