I have following indexes/unique constraints in my table.
INDNAME COLNAMES
SQL160215110206240 +ID
SQL160215110206360 +ENTITY_TYPE+TENANT_ID+ENTITY_LOCAL_USERSTORE+ENTITY_NAME
SQL160215145445420 +ENTITY_TYPE+TENANT_ID+ENTITY_LOCAL_USERSTORE+ENTITY_NAME+PROVISIONING_CONFIG_ID
Now I run following code segment on my darabase.
BEGIN
DECLARE v_rcount VARCHAR(128);
DECLARE STMT VARCHAR(200);
select INDNAME into v_rcount from SYSCAT.INDEXES WHERE TABNAME='IDP_PROVISIONING_ENTITY' AND COLNAMES='+ENTITY_TYPE+TENANT_ID+ENTITY_LOCAL_USERSTORE+ENTITY_NAME';
SET STMT = 'ALTER TABLE IDP_PROVISIONING_ENTITY DROP CONSTRAINT ' || v_rcount;
PREPARE S1 FROM STMT;
EXECUTE S1;
END
When I run it for the 1st time, I am getting following response.
DB20000I The SQL command completed successfully.
But when I list the indexes of the table, I am still seeing all 3 indexes as before.
And also when I run the same code segment again, I am getting following error.
SQL0204N "SQL160215110206360" is an undefined name. SQLSTATE=42704
Not only this index, if I try to drop any other index in the same database, I am getting the same error. What is the reason for this? How can I solve this?
The cause for this issue is, I am getting the name from SYSCAT.INDEXES. So there it is returning the name of INDEX. Even though a INDEX is created to each unique constraint, name of index can be different from name of Constraint. So here I have dropped the constraint and then I have checked the index table if it has removed. That's the reason why I can see the same index name still after removing the constraint.
Also every index name in SYSCAT.INDEXES will not refer to a constraint. So everytime I run DROP CONSTRAINT with a name from SYSCAT.INDEXES will not return success.
IBM DB2 behaves little bit differently compared to other well known databases when comes to constraints and indexes. So let me explain the solution for your problem in detail.
You have the following table.
CREATE TABLE IDP_PROVISIONING_ENTITY (
ID INTEGER NOT NULL,
PROVISIONING_CONFIG_ID INTEGER NOT NULL,
ENTITY_TYPE VARCHAR(255) NOT NULL,
ENTITY_LOCAL_USERSTORE VARCHAR(255) NOT NULL,
ENTITY_NAME VARCHAR(255) NOT NULL,
ENTITY_VALUE VARCHAR(255) NOT NULL,
TENANT_ID INTEGER NOT NULL,
PRIMARY KEY (ID),
UNIQUE (ENTITY_TYPE, TENANT_ID, ENTITY_LOCAL_USERSTORE, ENTITY_NAME),
UNIQUE (PROVISIONING_CONFIG_ID, ENTITY_TYPE, ENTITY_VALUE),
FOREIGN KEY (PROVISIONING_CONFIG_ID) REFERENCES IDP_PROVISIONING_CONFIG(ID) ON DELETE CASCADE)
/
It has a primary key and two unique constraints. The DB2 will automatically create indexes for these three constraints.
The problem is, we have not defined the constraints as named constraints. Therefore we have to take an extra effort to find out the names of the indexes and the constraints which are auto generated by DB2.
These are the two unique constraints that we have in the table.
UNIQUE (ENTITY_TYPE, TENANT_ID, ENTITY_LOCAL_USERSTORE, ENTITY_NAME),
UNIQUE (PROVISIONING_CONFIG_ID, ENTITY_TYPE, ENTITY_VALUE)
You can find the auto generated names for the unique constraints by running the following query. the constraintyp='U' for unique constraints and it is 'P' for primary keys.
db2 "select NAME from sysibm.systabconst where tbname='IDP_PROVISIONING_ENTITY' and constraintyp='U'"
NAME
--------
SQL160219074557840
SQL160219074557920
Above is the result I got. You will get different values in your database as these are random generated.
You can run the following query to see the indexes created for the IDP_PROVISIONING_ENTITY' table.
db2 "SELECT NAME, COLNAMES FROM SYSIBM.SYSINDEXES WHERE TBNAME='IDP_PROVISIONING_ENTITY'"
NAME COLNAMES
SQL160219074557290 +ID
SQL160219074557790 +PROVISIONING_CONFIG_ID+ENTITY_TYPE+ENTITY_VALUE
SQL160219074557860 +ENTITY_TYPE+TENANT_ID+ENTITY_LOCAL_USERSTORE+ENTITY_NAME
Now we know the constraint names for the two unique constraints and the index names for the IDP_PROVISIONING_ENTITY table.
You can find the particular index you need to drop by adding a where clause for the above query as below.
db2 "SELECT NAME FROM SYSIBM.SYSINDEXES WHERE TBNAME='IDP_PROVISIONING_ENTITY' and COLNAMES='+ENTITY_TYPE+TENANT_ID+ENTITY_LOCAL_USERSTORE+ENTITY_NAME'"
NAME
----------
SQL160219074557860
In IBM DB2, you cannot drop an index which is generated for a constraint (primary key or unique) directly. For that, you need to drop the constraint which will drop the index also.
But the problem is we do not know what is the name of the unique constraint that is associated with the index "+ENTITY_TYPE+TENANT_ID+ENTITY_LOCAL_USERSTORE+ENTITY_NAME". We already know that the index name we need to drop is SQL160219074557860.
You can find it out which constraint is associated with which index by running the following query.
db2 "select CONSTNAME, BNAME from SYSCAT.CONSTDEP where TABNAME = 'IDP_PROVISIONING_ENTITY'"
CONSTNAME BNAME
SQL160219074557790 SQL160219074557290
SQL160219074557840 SQL160219074557790
SQL160219074557920 SQL160219074557860
Based on the results, you can get to know the name of the constraint.
So the constraint name associated with the index name "SQL160219074557860" is "SQL160219074557920".
So since we know the constraint name now, we can drop the unique constraint.
db2 "ALTER TABLE IDP_PROVISIONING_ENTITY DROP UNIQUE SQL160219074557920"
This will drop the constraint as well as the index created for the constraint.
Related
I have two tables, one of student and one of staff that look as such:
create table student (
id int not null primary key
)
create table staff (
id int not null primary key
)
I want the id in each to be unique. I know this isn't how it should be in production but I'm just trying to see why my check constraint doesn't work and I'm using a simpler example to explain.
I then alter the tables to include the check as follows:
alter table student add constraint not_staff check (id not in (select id from staff))
alter table staff add constraint not_student check (id not in (select id from student))
These checks seem to be invalid.
My question is whether we're allowed to have these kinds of SQL statements inside of a check constraint. If so, why is the above constraint invalid and how would I go about fixing it.
Thanks!
You can't use queries in a check constraint in Db2. Refer to the description of the CREATE TABLE statement.
CHECK (check-condition)
Defines a check constraint. The search-condition must be true or unknown for every row of the table.
search-condition
The search-condition has the following restrictions:
...
The search-condition cannot contain any of the following (SQLSTATE 42621):
Subqueries
The easiest way to achieve your goal is not to create constraints, but create a sequence and use it in before triggers on both tables.
I have just inherited a database from another developer, and I have looked through the sys.objects table, filtering by constraints.
What does DF__role_sett__custo__4589517F mean - mainly the ID at the end of the string?
I know that DF_role_sett_custo means default constraint of role_setting_customer, but am not sure of the last ID 4589517f.
If you don't name a constraint when it is created, SQL Server will assign it a random name based on the table and column. It appends a random number so that it doesn't clash with existing constraint names.
In almost all cases, it is best to name a constraint when it is created. It's then easier to refer to the constraint by name in other T-SQL statements.
For instance, in the following create statement
CREATE TABLE dbo.some_table(
some_field INT NOT NULL DEFAULT(5)
);
The default constraint will be assigned a random name. In this statement:
CREATE TABLE dbo.some_table(
some_field INT NOT NULL CONSTRAINT DF_some_table_some_field DEFAULT(5)
);
The default constraint will have the name you assigned to it (i.e. DF_some_table_some_field).
I have a script written for Oracle databases that I'm converting to work in SQL Server and I have two questions about a specific section of code.
In Oracle script I have this code:
CREATE UNIQUE INDEX "PK_PORTALROLES" ON "PORTAL_ROLE" ("ROLE_NAME");
ALTER TABLE "PORTAL_ROLE" ADD CONSTRAINT "PK_PORTALROLES"
PRIMARY KEY ("ROLE_NAME") USING INDEX ENABLE;
Question (1)
From the code above what is the USING INDEX command in the ALTER TABLE line doing? Is it assigning the UNIQUE INDEX created on the first line to the newly created CONSTRAINT or is the CONSTRAINT getting a new UNIQUE INDEX to use when it is created?
Question (2)
To duplicate this in SQL Server, I commented out the CREATE UNIQUE INDEX line like this:
--CREATE UNIQUE INDEX "PK_PORTALROLES" ON "PORTAL_ROLE" ("ROLE_NAME");
And then replaced the ALTER TABLE line with this:
ALTER TABLE "PORTAL_ROLE" ADD CONSTRAINT "PK_PORTALROLES" PRIMARY KEY ("ROLE_NAME");
I understand that when a PRIMARY KEY CONSTRAINT is created in SQL Server a UNIQUE INDEX is automatically made. So is the one line of SQL Server code directly above doing the same thing as the two lines of Oracle code above?
EDIT
One final question. Is there a way in Oracle and SQL Server to assign an existing INDEX to a CONSTRAINT?
In Oracle
If there are more than one indexes on the column on which you want to add PK constraint, we can selectively choose the index to be assoicated with the PK using “USING INDEX“. This clause can be used while:
Adding the PK constraint for the first time (using “ALTER TABLE” command).
CREATE TABLE tbl_test ( col_1 NUMBER,
col_2 NUMBER,
col_3 NUMBER);
CREATE INDEX idx_col_1_2 ON tbl_test(col_1, col_2);
CREATE INDEX idx_col_1_3 ON tbl_test(col_1, col_3);
CREATE UNIQUE INDEX idx_col_1 ON tbl_test(col_1);
-- Forcing oracle to use the unique index "IDX_COL_1"
ALTER TABLE tbl_test ADD CONSTRAINT tbl_test_pk PRIMARY KEY(col_1)
USING INDEX idx_col_1;
SELECT constraint_name, constraint_type, index_name
FROM user_constraints
WHERE table_name = 'TBL_TEST';
-- CONSTRAINT_NAME | CONSTRAINT_TYPE | INDEX_NAME
-- TBL_TEST_PK | P | IDX_COL_1
What if? If you don't use the USING INDEX clause
ALTER TABLE tbl_test ADD CONSTRAINT tbl_test_pk PRIMARY KEY(col_1);
-- Although an unique index exists, oracle has picked up the first index
SELECT constraint_name, constraint_type, index_name
FROM user_constraints
WHERE table_name = 'TBL_TEST';
-- CONSTRAINT_NAME | CONSTRAINT_TYPE | INDEX_NAME
-- TBL_TEST_PK | P | IDX_COL_1_2
That shows The index associated with the PK constraint needn’t be unique.
But in SQLServer implicitly CLUSTERED INDEX will be created when primary key defined on any column
So to your last question. In Oracle you can assign index which we created can be assigned to constraints which we will create in future.
In SQLServer i guess it is not possible.
In Oracle, you can do
alter table PORTAL_ROLE add constraint pk_portalroles primary key('ROLE_NAME');
And it will create unique index for you. But when you drop or disable(!) constraint, it will drop that index. To avoid that (or to give index some custom name, or to use non-unique index, etc), it is usually done in 2 steps as in your code (as recommended by ORACLE).
Q1: constraint will be using existing index.
Q2: Yes, it will be enough for SQL Server.
When you specify a unique constraint on one or more columns, Oracle implicitly creates an index on the unique key. If you are defining uniqueness for purposes of query performance, then Oracle recommends that you instead create the unique index explicitly using a CREATE UNIQUE INDEX statement. You can also use the CREATE UNIQUE INDEX statement to create a unique function-based index that defines a conditional unique constraint.
I have added a new column, called Ordinal, to a table called Activity. The problem is that I gave it a UNIQUE constraint, set it to allow NULL (though this I won't want in the end.. I just needed to set it to that to get a little farther with the script), and did not give it a default value. I'm now running a RedGate SQL Compare script that was generated by comparing this table to a version of the Activity table that does not have the column. But I'm getting the following error:
The CREATE UNIQUE INDEX statement terminated because a duplicate key was found for the object name 'iwt.Activity' and the index name 'IX_Activity'. The duplicate key value is (1).
So based on my research, it's trying to create a unique key constraint on the Ordinal column, but NULL is not unique. So my next step was to give it a unique value of 1 just to let the script pass. But 1 isn't going to be unique either. So, finally, my question:
Preferably in SQL Server Management Studio, how do I set a column as having a unique default value? Isn't that what I would need to create this constraint?
Thanks.
try this:
NULL will be the first constraint when you create the column.
UNIQUE will be as add constraint, you should add the second constraint.
they can run on this order with no problem (tested):
--first constraint
alter table Table_Name
add Column_Name int null
--second constraint
alter table Table_Name
add constraint Constraint_Name unique (Column_Name)
In my example :
PaymentGatewayHash is column
Cart is a table
--first query
alter table Cart
add PaymentGatewayHash NVARCHAR(20) null
--second query
CREATE UNIQUE INDEX PaymentGatewayHashUnique
ON Cart (PaymentGatewayHash)
WHERE PaymentGatewayHash IS NOT NULL
I just tested that :D
I create the following table in H2:
CREATE TABLE TEST
(ID BIGINT NOT NULL PRIMARY KEY)
Then I look into INFORMATION_SCHEMA.TABLES table:
SELECT SQL
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = 'TEST'
Result:
CREATE CACHED TABLE TEST(
ID BIGINT NOT NULL
)
Then I look into INFORMATION_SCHEMA.CONSTRAINTS table:
SELECT SQL
FROM INFORMATION_SCHEMA.CONSTRAINTS
WHERE TABLE_NAME = 'TEST'
Result:
ALTER TABLE TEST
ADD CONSTRAINT CONSTRAINT_4C
PRIMARY KEY(ID)
INDEX PRIMARY_KEY_4C
These statements are not the ones which I have stated, therefore, the question is:
Is the information in TABLES and CONSTRAINS reflects how real SQL which was executed in database?
In original CREATE TABLE statement
there was no CACHED word. (not a problem)
I have never executed ALTER TABLE .. ADD CONSTRAINT statement.
The actual reason why I am asking the question is that I am not sure which statement should I execute in order to guarantee that primary key is used in a clustered index.
If you look at my previous question H2 database: clustered index support then you may find in the answer of Thomas Mueller the following statement:
If a primary key is created after the table has been created then the primary key is stored in a new index b-tree.
Therefore, if the statements are executed as such they are shown in INFORMATION_SCHEMA, then primary key is created after the table is created and hence ID is not used in a clustered index (basically as a key in a data b-tree).
Is there a way how one can guarantee that primary key is used in a clustered index in H2?
Is the information in TABLES and CONSTRAINS reflects how real SQL which was executed in database?
Yes. Basically, those are the statements that are run when opening the database.
If you look at my previous question
The answer "If a primary key is created after the table has been created..." was incorrect, I fixed it now to "If a primary key is created after data has been inserted...".
Is there a way how one can guarantee that primary key is used as a clustered index in H2?
This is now better described in the H2 documentation at "How Data is Stored Internally": "If a single column primary key of type BIGINT, INT, SMALLINT, TINYINT is specified when creating the table (or just after creating the table, but before inserting any rows), then this column is used as the key of the data b-tree."