Creating index with unique constraint for new blank field - constraints

A new column was added to an existing DB table (PA0023).
DB: HANA
The column should be unique, therefore i tried to create a unique index constraint via SE11.
Activation succeeded. However, while creating the index via Utilities... Database Utility, an error showed up:
Request: Create Index PA0023-Z01
...
sql:
CREATE UNIQUE INDEX 'PA0023~Z01' ON 'PA0023'
('MANDT',
'RECORD_KEY')
cannot CREATE UNIQUE INDEX; duplicate key found [5] Several documents with the same ID exist in the index;SAPABAP1:PA0023.$uc_PA0023~Z01$ content not unique, cannot define unique constraint. rowCount != distinctCount.
There aren't rows with the same value filled in that column. There are rows with blank value, which are considered duplicates. After replacing blanks in development environment, index was created well. It's less possible in production, because there are many records with an empty value in that new field.
So my question is: Is there a way to create the unique constraint without replacing the blanks?

You cannot create a unique constraint if the existing data does not provide uniqueness. So no you can't do this if you have multiple NULL values for the key. You would need to ensure the data is unique before creating the constraint.
This is normal database practice, it's not HANA specific.

While it is true that a compound primary key cannot contain any nullable columns it is permitted for a compound unique/candidate key to be defined with nullable columns. The only golden rule is that when adding or updating a record if any column in the unique key contains a NULL value then the index entry is NOT written to the database.
MySQL does this by default.
SQL Server will do this provided that you add "WHERE columnX IS NOT NULL" to the key's definition.
ORACLE is the same as SQL Server, except that the syntax is more complicated.

Related

Is there any way to force SQLite constrains checks?

For example, let say DB has foreign key A.b_id -> B.id with SET NULL on delete.
If record with some B.id get deleted, all b_id references will be set to NULL.
But if A already contains record where A.b_id has value that is not in B.id (it was inserted without foreign keys support), is there a way to force SQLite DB check foreign keys and set to NULL such data?
In fact, in first place I'm solving an DB upgrading task.
On start app checks if internal DB (resource) has higher version than user DB.
If so it backups user DB, copies internal empty DB to user storage. Than turns off foreign keys support and fills new DB with data from backup, inserting automatically in loop table by table for all columns with same name. Turns on foreign keys support back.
Everything works fine, but if in some table in old DB there is no foreign key constrain previously, while new DB has one, the data will be inserted as is and link can point nowhere (possibly wrong links is unavoidable and not related to question).
Yes, I understand a way to insert without turning off foreign keys support, but it would need knowledge of tables dependencies order that I would like to avoid.
Thanks for any help in advance!
Although I don't know of a way that automatically will set to NULL all orphaned values of a column in a table that (should) reference another column in another table, there is a way to get a report of all these cases and then act accordingly.
This is the PRAGMA statement foreign_key_check:
PRAGMA schema.foreign_key_check;
or for a single table check:
PRAGMA schema.foreign_key_check(table-name);
From the documenation:
The foreign_key_check pragma checks the database, or the table called
"table-name", for foreign key constraints that are violated. The
foreign_key_check pragma returns one row output for each foreign key
violation. There are four columns in each result row. The first column
is the name of the table that contains the REFERENCES clause. The
second column is the rowid of the row that contains the invalid
REFERENCES clause, or NULL if the child table is a WITHOUT ROWID
table. The third column is the name of the table that is referred to.
The fourth column is the index of the specific foreign key constraint
that failed. The fourth column in the output of the foreign_key_check
pragma is the same integer as the first column in the output of the
foreign_key_list pragma. When a "table-name" is specified, the only
foreign key constraints checked are those created by REFERENCES
clauses in the CREATE TABLE statement for table-name.
Check a simplified demo of the way to use this PRAGMA statement, or its function counterpart pragma_foreign_key_check().
You can get a list of the rowids of all the problematic rows of each table.
In your case, you can execute an UPDATE statement that will set to NULL all the orphaned b_ids:
UPDATE A
SET b_id = NULL
WHERE rowid IN (SELECT rowid FROM pragma_foreign_key_check() WHERE "table" = 'A')
This also works in later versions of SQLite:
UPDATE A
SET b_id = NULL
WHERE rowid IN (SELECT rowid FROM pragma_foreign_key_check('A'))
but it does not seem to work up to SQLite 3.27.0

Impala add column with default value

I want to add a column to an existing impala table(and view) with a default value (so that the existing rows also have a value). The column should not allow null values.
ALTER TABLE dbName.tblName ADD COLUMNS (id STRING NOT NULL '-1')
I went through the docs but could not find an example that specifically does this. How do I do this in Impala? Hue underlines/does not recognize the NOT NULL command
Are you using Kudu as a storage layer for your table? Because if not, then according to Impala docs,
Note: Impala only allows PRIMARY KEY clauses and NOT NULL constraints on
columns for Kudu tables. These constraints are enforced on the Kudu
side.
...
For non-Kudu tables, Impala allows any column to contain NULL values,
because it is not practical to enforce a "not null" constraint on HDFS
data files that could be prepared using external tools and ETL
processes.
Impala's ALTER TABLE syntax also does not support specifying default column values (in general, non-Kudu).
With Impala you could try as follow
add the column
ALTER TABLE dbName.tblName ADD COLUMNS(id STRING);
once you've added the column you can fill that column as below using the same table
INSERT OVERWRITE dbName.tblName SELECT col1,...,coln, '-1' FROM dbName.tblName;
where col1,...,coln are the previous columns before the add columns command and '-1' is to fill the new column.

Handling DocumentClientException with BulkImport

I am using Microsoft.Azure.CosmosDB.BulkExecutor.IBulkExecutor.BulkImportAsync to insert documents as a batch. I have implemented unique constraints for my cosmos db collection. If any of the input documents violates the constraint the entire bulk import operation fails with throwing DocumentClientException. Is this an expected behaviour? Or is there a way we can handle the exceptions for failed documents and make sure the valid documents are inserted?
First of all Thanks to Microsoft Document which has explained solid scenarios on the issue,
https://learn.microsoft.com/en-us/azure/data-factory/connector-troubleshoot-guide
This error appears when we define unique_key in addition to default id field defined by cosmos. The reason could be possible duplication of row for Unique Key in the dataset. Another possible reason, the Delta dataset which we are about to load has some of the unique keys which are already present in existing cosmos dataset.
For regular batch jobs there could be some updates happening on existing unique key itself, but we cannot update an existing unique key through batch process. As each record gets into cosmos as new record with new 'id' field value. Cosmos updates an existing record only same id field not on unique key.
Workaround, Since unique key is already going to be unique for every row across entire collection, we can define our unique value itself as also 'id' field. So now if we have any updates on addition field apart from unique key we can update them as 'id' field for respective unique key will also be same.
In SQL way,
SELECT <unique_key_field> AS id, <unique_key_field>, field1, field2 FROM <table_name>

sqlite - programmatically determine primary key(s)

I need to programatically determine what the primary key field(s) are for a given sqlite table (using sqlite api, not command line).
I can get a list of tables and a list of columns, but only see the column type using the Column_Type() function. Need to know if a given column is the primary key (or part of the primary key if a compound key is used).
Have a look at sqlite3_table_column_metadata:
This routine returns metadata about a specific column of a specific
database table accessible using the database connection handle passed
as the first function argument.

SQLITE: Unable to remove an unnamed primary key

I have a sqlite table that was originally created with:
PRIMARY KEY (`column`);
I now need to remove that primary key and create a new one. Creating a new one is easy, but removing the original seems to be the hard part. If I do
.indices tablename
I don't get the primary key. Some programs show the primary key as
Indexes: 1
[] PRIMARY
The index name is typically in the [].
Any ideas?
You can't.
PRAGMA INDEX_LIST('MyTable');
will give you a list of indices. This will include the automatically generated index for the primary key which will be called something like 'sqlite_autoindex_MyTable_1'.
But unfortunately you cannot drop this index...
sqlite> drop index sqlite_autoindex_MyTable_1;
SQL error: index associated with UNIQUE or PRIMARY KEY constraint cannot be dropped
All you can do is re-create the table without the primary key.
I the database glossary; a primary-key is a type of index where the index order is typically results in the physical ordering of the raw database records. That said any database engine that allows the primary key to be changed is likely reordering the database... so most do not and the operation is up to the programmer to create a script to rename the table and create a new one. So if you want to change the PK there is no magic SQL.
select * from sqlite_master;
table|x|x|2|CREATE TABLE x (a text, b text, primary key (`a`))
index|sqlite_autoindex_x_1|x|3|
You'll see that the second row returned from my quick hack has the index name in the second column, and the table name in the third. Try seeing if that name is anything useful.

Resources