column_list in views are displayed as manadory - snowflake-cloud-data-platform

In recent day, <column_list> is added automatically to views, eventhough the parameter is documented as optional: https://docs.snowflake.com/en/sql-reference/sql/create-view.html .
This causes views that are defined as
create view my_view
as
select *
from tbl
to throw an error, if a new field is added to a table, unless the view is refreshed.
Is there a way to define <column_list> as optional?

This behavior is by designand it is decribed at CREATE VIEW - Usage Notes:
View definitions are not dynamic. A view is not automatically updated if the underlying sources are modified such that they no longer match the view definition, particularly when columns are dropped
To reporduce the case:
CREATE OR REPLACE TABLE t AS SELECT 1 AS c;
CREATE VIEW v_t AS SELECT * FROM t;
SELECT * FROM v_t;
ALTER TABLE t ADD COLUMN d INT;
SELECT * FROM v_t;
-- SQL compilation error:
-- View definition for 'PUBLIC.V_T' declared 1 column(s),
-- but view query produces 2 column(s).

Related

Table-valued function refresh

I have a table-valued function (TVF) in SQL Server that looks like this:
CREATE FUNCTION TVF_xyz(#AuditKey INT)
RETURNS TABLE
AS
RETURN
SELECT *
FROM xyz
WHERE AUDIT_KEY = #AuditKey
GO
Now, I added a new column to the xyz table.
When I query using TVF_xyz, it doesn't show me the new column (shows all other columns except newly added).
Query:
SELECT TOP 10 *
FROM TVF_xyz (1543)
I would like to know, how to refresh TVF to show new column.
PS: Select * used in TVF to fetch all columns.
After bit of searching, I found sp_refreshsqlmodule (Transact-SQL), its common behavior of TVF.
In order to refresh TVF, following SP needs to be executed:
EXEC sys.sp_refreshsqlmodule 'TVF_xyz'
https://msdn.microsoft.com/en-us/library/bb386954(v=vs.110).aspx
The following SQL function explicitly states that it returns a TABLE. Therefore, the returned rowset structure is implicitly defined.
sample
CREATE FUNCTION ProductsCostingMoreThan(#cost money)
RETURNS TABLE
AS
RETURN
SELECT ProductID, UnitPrice
FROM Products
WHERE UnitPrice > #cost

SQL Server: view or function contains a self-reference. Views or functions cannot reference themselves directly or indirectly

I'm trying to change the date format of a column stored in a view by doing an ALTER VIEW statement, but it's not working and I'm not sure why.
My query:
ALTER VIEW v_cust_invoices
AS
SELECT
FORMAT(INV_DATE,'MM-dd-yy') as INV_DATE
FROM
v_cust_invoices
I always get the error
View or function 'v_cust_invoices' contains a self-reference. Views or functions cannot reference themselves directly or indirectly
I'm trying to change the date format of INV_DATE to mm-dd-yy (it's currently yy-mm-dd). Can someone help me? Not sure what I'm doing wrong.
Edit: If I do
ALTER VIEW v_cust_invoices
AS
SELECT FORMAT(INV_DATE,'MM-dd-yy') as INV_DATE
FROM INVOICE
instead, it deletes all of the columns except for INV_DATE.
View definition:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE VIEW [dbo].[v_cust_invoices] AS
SELECT
CUSTOMER.CUST_NUM, CUST_LNAME,
CUST_BALANCE, INV_NUM, INV_DATE, INV_AMOUNT
FROM
CUSTOMER, INVOICE
GO
You must change the query so that it does not reference itself.
Look at the current definition of the v_cust_invoices view, at its FROM clause. You will see a reference to a table or to some other view. replace the last line in your query with the last line below, substituting the name of the table (or other view) this view gets it's data from.
ALTER VIEW v_cust_invoices
AS
SELECT FORMAT(INV_DATE,'MM-dd-yy') as INV_DATE,
[Plus all the rest of the output columns
from CURRENT definition of v_cust_invoices]
FROM [here Put the table or other view that is in current view definition]
or, now that op has posted complete view definition:
ALTER VIEW [dbo].[v_cust_invoices] AS
SELECT FORMAT(INV_DATE,'MM-dd-yy') INV_DATE,
CUSTOMER.CUST_NUM, CUST_LNAME,
CUST_BALANCE, INV_NUM, INV_DTE, INV_AMOUNT
FROM CUSTOMER, INVOICE
GO

To add a column to a view

I am now working on a View in SQL Server 2012 which is very long (has around 800 columns). We allow users to add custom columns to the table(A separate UI that allows user to specify column name, type and max length).Once the column is added to the table, it must be reflected in the view too. Is there a way to automatically accomplish this ? Right now, I need to create an alter view statement with the already existing 800+ columns and newly added column. Also, can sp_refreshview be used for this purpose? Looking for some answers. Thanks in advance.
If you manually set which columns are included to view (I mean SELECT column1, column2 FROM), then the automatic update probably isn't possible.
If SELECT * is used in view (bad practice), there is a solution:
exec sp_refreshview [dbo.v_customer]
And its more common form here (update all views).

Order BY is not supported in view in sql server

i am trying to create a view in sql server.
create view distinct_product as
select distinct name from stg_user_dtlprod_allignmnt_vw order by name;
this is showing an error.
error message is:
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.
plz help me out where i am wrong.
You could use TOP with a number that is greater than the number of records:
CREATE VIEW [dbo].[distinct_product]
AS
SELECT DISTINCT TOP 10000000 name
FROM stg_user_dtlprod_allignmnt_vw
ORDER BY name
You cannot use TOP 100 PERCENT since the optimizer recognizes that TOP 100 PERCENT qualifies all rows and does not need to be computed at all, so the ORDER BY wouldn't be guaranteed.
A view cannot be sorted with an ORDER BY clause. You need to put the ORDER BY clause into any query that references the view.
A view is not materialized - the data isn't stored, so how could it be sorted? A view is kind of like a stored procedure that just contains a SELECT with no parameters... it doesn't hold data, it just holds the definition of the query. Since different references to the view could need data sorted in different ways, the way that you do this - just like selecting from a table, which is also an unsorted collection of rows, by definition - is to include the order by on the outer query.
You can't order a view like that when it's created as the message states, unless you follow the other answers from Tim / Raphael, but you can order results selected from a view:
So create it in step 1:
create view distinct_product as
select distinct name
from stg_user_dtlprod_allignmnt_vw
Then order it when you retrieve data:
select *
from distinct_product
order by name

SQL Server Indexed View Error

I realize this is a very contrived example, but I've simplified the full version down to the following which demonstrates the problem:
CREATE VIEW model.Appointments_Partition1
WITH SCHEMABINDING AS
SELECT CONVERT(varchar(15), AppointmentId) as Id,
ap.AppTypeId as AppointmentTypeId,
ap.Duration as DurationMinutes,
ap.AppointmentId as EncounterId,
COUNT_BIG(*) as __count_big
FROM dbo.Appointments ap
JOIN dbo.PracticeCodeTable pct ON SUBSTRING(pct.Code, 1, 1) = ap.ScheduleStatus
AND pct.ReferenceType = 'AppointmentStatus'
WHERE ap.AppTime > 0
GROUP BY CONVERT(varchar(15), AppointmentId), ap.AppTypeId, ap.Duration, ap.AppointmentId
CREATE UNIQUE CLUSTERED INDEX [IX_Appointments_Partition1_Id]
ON model.Appointments_Partition1 ([Id]);
I get:
Msg 8668, Level 16, State 0, Line 12
Cannot create the clustered index 'IX_Appointments_Partition1_Id' on view 'PracticeRepository.model.Appointments_Partition1' because the select list of the view contains an expression on result of aggregate function or grouping column. Consider removing expression on result of aggregate function or grouping column from select list.
I'm including count_big...so why is the group by a problem?....and how can I resolve the error?
Here is the same error message with some boolean logic applied to it:
Cannot create the clustered index '...' on view '...' because the
select list of the view contains an expression on a grouping column.
Consider removing expression on a grouping column from the select list.
You need to remove the CONVERT in CONVERT(varchar(15), AppointmentId)
I find this reason on one of the blogs, seems reasonable to me
No, you can't use schema binding on a view that has an aggregate. And you can't index a view unless you use schema binding. You also can't bind an index that uses outer or left joins. Basically, you can only bind a view that contains a simple select statement.
http://www.tek-tips.com/viewthread.cfm?qid=1401646
You can go through the blog and see if it exactly matched your scenario.
http://technet.microsoft.com/en-us/library/cc917715.aspx
If you want to build index on views, then you must create views with schema binding, in the above link it is explained in detail. Go through the section of Design Considerations

Resources