IF NOT EXISTS(SELECT * FROM sys.indexes WHERE name = 'MyTableIndex' AND object_id = OBJECT_ID('tablename'))
    BEGIN
        -- Index with this name, on this table does NOT exist
    END
Answer from AdaTheDev on Stack Overflow
🌐
SQLServerCentral
sqlservercentral.com › home › topics › if exists drop index ... if not exists create index
IF EXISTS DROP INDEX ... IF NOT EXISTS CREATE INDEX – SQLServerCentral Forums
August 13, 2012 - IF EXISTS (SELECT 1 FROM sys.indexes WHERE name = 'Index name here' AND object_id = OBJECT_ID('Table Name Here') DROP INDEX .... CREATE INDEX ... Gail Shaw Microsoft Certified Master: SQL Server, MVP, M.Sc (Comp Sci) SQL In The Wild: Discussions on DB performance with occasional diversions into recoverability
Discussions

azure sql database - SQL Server: "if not exists... create index" pattern fails "because an index or statistics already exists" - Stack Overflow
I need reliable code to say "create index if it doesn't already exist." I thought I had it: IF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = ' More on stackoverflow.com
🌐 stackoverflow.com
sql server - Create an index without redundant code - Database Administrators Stack Exchange
I need a simple index creation script in a stored procedure as part of my database project. If the index in question already exists, I want to recreate it, to ensure that no other process has chan... More on dba.stackexchange.com
🌐 dba.stackexchange.com
July 11, 2017
sql - Creating index if index doesn't exist - Stack Overflow
I have a problem creating an index with the advantage database server if it doesn't exist with a sql query. My query looks like this: If not Exists( More on stackoverflow.com
🌐 stackoverflow.com
postgresql - Create index if it does not exist - Database Administrators Stack Exchange
I am working on a function that allows me to add an index if it does not exist. I am running into the problem that I cannot get a list of indexes to compare to. Any thoughts? This is a similar iss... More on dba.stackexchange.com
🌐 dba.stackexchange.com
November 27, 2015
🌐
Microsoft Learn
learn.microsoft.com › en-us › sql › t-sql › statements › create-index-transact-sql
CREATE INDEX (Transact-SQL) - SQL Server | Microsoft Learn
1 week ago - Specifies not to drop and rebuild the existing index. SQL Server displays an error if the specified index name already exists.
🌐
Medium
medium.com › @qingedaig › sql-server-build-index-step-by-step-e0cacf4f4cab
sql server: build index step by step | by Alice Dai | Medium
June 11, 2025 - This script conditionally creates a filtered nonclustered index on the exampleTable table, targeting performance optimization — specifically when filtering on ReID IS NOT NULL. ... IF NOT EXISTS ( SELECT * FROM sys.indexes WHERE name = 'IDX_HID' AND object_id = OBJECT_ID('exampleTable') ) This block checks SQL Server’s system catalog to see if an index named IDX_HID already exists on the exampleTable table.
🌐
Kendralittle
kendralittle.com › 2016 › 01 › 28 › how-to-check-if-an-index-exists-on-a-table-in-sql-server
How to Check if an Index Exists on a Table in SQL Server
January 28, 2016 - It was created with this code: CREATE NONCLUSTERED INDEX ix_halp ON agg.FirstNameByYear (ReportYear) INCLUDE (FirstNameId, Gender, NameCount); GO · Let’s say we’re running code that is going to create the index if it does NOT exist.
🌐
GitHub
github.com › jOOQ › jOOQ › issues › 7961
CREATE INDEX IF NOT EXISTS should intercept error code 1913 in SQL Server · Issue #7961 · jOOQ/jOOQ
The operation failed because an index or statistics with name 'INDEX_NAME' already exists on table · Used dslContext.createIndexIfNotExists("INDEX_NAME"), with jooq version 3.9.5 same code did work. jOOQ: 3.11.5 · Java: 1.8.0_121 · Database (include vendor): Microsoft SQL Server 2016 (SP1) (KB3182545) - 13.0.4001.0 (X64) Oct 28 2016 18:17:30 Copyright (c) Microsoft Corporation Developer Edition (64-bit) on Windows Server 2016 Standard 6.3 (Build 14393: ) (Hypervisor) OS: Windows · JDBC Driver (include name if inofficial driver): com.microsoft.sqlserver mssql-jdbc 7.0.0.jre8 ·
Author   jOOQ
Find elsewhere
🌐
HTTP Glossary
cryer.co.uk › brian › sqlserver › howtocreateindexunlessexists.htm
Cry How To - Create index unless it exists
if not exists (select * from sysindexes where id=object_id('Employees') and name='IE1Employee') create index IE1Employee on Employees(name) go · These notes have been tested against SQL Server 7, SQL Server 2000, SQL Server 2005 and SQL Server 2008.
Top answer
1 of 3
3

In SQL Server 2016, this is very easy, you just need to make a choice between having simple scripts or enjoying whatever performance you've actually observed from DROP_EXISTING (is this quantifiable? Have you tested it?).

CREATE TABLE dbo.what(i int, INDEX x(i));
GO

DROP INDEX IF EXISTS dbo.what.x;
GO

CREATE INDEX x ON dbo.what(i DESC);
GO
2 of 3
4

So, your requirements are:

  • Create all indexes on the list, dropping and replacing existing indexes.
  • If the index does exist, use WITH (DROP_EXISTING = ON).
  • No repetition of the code to create the index.

I only see two options that would do this:

Option 1: Dynamic SQL

Build the basic CREATE INDEX command; then, if the index exists, tack on the DROP_EXISTING clause.

DECLARE @stmt NVARCHAR(MAX);

SET @stmt = N'
CREATE NONCLUSTERED INDEX [IX_a]
       ON [dbo].animals
       INCLUDE([ID], [Currency])'
+ CASE WHEN EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[animals]') AND name = N'IX_a')
    THEN N' WITH (DROP_EXISTING = ON)'
    ELSE N''
  END
+ N';'
;

EXECUTE sp_executesql @stmt;

Obviously, this solution has some issues of its own. In general, you have to maintain the statements as strings. The biggest issues here are that you have to remember to double any single quotes that should be in the statement. As the sample statement has none, this may not turn out to be an issue, but it must be noted. In particular, the statement must be altered if need other WITH options set. Again, in this example, that's not an issue. If all statements did have existing WITH options to include, it would be a huge issue either (though the statement would need tweaked:

SET @stmt = N'
CREATE NONCLUSTERED INDEX [IX_a]
       ON [dbo].animals
       INCLUDE([ID], [Currency]) WITH (DATA_COMPRESSION = PAGE'
+ CASE WHEN EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[animals]') AND name = N'IX_a')
    THEN N', DROP_EXISTING = ON'
    ELSE N''
  END
+ N');'
;



Option 2: create a "dummy" index

Note that I wouldn't recommend this; it's actually at least as hard to maintain as simply having two copies of the CREATE INDEX statement, and causes extra work on the system. However, if you would expect that the index would almost always be there, it might be useful.

First, you create an index with the name you want (the columns don't matter); then, replace it with the index you actually want.

IF NOT EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[animals]') AND name = N'IX_a')
    CREATE NONCLUSTERED INDEX [IX_a]
           ON [dbo].[animals] ([BioNr] ASC);

CREATE NONCLUSTERED INDEX [IX_a]
       ON [dbo].animals
       INCLUDE([ID], [Currency]) WITH (DROP_EXISTING = ON);

As I said, I wouldn't recommend it, but it would (technically, at least) meet your requirements, so I thought I should mention it.


Final Note

It's probably worth posting a CONNECT item, requesting that DROP_EXISTING = ON be allowed whether the index exists or not (if you can't find an existing one, at least). It seems entirely reasonable for the option to simply be ignored if the index doesn't exist.

🌐
MariaDB
mariadb.com › kb › en › create-index
CREATE INDEX | Server | MariaDB Documentation
CREATE [OR REPLACE] [UNIQUE|FULLTEXT|SPATIAL|VECTOR] INDEX [IF NOT EXISTS] index_name [index_type] ON tbl_name (index_col_name,...) [WAIT n | NOWAIT] [index_option] [algorithm_option | lock_option] ...
🌐
Microsoft Learn
learn.microsoft.com › en-us › sql › relational-databases › indexes › create-nonclustered-indexes
Create Nonclustered Indexes - SQL Server | Microsoft Learn
November 22, 2024 - IF EXISTS (SELECT name FROM sys.indexes WHERE name = N'IX_ProductVendor_VendorID') DROP INDEX IX_ProductVendor_VendorID ON Purchasing.ProductVendor; GO -- Create a nonclustered index called IX_ProductVendor_VendorID -- on the Purchasing.ProductVendor table using the BusinessEntityID column.
Top answer
1 of 2
137

Index names in PostgreSQL

  • Index names are unique across a single database schema.
  • Index names cannot be the same as any other index, (foreign) table, (materialized) view, sequence or user-defined composite type in the same schema.
  • Two tables in the same schema cannot have an index of the same name. (Follows logically.)

If you do not care about the name of the index, have Postgres auto-name it:

CREATE INDEX ON tbl1 (col1);

is (almost) the same as:

CREATE INDEX tbl1_col1_idx ON tbl1 USING btree (col1);

Except that Postgres will avoid a naming collisions and automatically pick the next free name:

tbl1_col1_idx 
tbl1_col1_idx2
tbl1_col1_idx3
...

Just try it. But, obviously, you would not want to create multiple redundant indexes. So it wouldn't be a good idea to just blindly create a new one.

Test for existence

Postgres 9.5 or newer

Now available:

CREATE INDEX IF NOT EXISTS ...

Also works for CREATE INDEX CONCURRENTLY IF NOT EXISTS.

However, the manual warns:

Note that there is no guarantee that the existing index is anything like the one that would have been created.

It's a plain check for the object name. (Applies to variants for older versions below, too.)
To find existing indexes on the same table for the same column(s):

SELECT pg_get_indexdef(indexrelid)
FROM   pg_index
WHERE  indrelid = 'public.big'::regclass
AND   (indkey::int2[])[:] = ARRAY (
   SELECT attnum
   FROM   unnest('{usr_id, created_at}'::text[]) WITH ORDINALITY i(attname, ord)
   JOIN  (
      SELECT attname, attnum
      FROM   pg_attribute
      WHERE  attrelid = 'public.big'::regclass
      ) a USING (attname)
   ORDER BY ord
   );

Restrictions:

  • Only works for columns, not other index expressions.
  • Also reports partial indexes (with WHERE clause) and covering indexes (with INCLUDE clause).
  • Reports any type of index, not just B-tree indexes.

Study the results (if any) before proceeding, or refine the query to your needs ...

Further reading:

  • Find tables with multiple indexes on same column
  • Normalize array subscripts for 1-dimensional array so they start with 1

Postgres 9.4

You can use the new function to_regclass() to check without throwing an exception:

DO
$$
BEGIN
   IF to_regclass('myschema.mytable_mycolumn_idx') IS NULL THEN
      CREATE INDEX mytable_mycolumn_idx ON myschema.mytable (mycolumn);
   END IF;

END
$$;

Returns NULL if an index (or another object) of that name does not exist. See:

  • How to check if a table exists in a given schema

This doesn't work for CREATE INDEX CONCURRENTLY, since that variant cannot be wrapped in an outer transaction. See comment by @Gregory below.

Postgres 9.3 or older

Cast the schema-qualified name to regclass:

SELECT 'myschema.myname'::regclass;

If it throws an exception, the name is free.
Or, to test the same without throwing an exception, use a DO statement:

DO
$$
BEGIN
   IF NOT EXISTS (
      SELECT
      FROM   pg_class c
      JOIN   pg_namespace n ON n.oid = c.relnamespace
      WHERE  c.relname = 'mytable_mycolumn_idx'
      AND    n.nspname = 'myschema'
   ) THEN
    
        CREATE INDEX mytable_mycolumn_idx ON myschema.mytable (mycolumn);
    END IF;
END
$$;

The DO statement was introduced with Postgres 9.0. In earlier versions you have to create a function to do the same.
Details about pg_class in the manual.
Basics about indexes in the manual.

2 of 2
13

It will be available in 9.5. Here is actual git commit https://github.com/postgres/postgres/commit/08309aaf74ee879699165ec8a2d53e56f2d2e947

Discussion on pg hackers http://postgresql.nabble.com/CREATE-IF-NOT-EXISTS-INDEX-td5821173.html

🌐
Sqlespresso
sqlespresso.com › home › performance tuning › sql index creation using drop existing= on
SQL Index Creation Using DROP EXISTING= ON - A Shot of SQLEspresso
February 17, 2021 - DROP INDEX IF EXISTS [dcacIDX_ServiceType] ON [dbo].[Accounts] GO CREATE NONCLUSTERED INDEX [dcacIDX_ServiceType] ON [dbo].[Accounts] ( [ServiceType] ASC ) INCLUDE([AccountId] WITH (STATISTICS_NORECOMPUTE = OFF, DROP_EXISTING = OFF, ONLINE = OFF, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] GO · Now I should also note that the DROP_EXISITING method is also faster when you must modify a Clustered index. Every Non-Clustered index refers to the Clustered index using what is called a clustering key, essentially, a pointer to the row in the clustered index. When a clustered index is dropped and re-created, SQL Server must rebuild the Non-Clustered indexes on that table.
🌐
Couchbase
couchbase.com › sql++
Create index if not exists - SQL++ - Couchbase Forums
April 14, 2020 - I have been tried to create index only if one does not exists by issue CREATE INDEX NOT EXISTS typeId_index ON fmm-schema(typeId) But I keep getting the following error: [ { “code”: 3000, “msg”: “syntax error - at NOT”, “query_from_user”: “CREATE INDEX NOT EXISTS typeId_index ON fmm-schema(typeId)” } ] But according to https://docs.couchbase.com/server/6.5/analytics/5_ddl.ht, it seems I should be able to do that.
🌐
tutorialpedia
tutorialpedia.org › blog › add-index-to-table-if-it-does-not-exist
How to Add an Index to a Table Only If It Doesn’t Exist: A Guide Using ALTER TABLE Syntax
DO $$ BEGIN IF NOT EXISTS ( SELECT ... = 'customers' AND indexname = 'idx_customers_email' ) THEN CREATE INDEX idx_customers_email ON customers (email); END IF; END $$; ... SELECT indexname FROM pg_indexes WHERE schemaname = 'public' ...
🌐
Oracle
docs.oracle.com › en › database › other-databases › nosql-database › 22.1 › sqlreferencefornosql › create-index.html
CREATE INDEX Statement
June 16, 2022 - Syntax · create_index_statement ::= CREATE INDEX [IF NOT EXISTS] index_name ON table_name "(" path_list ")" [WITH NO NULLS][comment] index_name ::= id path_list ::= index_path ("," index_path)* index_path ::= name_path [path_type] | multikey_path_prefix [.name_path] [path_type] name_path ::= ...