SQL Server Materialized View (Indexed View) error - sql-server

I'm trying to create a Materialized View using Microsoft SQL Server Management Studio 14.0.17285.0. Following is the script I ended up with to achieve the same.
My plan is to create a view and create an index on top of it.
use data_warehouse;
--Set the options to support indexed views.
SET NUMERIC_ROUNDABORT OFF;
SET ANSI_PADDING, ANSI_WARNINGS, CONCAT_NULL_YIELDS_NULL, ARITHABORT,
QUOTED_IDENTIFIER, ANSI_NULLS ON;
GO
CREATE VIEW products_yearly_v2
WITH SCHEMABINDING
AS
SELECT
p.product_id AS product_id,
p.product_description AS product_name,
d.order_year AS order_year,
SUM(s.order_total) AS sal_by_dept
FROM
[data_warehouse].[dbo].orders_fact AS s
INNER JOIN
[data_warehouse].[dbo].time_dimension AS d ON s.time_id = d.order_date
INNER JOIN
[data_warehouse].[dbo].product_dimension AS p ON s.product_id = p.product_id
GROUP BY
d.order_year, p.product_id, p.product_description;
CREATE UNIQUE CLUSTERED INDEX IDX_V1
ON products_yearly_v1 (order_year, product_id);
I'm getting this error:
Msg 156, Level 15, State 1, Procedure products_yearly_v2, Line 12 [Batch Start Line 7]
Incorrect syntax near the keyword 'CREATE'
Update
Added COUNT_BIG(*) in order to create the index.
SELECT COUNT_BIG(*) as count_big, p.product_id as product_id, d.order_year as order_year, sum(s.order_total) AS sal_by_dept ....
Removed product_description from GROUP BY
GROUP BY d.order_year,p.product_id;
Readded,
USE data_warehouse

You need to use 2-part names:
SCHEMABINDING
Binds the view to the schema of the underlying table or tables. When SCHEMABINDING is specified, the base table or tables cannot be modified in a way that would affect the view definition. The view definition itself must first be modified or dropped to remove dependencies on the table that is to be modified. When you use SCHEMABINDING, the select_statement must include the two-part names (schema.object) of tables, views, or user-defined functions that are referenced. All referenced objects must be in the same database.
USE data_warehouse
GO
CREATE VIEW dbo.products_yearly_v2
WITH SCHEMABINDING
AS
SELECT
p.product_id AS product_id,
p.product_description AS product_name,
d.order_year AS order_year,
SUM(s.order_total) AS sal_by_dept
FROM [dbo].orders_fact AS s
JOIN [dbo].time_dimension AS d ON s.time_id = d.order_date
JOIN [dbo].product_dimension AS p ON s.product_id = p.product_id
GROUP BY d.order_year, p.product_id, p.product_description;
GO
-- index on products_yearly_v2 not products_yearly_v1
CREATE UNIQUE CLUSTERED INDEX IDX_V2
ON dbo.products_yearly_v2 (order_year, product_id);

Related

Accees table attribute in Snowflake CTE

use database DQ_MART;
use schema WORKING;
WITH ASCENDER_EMPLOYEE AS (
**SELECT DISTINCT EMPLOYEE_ID FROM RECONCILLIATION_ASCENDER_WORKER_TIMESHEET**
),
WORKDAY_EMPLOYEE AS (
**SELECT DISTINCT EMPLOYEE_ID FROM RECONCILLIATION_WORKDAY_WORKER_TIMESHEET**
)
SELECT 'Missing employee in Ascender' DQ_RULE_NAME,
RECONCILLIATION_WORKDAY_WORKER_TIMESHEET.EMPLOYEE_ID KEY
FROM WORKDAY_EMPLOYEE WORKDAY
LEFT OUTER JOIN ASCENDER_EMPLOYEE ASCENDER
ON ASCENDER.EMPLOYEE_ID = WORKDAY.EMPLOYEE_ID
;
Hi All, I am bit new to Snowflake SQL CTE. In the above query, I am getting an error, Error: invalid identifier 'RECONCILLIATION_WORKDAY_WORKER_TIMESHEET.EMPLOYEE_ID' (line 16) in this line
RECONCILLIATION_WORKDAY_WORKER_TIMESHEET.EMPLOYEE_ID
The select statements where the same table is accessed runs properly.
Te database and schema where the table resides is set correctly and I do have SELECT grant on the tables.
Is there a scope visibility in Snowflake which is causing the error to occur. Any suggestions will be welcome.
"RECONCILLIATION_WORKDAY_WORKER_TIMESHEET.EMPLOYEE_ID" means the column "EMPLOYEE_ID" in the table "RECONCILLIATION_WORKDAY_WORKER_TIMESHEET".
Your select statement that uses this column is:
SELECT <column list>
FROM WORKDAY_EMPLOYEE WORKDAY
LEFT OUTER JOIN ASCENDER_EMPLOYEE ASCENDER
ON ASCENDER.EMPLOYEE_ID = WORKDAY.EMPLOYEE_ID
which doesn't include a table called RECONCILLIATION_WORKDAY_WORKER_TIMESHEET - which is why you are getting the error

SQL Server - indexed view with string_agg

I try to define an indexed view to create full text search index on it.
The view itself is created correctly:
CREATE OR ALTER VIEW dbo.my_view WITH SCHEMABINDING AS
SELECT p.id as protector_id,
p.name as protector_name,
string_agg(cast(c.name as nvarchar(max)), ', ') as crops_names,
count_big(*) as count_big
FROM dbo.protectors p
INNER JOIN dbo.protectors_crops pc on p.id = pc.protector_id
INNER JOIN dbo.crops c on pc.crop_id = c.id
GROUP BY p.id, p.name
But when I try to create an index:
CREATE UNIQUE CLUSTERED INDEX my_view_index ON dbo.my_view (protector_id)
i get an error:
[S0001][10125] Cannot create index on view "dbo.my_view" because it uses aggregate "STRING_AGG". Consider eliminating the aggregate, not indexing the view, or using alternate aggregates. For example, for AVG substitute SUM and COUNT_BIG, or for COUNT, substitute COUNT_BIG.
Documentation doesn't state anything about STRING_AGG, neither I can find any solution to replace it.
Although STRING_AGG is not currently listed as a disalowed element in the current documentation, it is indeed not allowed since it is called out explicitly in the error message. Minimal example:
CREATE TABLE dbo.test_agg(
id int
,col varchar(10)
)
GO
CREATE VIEW dbo.vw_test_agg
WITH SCHEMABINDING
AS
SELECT
id
, STRING_AGG(col, ',') AS col
, COUNT_BIG(*) AS CountBig
FROM dbo.test_agg
GROUP BY id;
GO
Msg 10125, Level 16, State 1, Line 21 Cannot create index on view
"tempdb.dbo.vw_test_agg" because it uses aggregate "STRING_AGG".
Consider eliminating the aggregate, not indexing the view, or using
alternate aggregates. For example, for AVG substitute SUM and
COUNT_BIG, or for COUNT, substitute COUNT_BIG.
Also, note STRING_AGG is a deterministic function so it's not disallowed for that reason:
SELECT
name
, COLUMNPROPERTY(OBJECT_ID(N'dbo.vw_test_agg'), name, 'IsDeterministic') AS IsDeterministic
FROM sys.columns AS c
WHERE
object_id = OBJECT_ID(N'dbo.vw_test_agg')
AND name = N'col';
name
IsDeterministic
col
1
Read the documentation again.
If the view definition contains a GROUP BY clause, the key of the
unique clustered index can reference only the columns specified in
the GROUP BY clause
Don't think string_agg is deterministic - so that is likely another issue. I would skip the inclusion of the name in the view to avoid the extra join and additional overhead. Is Name unique as well or is ID the only guaranteed unique row in your first table? As it stands now, you the tuple <id, name> is unique for your statement.

SQL Server: list of views referencing other views

SQL Server: I would like to produce a list of views that reference other views.
The reason for this so that views can be created int the proper sequence, not having to resort to obscure view names to accomplish this.
Oracle provides this solution:
select * from USER_DEPENDENCIES
where type = 'VIEW'
and referenced_type = 'VIEW'
Which produces the desired result.
I have not found anything similar in SQL Server; I have been referencing INFORMATION_SCHEMA and its various components without success.
Here's a DMV query to get you started.
use tempdb
drop table if exists t
go
create table t(id int, a int, b int)
go
create or alter view v1 as select id, a from t
go
create or alter view v2 as select * from v1
go
select schema_name(v.schema_id) view_schema_name, v.name view_name, d.referenced_entity_name
from
sys.views v
join sys.sql_expression_dependencies d
on v.object_id = d.referencing_id
which outputs
view_schema_name view_name referenced_entity_name
--------------------- -------------- ---------------------------
dbo v1 t
dbo v2 v1
Take a look at sp_depends.
sp_depends 'YourViewNameHere'
You will get 2 recordsets. The first shows the objects that the view depends on, and the second shows the objects that depend on the view.

Error: Could not create index on view "dbo.DataEx". The view contains a self join on "dbo.Classifier"

What is a "self join" correct and full definition? As I understand self join is something like ...FROM Role r1 INNER JOIN Role r2 ON r1.ID = r2.ParenteRoleId
But where the "self join" is in this code:
http://sqlfiddle.com/#!6/e7d058/1
CREATE TABLE dbo.Classifier
(
ID int IDENTITY(1,1) NOT NULL,
Name nvarchar(128) NOT NULL
)
GO
CREATE TABLE dbo.Data
(
ID int IDENTITY(1,1) NOT NULL,
ClassifierID1 int NOT NULL,
ClassifierID2 int NOT NULL
)
GO
CREATE VIEW dbo.DataEx WITH SCHEMABINDING AS
SELECT d.ID, c1.Name as ClassifierName1, c2.Name as ClassifierName2
FROM dbo.Data d
INNER JOIN dbo.Classifier c1 ON d.ClassifierID1=c1.ID
INNER JOIN dbo.Classifier c2 ON d.ClassifierID2=c2.ID
GO
SET ARITHABORT ON
SET CONCAT_NULL_YIELDS_NULL ON
SET QUOTED_IDENTIFIER ON
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
SET NUMERIC_ROUNDABORT OFF
CREATE UNIQUE CLUSTERED INDEX [dbo$DataEx$PK] ON dbo.DataEx
(
[ID]
)
GO
This code throws an error:
Cannot create index on view "testdb.dbo.DataEx". The view contains a self join on "testdb.dbo.Classifier".
I also have tried to avoid this error using FROM dbo.Data d, dbo.Classifier c1, dbo.Classifier c2 WHERE d.ClassifierID1=c1.ID AND d.ClassifierID2=c2.ID but this doesn't help.
As I understand I can't use the same table twice in Indexed Views and I can't do anything with that, but at least I could learn some terminology ..
A self-join is, simply, any join which produces a result set which contains the same table more than once.
It doesn't matter whether the particular join conditions used to introduce each instance of the table mention the other instances of the same table.
(And the bad news, for the meta-question, is that if you're encountering this problem now, it's unlikely that there's a reformulation of your view's query such that it will be indexable)
Check out the msdn document 'Create Indexed Views' click here
Here, it's specified that
The SELECT statement in the view definition must not contain Transact-SQL elements like Self-joins etc

Unable to Increase Column size

I need increase column size of the table , i am using below query to increase the size but i am getting below error
Alter Table Tabl1 Alter Column Col1 VarChar(6) Not NULL
Msg 5074, Level 16, State 1, Line 1
The object 'Tabl1' is dependent on column 'Col1'.
Msg 5074, Level 16, State 1, Line 1
The statistics '_WA_Sys_Col1_5070F446' is dependent on column 'Col1'.
Msg 4922, Level 16, State 9, Line 1
ALTER TABLE ALTER COLUMN Col1 failed because one
or more objects access this column.
Because of same table as a dependency on the column
need help on this
SQL Server automatically adds statistics to a table over time to use when it parses a query and builds a query plan. You have to drop the statistic to change the column. For instance:
drop statistics [dbo].[Tabl1].[_WA_Sys_Col1_5070F446]
However, you should use SSMS to view the columns that are in the _WA_Sys_Col1_5070F446 statistics before you drop it so that you can recreate it. Something like this:
create statistics [_WA_Sys_Col1_5070F446] on [dbo].[Tabl1]([Col1])
But there may be more columns..., so be sure to find out which need to be included before you drop it.
You can run this SQL to find most of the dependencies, it doesn't report the statistics dependencies, but it catches most of the others:
SELECT OBJECT_NAME(d.object_id) AS SP_Or_Function, OBJECT_NAME(d.referenced_major_id) AS TableReferenced
FROM sys.sql_dependencies AS d INNER JOIN
sys.all_sql_modules AS m ON m.object_id = d.object_id
where OBJECT_ID(N'Tabl1') = d.referenced_major_id
GROUP BY OBJECT_NAME(d.object_id), OBJECT_NAME(d.referenced_major_id)
ORDER BY SP_Or_Function, TableReferenced
You can find all statistics used by a given table with this query:
SELECT DISTINCT
OBJECT_NAME(s.[object_id]) AS TableName,
c.name AS ColumnName,
s.name AS StatName,
s.auto_created,
s.user_created,
s.no_recompute,
s.[object_id],
s.stats_id,
sc.stats_column_id,
sc.column_id,
STATS_DATE(s.[object_id], s.stats_id) AS LastUpdated
FROM sys.stats s JOIN sys.stats_columns sc ON sc.[object_id] = s.[object_id] AND sc.stats_id = s.stats_id
JOIN sys.columns c ON c.[object_id] = sc.[object_id] AND c.column_id = sc.column_id
JOIN sys.partitions par ON par.[object_id] = s.[object_id]
JOIN sys.objects obj ON par.[object_id] = obj.[object_id]
WHERE OBJECTPROPERTY(s.OBJECT_ID,'IsUserTable') = 1
AND (s.auto_created = 1 OR s.user_created = 1)
AND object_id(N'Tabl1') = s.[object_id]
Thanks to SQLAuthority for the last two SQL queries:
SQL SERVER – Get the List of Object Dependencies – sp_depends and information_schema.routines and sys.dm_sql_referencing_entities (Gabriel's post)
SQL SERVER – Find Details for Statistics of Whole Database – DMV – T-SQL Script
Here is quote from SQL Server 2000 help:
ALTER COLUMN
The altered column cannot be:
.....
Used in an index, unless the column is a varchar, nvarchar, or varbinary data type, the data type is not changed, and the new size is
equal to or larger than the old size.
Used in statistics generated by the CREATE STATISTICS statement. First remove the statistics using the DROP STATISTICS statement.
Statistics automatically generated by the query optimizer are
automatically dropped by ALTER COLUMN. .....

Resources