Showing posts from March, 2017Show All
What are indexed views? Or What are materialized views?
Why do SQL Server Views needs to be refreshed every once in a while? How to Refresh View?
Whar are the Limitations of VIEW in SQL Server?

Difference between View and CTE

Views can be indexed but CTE can't. So this is one important point.

CTE work excellent on tree hierarchyi.e. recursive

Also, consider views when dealing with complex queries. Views being a physical object on database (but does not store data physically) and can be used on multiple queries, thus provide flexibility and centralized approach. CTE, on the other hand are temporary and will be created when they are used; that's why they are called as inline view.

What is Schemabinding?

 In SQL Server, when we use the “WITH SCHEMABINDING” clause in the definition of an object (view or function), we bind the object to the schema of all the underlying tables and views. This means that the underlying tables and views cannot be modified in a way that would affect the definition of the schema-bound object. It also means that the underlying objects cannot be dropped. We can still modify those tables or views, as longs as we don’t affect the definition of the schema-bound object (view or function).

If we reference a view or function in a schema-bound object (view or function), then the underlying view or function must also be schema-bound. And we cannot change the collation of a database, if it contains schema-bound objects

For schema binding, SQL server requires a more specific and safer SELECT statement. There are a couple of restrictions, which we must remember:

  1. We must use two-part names, when referencing tables, views or functions (SchemaName.ObjectName).

  2. We cannot use SELECT *, so we must choose specific column names. Otherwise, we will get the following error:

Msg 1054, Level 15, State 6, Procedure vwName, Line x

Syntax ‘*’ is not allowed in schema-bound objects.

We cannot run sys.sp_refreshview on a schema-bound view (or sys.sp_refreshsqlmodule on a schema-bound function).

We will get an unhelpful error, something like:

Could not find object ‘vwName’ or you do not have permission.

What are indexed views? Or What are materialized views?

 A view is a virtual table that means it does not contain any physical data. A view is nothing more than a compiled SQL query. Every time, we issue a select query against a view, we actually get the data from the underlying base tables and not from the view, as the view itself does not contain any data.

When we create an index on a view, the data gets physically stored in the view. So, when we issue a select query against an indexed view, the data is retrieved from the index without having to go to the underlying table, which will make the select statement to work slightly faster. However, the disadvantage is INSERT, UPDATE and DELETE operations will become a little slow, because every time we insert or delete a row from the underlying table, the view index needs to be updated. In short, DML operations will have a negative impact on performance.

Oracle refers to indexed views as materialized views.

Only the views created with schema binding can have an Index. Simply adding WITH SCHEMABINDING to the end of the CREATE VIEW statement will accomplish this. However, the effect is that any changes to the underlying tables which will impact the view are not allowed. Since the indexed view is stored physically, any schema changes would impact the schema of the stored results set. Therefore, SQL Server requires that schema binding is used to prevent the view’s schema (and therefore the underlying tables) from changing.

The first index for a view must be a UNIQUE CLUSTERED INDEX, after which, it’s possible to create non-clustered indexes against the view.

Indexed Views are heavily used in data warehouses and reporting databases that are not highly transactional.

Let's now, look at an example of creating an Indexed view. For the purpose of this video, we will be using tblProduct and tblProductSales tables.

Script to create table tblProduct
Create Table tblProduct
(
ProductId int primary key,
Name nvarchar(20),
UnitPrice int
)

Script to pouplate tblProduct, with sample data
Insert into tblProduct Values(1, 'Books', 20)
Insert into tblProduct Values(2, 'Pens', 14)
Insert into tblProduct Values(3, 'Pencils', 11)
Insert into tblProduct Values(4, 'Clips', 10)

Script to create table tblProductSales
Create Table tblProductSales
(
ProductId int,
QuantitySold int
)

Script to pouplate tblProductSales, with sample data
Insert into tblProductSales values(1, 10)
Insert into tblProductSales values(3, 23)
Insert into tblProductSales values(4, 21)
Insert into tblProductSales values(2, 12)
Insert into tblProductSales values(1, 13)
Insert into tblProductSales values(3, 12)
Insert into tblProductSales values(4, 13)
Insert into tblProductSales values(1, 11)
Insert into tblProductSales values(2, 12)
Insert into tblProductSales values(1, 14)

tblProduct Table


tblProductSales Table


Create a view which returns Total Sales and Total Transactions by Product. The output should be, as shown below.


Script to create view vWTotalSalesByProduct
Create view vWTotalSalesByProduct
with SchemaBinding
as
Select Name, 
SUM(ISNULL((QuantitySold * UnitPrice), 0)) as TotalSales, 
COUNT_BIG(*) as TotalTransactions
from dbo.tblProductSales
join dbo.tblProduct
on dbo.tblProduct.ProductId = dbo.tblProductSales.ProductId
group by Name

If you want to create an Index, on a view, the following rules should be followed by the view. For the complete list of all rules, please check MSDN.

1. The view should be created with SchemaBinding option

2. If an Aggregate function in the SELECT LIST, references an expression, and if there is a possibility for that expression to become NULL, then, a replacement value should be specified. In this example, we are using, ISNULL() function, to replace NULL values with ZERO.

3. If GROUP BY is specified, the view select list must contain a COUNT_BIG(*) expression

4. The base tables in the view, should be referenced with 2 part name. In this example, tblProduct and tblProductSales are referenced using dbo.tblProduct and dbo.tblProductSales respectively.

Now, let's create an Index on the view:
The first index that you create on a view, must be a unique clustered index. After the unique clustered index has been created, you can create additional nonclustered indexes.
Create Unique Clustered Index UIX_vWTotalSalesByProduct_Name
on vWTotalSalesByProduct(Name)

Since, we now have an index on the view, the view gets materialized. The data is stored in the view. So when we execute Select * from vWTotalSalesByProduct, the data is retrurned from the view itself, rather than retrieving data from the underlying base tables.

Indexed views, can 
significantly improve the performance of queries that involves JOINS and Aggeregations. The cost of maintaining an indexed view is much higher than the cost of maintaining a table index.

Indexed views are ideal for scenarios, where the underlying data is not frequently changed. Indexed views are 
more often used in OLAP systems, because the data is mainly used for reporting and analysis purposes. Indexed views, may not be suitable for OLTP systems, as the data is frequently addedd and changed.

Ref: 

https://csharp-video-tutorials.blogspot.com/2012/09/indexed-views-in-sql-server-part-41.html

Can we create a view based on other views?

 Yes, we can create a view based on other views. Usually, we create views based on tables, but it is also possible to create views based on views.


Ref: 

https://dotnettutorials.net/lesson/sql-server-views-interview-questions-answers/

Why do SQL Server Views needs to be refreshed every once in a while? How to Refresh View?

When a view is created in SQL Server, metadata for the referenced table columns (column name and ordinal position) is persisted in the database. Any change to the referenced base table(s) (column re-ordering, new column addition, etc) will not be reflected in the view until the view is either:

  • Altered with an ALTER VIEW statement
  • Recreated with DROP VIEW/CREATE VIEW statements
  • Refreshed using system stored procedure sp_refreshview

    The following example creates a table and an associated view

    create table dbo.Customer
    (
    customer_id int identity(1,1) not null primary key,
    firstname nvarchar(40) not null,
    lastname nvarchar(40) not null,
    birthdate datetime null
    )
    go

    insert into dbo.Customer (firstname, lastname, birthdate)
    select 'George', 'Washington', '1950-07-01'

    insert into dbo.Customer (firstname, lastname, birthdate)
    select 'James', 'Madison', '1948-11-09'

    insert into dbo.Customer (firstname, lastname, birthdate)
    select 'Alexander', 'Hamilton', '1970-03-02'
    go

    create view dbo.v_Customer
    as
    select * from dbo.Customer
    go



    Running the view using select * from dbo.v_Customer, we see the following output:



    A new business requirement has now been identified; we need to add a last order date to keep track of the last time this customer ordered stock from our warehouse:
     

    alter table dbo.Customer
    add last_order_date datetime null
    go
    exec sp_help [dbo.Customer]
    go


    As we can see, the last_order_date has been added to the table.  However, running our view again we get the same output as before the column change!



    This occurs because the view's metadata information about the table needs to be updated; it's not maintained automatically. This can be corrected using one of the methods mentioned at the beginning of this tip. My preference is to use sp_refreshview since I don't have to hunt down the view and issue a DROP VIEW/CREATE VIEW and re-grant permissions or issue an ALTER VIEW statement:
     

    exec sp_refreshview [dbo.v_customer]
    go
    select * from dbo.v_customer
    go

    As you can see, the view now returns all columns including the newly added one.



    I find that this can always be avoided by not issuing "SELECT *" in your view definitions. By explicitly defining a column list, you're forced to change any views that reference tables that may require a change. Another approach is to issue your CREATE VIEW statements with a SCHEMABINDING option. Views defined with this option do not allow SELECT * syntax (you'll receive an error if you try) and forces you to enter an explicit column list. This way, you can prevent a less experienced developer from changing a view to use this syntax

    If you're curious about how your view metadata is being stored, you can take a peek at the INFORMATION_SCHEMA.COLUMNS view (view column information is kept there as well as table column information).

  • Whar are the Limitations of VIEW in SQL Server?

    1. You can't create a parameterized view, in other words you can't create a view with a parameter.
      For example:
      CreateView vw_OrdersNorthwind
      @OrderID  int
      As
      select
       CustomerID,ShipCity,ShipCountryfrom orders orderby OrderID descgo
      Error: It will give you an incorrect syntax error.
       
    2. Views are not based on temporary tables, if we try to create one then it gives us a massage.

      An example is as follows:

      Step 1: Temp table creation
      createtable ##MobileDetails( ID int NOTNull ,MobileNamenvarchar(50),CompanyName nvarchar (50))
      Step 2: Insert a few records into the TempTable:
      insertinto  ##MobileDetailsvalues (1,'Galaxy S2','Samsung')insertinto  ##MobileDetailsvalues (1,'Nokia Lumia','Nokia')insertinto  ##MobileDetailsvalues (1,'IPhone5','IPhone');insertinto  ##MobileDetailsvalues (1,'Blackberry Z10','Blackberry');
      Step 3: Creation of a view on the TempTable.
      createview vw_onTempTableas
      select
       MobileName,CompanyNamefrom ##MobileDetailsgo
      An error prompted by the SQL Server after running the preceding command.

      Msg 4508, Level 16, State 1, Procedure vw_onTempTable, Line 3
      Views or functions are not allowed on temporary tables. Table names that begin with '#' denote temporary tables.
       
    3. You can't use an order by clause at the time of view creation. Kindly have a look at an example below:

      Let's run the following command in the query editor of SQLServer:
      CreateView vw_OrdersNorthwindAs
      select
       OrderID,CustomerID,ShipCity,ShipCountryfrom orders orderby OrderID descgo
      It issues the error:

      Msg 1033, Level 15, State 1, Procedure vw_OrdersNorthwind, Line 3
      The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries, and common table expressions, unless TOP or FOR XML is also specified.

      It clearly specifies to use TOP or FOR XML in your TSQL.

      Now I make some changes in the preceding query and run it again.
      CreateView vw_OrdersNorthwindAs
      select
      top 100 OrderID,CustomerID,ShipCity,ShipCountryfrom orders orderby OrderID descgo
      Now select the records from the View and run this query.
      Select* from vw_OrdersNorthwind
       
      image1.jpg
    4. All the tables referenced by the view must be in the same database as the view.
    5. An indexed view must be created with the SCHEMABINDING option. This option prohibits the schema of the base tables from being changed, for example adding or dropping a column.
    6. If you add any new column to a table then it would not be reflected in the View untill you won't run the 
      EXEC sp_refreshview 'ViewName'.

      Don't use Select *, just use a select specific columnnames
      It's a best practice to create a view with SCHEMABINDING using this, the base table will not be modified.
       
    7. You can't use count (*) in a view creation query, for example:
      CreateView vw_OrdersNorthwindAs--select OrderID,CustomerID,ShipCity,ShipCountry from orders selectcount(*) from ordersgo
      It also forces you to supply any column value.

      Msg 4511, Level 16, State 1, Procedure vw_OrdersNorthwind, Line 4
      Create View or Function failed because no column name was specified for column 1.
            Workaround of this issue is  use the following syntax:

    CreateView vw_OrdersNorthwindAs--select OrderID,CustomerID,ShipCity,ShipCountry from orders select count(*) As Total from ordersgo

    select * from vw_OrdersNorthwind 

    Are Views Updateable?

     Is it possible to Insert, Update and delete rows, from the underlying tblEmployees table, using view vWEmployeesDataExceptSalary?

    Yes & No, depending on the number of base tables, the VIEW is created upon, and the number of base tables affected by the UPDATE statement. 


    1. A View is based on a single base table, then the UPDATE suceeds and works as expected.
    2. A View is based on more than one base table, and if the UPDATE affects multiple base tables, the update is not allowed and the statement terminates with an error.
    3. A View is based on more than one base table, and if the UPDATE affects only one base table, the UPDATE succeeds(but not as expected always)


     If a view is based on multiple tables, and if you update the view, it may not update the underlying base tables correctly. To correctly update a view, that is based on multiple table, INSTEAD OF triggers are used.

    What is the VIEW and What are their Advantages?

    What is a View?
    A view is nothing more than a saved SQL query. A view can also be considered as a virtual table.


    To select data from the view, SELECT statement can be used the way, we use it with a table.
    SELECT * from vWEmployeesByDepartment

    When this query is executed, the database engine actually retrieves the data from the underlying base tables, tblEmployees and tblDepartments. The View itself, doesnot store any data by default. However, we can change this default behaviour, which we will talk about in a later session. So, this is the reason, a view is considered, as just, a stored query or a virtual table.



    Advantages of using views:
    1. Views can be used to reduce the complexity of the database schema, for non IT users. The sample view, vWEmployeesByDepartment, hides the complexity of joins. Non-IT users, finds it easy to query the view, rather than writing complex joins.

    2. Views can be used as a mechanism to implement row and column level security.
    Row Level Security:
    For example, I want an end user, to have access only to IT Department employees. If I grant him access to the underlying tblEmployees and tblDepartments tables, he will be able to see, every department employees. To achieve this, I can create a view, which returns only IT Department employees, and grant the user access to the view and not to the underlying table.

    View that returns only IT department employees:
    Create View vWITDepartment_Employees
    as
    Select Id, Name, Salary, Gender, DeptName
    from tblEmployee
    join tblDepartment
    on tblEmployee.DepartmentId = tblDepartment.DeptId
    where tblDepartment.DeptName = 'IT'

    Column Level Security:
    Salary is confidential information and I want to prevent access to that column. To achieve this, we can create a view, which excludes the Salary column, and then grant the end user access to this views, rather than the base tables.

    View that returns all columns except Salary column:
    Create View vWEmployeesNonConfidentialData
    as
    Select Id, Name, Gender, DeptName
    from tblEmployee
    join tblDepartment
    on tblEmployee.DepartmentId = tblDepartment.DeptId

    3. Views can be used to present only aggregated data and hide detailed data.

    View that returns summarized data, Total number of employees by Department.

    Create View vWEmployeesCountByDepartment
    as
    Select DeptName, COUNT(Id) as TotalEmployees
    from tblEmployee
    join tblDepartment
    on tblEmployee.DepartmentId = tblDepartment.DeptId
    Group By DeptName