Adapt ON CONFLICT clause to new unique index? - sqlite

I want to add an extra unique constraint to an existing table. This and other answers say it's not possible with sqlite, and suggest creating an unique index:
ALTER TABLE example ADD COLUMN new_unique TEXT;
CREATE UNIQUE INDEX new_unique_index ON example(new_unique);
This seems to work. However, I'm having trouble with UPSERTs:
INSERT INTO example (foo, old_unique, new_unique) VALUES ('foo', 'old', 'new') ON CONFLICT(old_unique, new_unique) DO UPDATE SET foo='foo';
This gives an error:
ON CONFLICT cause does not match any PRIMARY KEY or UNIQUE constraint
Is there any way I could adapt the ON CONFLICT clause of the statement above to work with the new "constraint"?
I tried using new_unique_index, to no avail. If it's impossible, is there any alternative to creating a new table with the new unique constraint and copying the values from the old table into the new one with NULL for the new constraint column? This would be burdensome. I imagine I could create a new table with all of the former's columns, except the old uniques, plus the new unique, and link them somehow, but it sounds messy and I have no idea how to proceed.
Minimum reproducible example:
CREATE TABLE example (foo TEXT, old_unique TEXT, UNIQUE(old_unique));
ALTER TABLE example ADD COLUMN new_unique TEXT;
CREATE UNIQUE INDEX new_unique_index ON example(new_unique);
INSERT INTO example (foo, old_unique, new_unique) VALUES ('foo', 'old', 'new') ON CONFLICT(old_unique, new_unique) DO UPDATE SET foo='foo';

Is there any way I could adapt the ON CONFLICT clause of the statement above to work with the new "constraint"?
(old_unique, new_unique) is a not a possible constraint target as there is no index that combines both columns, each is an individual constraint (so you could use one or the other, as my understanding is that you are limited to a single UPSERT clause and a single conflict target).
If instead of :-
CREATE UNIQUE INDEX new_unique_index ON example(new_unique);
You used
CREATE UNIQUE INDEX new_unique_index ON example(old_unique,new_unique);
Then the following will work :-
INSERT INTO example (foo,old_unique,new_unique) VALUES('foo','old','new') ON CONFLICT (old_unique,new_unique) DO UPDATE SET foo = 'foo';
(well at least not be rejected due to no covering primary key or index for the given conflict target).
If it's impossible, is there any alternative to creating a new table with the new unique constraint and copying the values from the old table into the new one with NULL for the new constraint column? This would be burdensome.
It's not really burdensome e.g. you could use :-
CREATE TABLE IF NOT EXISTS temp_example (foo, old_unique,new_unique, UNIQUE(old_unique,new_unique));
INSERT INTO temp_example SELECT *,null FROM example;
ALTER TABLE example RENAME TO old_example;
ALTER TABLE temp_example RENAME TO example;
DROP TABLE If EXISTS old_example;
i.e. as you are adding a column and it will be the last column then there is no need to code column names.

Related

Creating index with unique constraint for new blank field

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.

Indexes in Teradata

How to Enable/Disable Indexes in TERADATA Database?
I want to disable indexes and do update and then enable the indexes in Teradata.
If Enable/Disable option not available in Teradata, in the sense How can I achieve this ? If I use DROP Indexes, how can I recreate the indexes for all the tables?
Teradata gives you a way to create a table without choosing for primary index (if you are sure of any column).
You can create table with No primary Index. Here is a sample of how to do so:
Create table <table name>
(<columnname> <datatype>,
<columnname> <datatype>)
no primary index ;
Teradata does not have a disable index feature.
All tables have a Primary Index (PI) which is chosen by the RDBMS unless you specify one.
CREATE INDEX <index name> (<column list>) ON table name;
CREATE UNIQUE INDEX (department) ON tbl_employee;
DROP INDEX ind_dept ON tbl_employee;
DROP INDEX (department,emp_number) ON tbl_employee;
In Teradata you can't drop Primary index of a table. The primary index defines where data will reside and which AMP receives the row.
To alter the primary index of a table you need to delete all the records from the table ( As data is already distributed by the row hash value of the PI) then only you can change the primary index of a table by using below command:-
Alter table table_name modify primary index index_name (column list);
Steps to achieve your goal
You can crate a new table with your desired index ( temp, wrk, intermediate table) insert the records from the original table and update the wrk table.
delete the original table and insert the wrk table data.
And you are done.
Create & Drop index is the only option you have here
Simple answer - you can't disable and re-enable indexes in Teradata.
However, there some workarounds.
Drop Index
If you talking about PI (primary index) - you can't drop it. All you can do is to make a copy of a table without an index.
You can drop secondary index though. Then simply create it again when you need it.
Drop-Create Table
This doesn't fit all cases, but often this is the fastest way to do the work, especially if the issue you have is with PI.
BTW: it is not clear, why would you need to do that? Performance or logic or something else? That probably will affect recommendation.
Since you did not specify what kind of index you want to disable/enable, below are the approach you can follow on either cases.
PRIMARY INDEX
CREATE a new table with the same PI
INSERT the updated data to new table
DROP the old table - DROP TABLE <OldTable>;
RENAME the new table same as the old one. - RENAME TABLE <NewTable> TO <OldTable>;
Above recommendation for Primary Index is only applicable if you are going to update a primary index column value. If you will update other columns (not the PI column) then you can just issue an UPDATE Statement directly.
SECONDARY INDEX
DROP the SI - DROP INDEX <IndexName> ON <TableName>;
UPDATE table data
RECREATE the SI - CREATE INDEX <IndexName> (<ColumnList>) ON <TableName>;

Why two column created of same name in angular + ionic

I am creating a table inside the DB.I am a successfully created a table and able to insert data on table my issue is that in my table I have two "ID" columns but I only created one .why two ID column generate in table.
Follow this step to generate issue :-
Click the bottom right button (enter the text in pop up screen ).Press "add" button .It generate the row in a "cases" table but when you inspect it show two column of "ID" why ?
Here is my code
http://codepen.io/anon/pen/OVPgoP
db.transaction(function(tx) {
tx.executeSql('CREATE TABLE "Cases" ("ID" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL , "CaseName" VARCHAR NOT NULL )');
})
It appears that this is the expected behaviour for SQLite, the technology underpinning Web SQL (which is a deprecated technology, btw).
From the docs:
If a table contains a column of type INTEGER PRIMARY KEY, then that column becomes an alias for the ROWID. You can then access the ROWID using any of four different names, the original three names described above or the name given to the INTEGER PRIMARY KEY column. All these names are aliases for one another and work equally well in any context.
Therefore, my guess is that the Chrome devtools are showing the rowid column using its alias (ID), in addition to the alias column explicitly added (ID).
It seems like you don't actually need to explicitly add an ID column with Web SQL/SQLite. It will add one for you, which you can refer to using rowid, _rowid_ or oid in any statement.
EDIT: Here is a fork of your CodePen, with updates and deletes all correctly working.
Totally new to webSQL, so this answer is very useful to me as well. You can't expect primary keys to work properly with webSQL because internally it tracks something called "rowid" as the primary key. Use unique instead, as seen in a useful example here. You can also use this error code from the spec to figure out if a non-unique column value was inserted.

SQLite3 - Updating a single column in a multi-column database

I am creating a table that has a total of five columns. DUring the main "create" process, I only have enough data to populate four of the columns. Later in the execution of the program, I have the data for the fifth column. I start performing an "INSERT OR REPLACE". But! I only use the key column and the fifth column in the statement.
When I browse the database, columns two through four are NULL. So, the question is: Is there a way to only update a specific column (including the key) while keeping the existing data in tact?
INSERT OR REPLACE is the wrong statement, as you've discovered. Unless you can provide correct values for all the columns, an UPDATE statement is a better choice. Just update the column.
update your_table_name
set your_column_name = 'New Value'
where your_key_column = 'Something';
In many applications, more caution is called for.
update your_table_name
set your_column_name = 'New Value'
where your_key_column = 'Something'
and your_column_name is null;

Sort an entire SQLite table

I have an SQLite table that I need to sort. I am familiar with the ORDER BY command but this is not what I am trying to accomplish. I need the entire table sorted within the database.
Explanation:
My table uses a column called rowed which sets the order of the table (a key?). I need to sort the table by another column called name and then re-assign rowid numbers in alphabetical order according to name. Can this be done?
Assuming you created your original table like so:
CREATE TABLE my_table (rowid INTEGER PRIMARY KEY, name TEXT, somedata TEXT) ;
You can create another sorted table like so:
CREATE TABLE my_ordered_table (rowid INTEGER PRIMARY KEY, name TEXT, somedata TEXT) ;
INSERT INTO my_ordered_table (name, somedata) SELECT name,somedata FROM my_table
ORDER BY name ;
And if you then want to replace the original table:
DROP TABLE my_table ;
ALTER TABLE my_ordered_table RENAME TO my_table;
I think this issue relates to wanting the primary key to mean something. Avoid that trap. Choose an arbitrarily generated primary key that uniquely identifies a row of data and has no other meaning. Otherwise you will eventually run into the problem of wanting to alter the primary key values to preserve the meaning.
For a good explanation of why you should rely on ORDER BY to retrieve the data in the desired order instead of assuming the data will otherwise appear in a sequence determined by the primary key see Cruachan's answer to a similar question

Resources