SQL Server : cannot create index on view because it references derived table. - sql

How can I add a clustered index to the following view?
CREATE VIEW [vExcludedIds]
WITH SCHEMABINDING
AS
SELECT DISTINCT
TempTable.Id
FROM
(VALUES (1), (2), (3)) AS TempTable(Id)
And my index creation command is:
CREATE UNIQUE CLUSTERED INDEX IDX_V1
ON [vExcludedIds] (Id);
And I get the following error:
Cannot create index on view "Test.dbo.vExcludedIds" because it references derived table "TempTable" (defined by SELECT statement in FROM clause). Consider removing the reference to the derived table or not indexing the view.
Also, when I try to add the index manually in SQL Server Management Studio, I get an error at the top of "New Index" window saying:
HasClusteredColumnStoreIndex: unknown property.
Any ideas please?

Please read https://msdn.microsoft.com/en-AU/library/ms191432.aspx
There are a lot of limitations for creating indexed views.
...
The SELECT statement in the view definition must not contain the following Transact-SQL elements:
DISTINCT
Derived table
Consider creating a table or table function

Related

Inserting from one table or view into another but avoid combination duplicates- Can this be done in SQL? If so how?

I have a table that has a primary key WORKITEMID, and the following 3 foreign keys PRODSERVID,PROCESSID,and TASKKNOWID.
I have a view that I can create that also has PRODSERVID,PROCESSID, AND TASKKNOWID. This view will usually have ALL the records in above table plus some new ones - not in the table. The 'table' by definition is meant to hold the unique combinations of PRODSERVID, PROCESSID, and TASKKNOWID.
I would like to insert from the view into the table any new combinations in the view not present in the table. And I don't want to overwrite the existing WORKITEMIDs in the INSERT- because those WORKITEMIDs are used elsewhere.
Can this be done in SQL?
Thanks
Absolutely, the simplest form of criteria for this is to use the negation of EXISTS()
INSERT INTO [TableName] (PRODSERVID,PROCESSID,TASKKNOWID,... )
SELECT PRODSERVID,PROCESSID,TASKKNOWID,...
FROM [ViewName] v
WHERE NOT EXISTS (
SELECT 1 FROM [TableName] t
WHERE t.PRODSERVID = v.PRODSERVID AND t.PROCESSID = v.PROCESSID AND t.TASKKNOWID = v.TASKKNOWID
)
replace the ... with your other fields
You could also use a non-corellating outer join but I find not exists makes the intent much clearer.
There is a good comparison of the different approaches to this issue in this article: T-SQL commands performance comparison – NOT IN vs SQL NOT EXISTS vs SQL LEFT JOIN vs SQL EXCEPT

How can I copy a Redshift table but add a sortkey to a column?

I'm currently working on a project that uses a Redshift table with 51 columns. However, the person who made the table forgot to add a sortkey to our time column which will hurt performance for our use case if we don't add it.
How can I make a version of the table with our time column as the sortkey? I'm aware that you can't make a column a sortkey if its a member of an existing table, but I was hoping there's a way to do it that doesn't involve writing out the CREATE TABLE syntax by hand; for example, something like this would be nice:
timecube=# CREATE TABLE foo (like bar) sortkey(time);
ERROR: CREATE TABLE LIKE is not supported with DISTSTYLE, DISTKEY(), or SORTKEY() clauses
but as you can see its not supported. Is there another way? As we're still developing we don't need any of existing data.
Using traditional tools like pgdump didn't work well because they don't include any of the Redshift extras like encoding.
Redshift supports specifying the DIST and SORT keys as part of CREATE TABLE AS statements, as per the docs.
CREATE TABLE table_name
DISTSTYLE KEY
DISTKEY ( column )
SORTKEY ( column )
AS
(SELECT *
FROM source_table)
;
First step you need to do use get create table statement for existing table. Then create new table this time add sort key to new table.
Check encoding for old table ( when you load data using copy command it automatically adds compression encodings)
select "column", type, encoding
from pg_table_def where tablename = 'old_table'
When creating new table add encoding type for each column. Create table with Sort key .
Once new table is created use below command
insert into new table ( select * from old table order by time asc)

creating table as select is dropping the not null constraints in postgresql

in postgres sql creating the table as select dropped the not null constraints on the table.
for example :
create table A (char a not null);
create table B as select * from a;
select * from B;-- no constraint is copied from A table
please let me know how to copy table data as well as constraints in postgres.
There is no single-command solution to this.
To create a table based on an existing one, including all constraints, use:
create table B ( like a including constraints);
Once you have done that, you can copy the data from the old one to the new one:
insert into b
select * from a;
If you do this in a single transaction, it looks like an atomic operation to all other sessions connected to the database.
very detailed and nicely explained tutorial for create table command in PostgreSQL 9.1
http://www.postgresql.org/docs/current/static/sql-createtable.html
Not null constraints are always copied (if creating table by giving reference of parent table in create table command) and even with including constraints, only check constraint will be copied.

Practical limitations of expression indexes in PostgreSQL

I have a need to store data using the HSTORE type and index by key.
CREATE INDEX ix_product_size ON product(((data->'Size')::INT))
CREATE INDEX ix_product_color ON product(((data->'Color')))
etc.
What are the practical limitations of using expression indexes? In my case, there could be several hundred different types of data, hence several hundred expression indexes. Every insert, update, and select query will have to process against these indexes in order to pick the correct one.
I've never played with hstore, but I do something similar when I need an EAV column, e.g.:
create index on product_eav (eav_value) where (eav_type = 'int');
The limitation in doing so is that you need to be explicit in your query to make use of it, i.e. this query would not make use of the above index:
select product_id
from product_eav
where eav_name = 'size'
and eav_value = :size;
But this one would:
select product_id
from product_eav
where eav_name = 'size'
and eav_value = :size
and type = 'int';
In your example it should likely be more like:
create index on product ((data->'size')::int) where (data->'size' is not null);
This should avoid adding a reference to the index when there is no size entry. Depending on the PG version you're using the query may need to be modified like so:
select product_id
from products
where data->'size' is not null
and data->'size' = :size;
Another big difference between regular and partial index is that the latter cannot enforce a unique constraint in a table definition. This will succeed:
create unique index foo_bar_key on foo (bar) where (cond);
The following won't:
alter table foo add constraint foo_bar_key unique (bar) where (cond);
But this will:
alter table foo add constraint foo_bar_excl exclude (bar with =) where (cond);

Index View Index Creation Failing

I'm trying to create an index on a view and it keeps failing, I'm pretty sure its b/c I'm using an alias for the column. Not sure how or if I can do it this way. Below is a simplified scenario.
CREATE VIEW v_contracts WITH SCHEMABINDING
AS
SELECT
t1.contractid as 'Contract.ContractID'
t2.name as 'Customer.Name'
FROM contract t1
JOIN customer t2
ON t1.contractid = t2.contractid
GO
CREATE UNIQUE CLUSTERED INDEX v_contracts_idx ON v_contracts(t1.contractid)
GO
---------------------------
Incorrect syntax near '.'.
CREATE UNIQUE CLUSTERED INDEX v_contracts_idx ON v_contracts(contractid)
GO
---------------------------
Column name 'contractid' does not exist in the target table or view.
CREATE UNIQUE CLUSTERED INDEX v_contracts_idx ON v_contracts(Contract.ContractID)
GO
---------------------------
Incorrect syntax near '.'.
Anyone know how to create an indexed view using aliased columns please let me know.
try using brackets around the column name because the name is not a valid column name
CREATE UNIQUE CLUSTERED INDEX v_contracts_idx
ON v_contracts([Contract.ContractID])
GO
Also indexed views require 5 or so SET options to be on, more info here: http://msdn.microsoft.com/en-us/library/ms191432.aspx
How about a comma between the two columns???
SELECT
t1.contractid as 'Contract.ContractID' -- <=== comma missing here
t2.name as 'Customer.Name'
And I probably wouldn't really use "Contract.ContractID" as my alias..... the dotted notation has special meaning in SQL Server (database.schema.object) - so I would avoid anything that could cause trouble there.....
CREATE VIEW v_contracts WITH SCHEMABINDING
AS
SELECT
t1.contractid as 'ContractID' , -- comma here at the end!!
t2.name as 'CustomerName'
FROM contract t1
JOIN customer t2 ON t1.contractid = t2.contractid
GO
CREATE UNIQUE CLUSTERED INDEX v_contracts_idx ON v_contracts(ContractID)
GO
Why are you aliasing the tables if you are simply going to re-alias the columns back to the original?? Just do
CREATE VIEW v_contracts WITH SCHEMABINDING
AS
SELECT
Contract.ContractID,
Customer.Name
FROM contract
JOIN customer
ON contract.contractid = customer.contractid
GO
And yes, you were missing a comma.