I'm having issues creating an index on a view that uses a custom CLR aggregate function.
I don't see any way to flag the aggregate function as deterministic or with schemabinding.
I'm creating my function like so:
CREATE ASSEMBLY StringUtil
AUTHORIZATION dbo
FROM 'C:\StringUtil.dll'
WITH PERMISSION_SET = UNSAFE
GO
CREATE AGGREGATE SUMSTRING (#input nvarchar(200))
RETURNS nvarchar(max) WITH SCHEMABINDING
EXTERNAL NAME StringUtil.Concatenate
And my view is defined as:
CREATE VIEW RolledValues WITH SCHEMABINDING
AS
SELECT ID, SumString(ValueText) as Value FROM [dbo].[IDValue]
GROUP BY ID
The issue occurs when I try to create an index on that view:
CREATE UNIQUE CLUSTERED INDEX IDX_RollValues_ID_VALUE on RolledValues (ID)
Error: Cannot create index on view "dbo.RolledValues" because it uses aggregate
"dbo.SumString". Consider eliminating the aggregate, not indexing the view, or
using alternate aggregates.
So is it possible to use a custom aggregate function in an indexed view? I cannot find any documentation on this...
The page on Creating Indexed Views lists a number of restrictions:
The SELECT statement in the view cannot contain the following Transact-SQL syntax elements:
...
A CLR user-defined aggregate function.
There's not even provision, at the current time, to describe a CLR aggregate as Deterministic (at least, if the API was going to be consistent). The SqlFunctionAttribute has an IsDeterministic property. No such property exists in SqlUserDefinedAggregateAttribute
It does help to reason about things if you consider why so many restrictions exist on indexed views.
The ones on aggregates have a pretty simple explanation - you're only allowed to use aggregates (such as SUM and COUNT_BIG) that have the property that SQL Server will be able to adjust the values, or add or remove rows from the index, based purely on the subset of rows that are the subject of the current transaction.
E.g. if the view has a row with ID=19, COUNT_BIG=5, and SUM=96, and a transaction deletes 3 rows with ID 19, whose SUM adds to 43, then it can update that row of the view to be COUNT_BIG=2 and SUM=53. Alternatively, if the transaction had deleted 5 rows with ID=19, it would have caused the row to be removed.
Note that in either case, we don't have to examine any other rows of the table to determine if they have ID=19.
So how could SQL Server hope to achieve similar functionality with a user defined aggregate? The current interface for user defined aggregates doesn't have the sort of support you'd need (it would need to have a trigger like interface also).
Related
I have an application that allows users to define their own views in SQL and later have the application generate metadata about that view. This is mostly really easy as information_schema.columns tells me what the columns/types the view uses.
However, is there a way to find out whether the view can accept INSERT or UPDATE queries without doing something horrible like parsing the SQL myself or doing a test INSERT and checking for errors/rolling back the transaction?
I'm assuming SQL Server here, YMMV with other RDBMS products...
Assuming you're not using INSTEAD OF triggers, there is no flag or query that indicates whether a view is updatable or not, probably because a view can be updatable for certain classes of updates but not others.
Per the documentation:
Updatable Views
You can modify the data of an underlying base table
through a view, as long as the following conditions are true:
Any modifications, including UPDATE, INSERT, and DELETE statements, must reference columns from only one base table.
The columns being modified in the view must directly reference the underlying data in the table columns.
The columns cannot be derived in any other way, such as through the following: An aggregate function: AVG, COUNT, SUM, MIN, MAX,
GROUPING, STDEV, STDEVP, VAR, and VARP.
The column cannot be computed from an expression that uses other columns. Columns that are formed by using the set operators UNION,
UNION ALL, CROSS JOIN, EXCEPT, and INTERSECT amount to a
computation and are also not updatable.
The columns being modified are not affected by GROUP BY, HAVING, or DISTINCT clauses.
TOP is not used anywhere in the select_statement of the view together with the WITH CHECK OPTION clause.
The previous restrictions apply to any subqueries in the FROM
clause of the view, just as they apply to the view itself. Generally,
the Database Engine must be able to unambiguously trace modifications
from the view definition to one base table. For more information, see
Modify Data Through a View.
So you might have a view that is based off a JOIN, where certain updates (involving only one base table) were legal, while others (involving multiple base tables) were not.
In sql server we can Update data view.I think the concept of view is a read only table.
Why we can edit view in sql.is there possible in oracle?
To answer your question of why can we create an editable view, it is so that you can limit access to fields that you do not want updated (or viewed). Then you can give a user access to the view, but not to the underlying tables
For a simple example, you could have a personnel table. You could create an view allowing some users to update a field like emergency contact details, but not see or update bank details or salary
There are lots of criteria to meet to make a view updatable, and you can indeed use INSTEAD OF triggers for extended functionality http://msdn.microsoft.com/en-us/library/ms187956.aspx
I think the concept of view is a read only table
No, it's more of a virtual table - anywhere you have a real table, you ought to be able to replace it with a view, and the users should be none the wiser.
According to Codd:
Rule 6: The view updating rule:
All views that are theoretically updatable must be updatable by the system.
However, in practicality, this ideal has not been achievable.
In addition to what #JamieA wrote, views can not only limit access to fields, but also limit access to data in the table.
Look at simple SQL-Fiddle example and experiment with it.
The view in the example restrict access only to columns id,val1 of the table, but also restrics access to rows (only id = 2..10). You can update and delete only rows 2..10 throught the view.
However the view does not prevent insertion of a row with id = 20
Here is another example - a view with check option - it this case the view prevents not only deletes and updates, but prevent also inserting rows that do not match a where clause of the view.
#yogi wrote that we can't update a view if the view joins two tables -> here is a third demo that shows a simple view that joins two tables, and how an update of this view works.
These simple examples are for Oracle, but after small modifications should also work in MS-SQL (must change datatypes in create tables), since when i looked througs MSDN documentation (section: updatable views -> http://msdn.microsoft.com/en-us/library/ms187956.aspx), I didn't find any significant differences between ms-sql and oracle, it seems that views work similary on both databases.
Yes it is possible in Oracle, the other answers already explained why views are updatable and had shed some light on that question, they are also allowed in Oracle but have some restrictions/limitations here is the Oracle documentation
Like, the view select cant have: aggregate functions, distinct clause, group by... read the link for more info
Since views are read only tables and its doesn't support DML statements you can't perform update on view.
An interesting factor is there you can write update statemnt over view and write a instead of trigger for that hence you can perform multiple update statements on tables which are in the view.
According to Pinal Dev Views having following limitations
ORDER BY Does Not Work.
Adding Column is Expensive by Joining Table Outside View
Index Created on View not Used Often
SELECT * and Adding Column Issue in View
COUNT(*) Not Allowed but COUNT_BIG(*) Allowed
UNION Not Allowed but OR Allowed in Index View
Cross Database Queries Not Allowed in Indexed View
Outer Join Not Allowed in Indexed Views
SELF JOIN Not Allowed in Indexed View
Keywords View Definition Must Not Contain for Indexed View
View Over the View Not Possible with Index View
I'm using SQL Server 2008 and I have a view that looks like this:
select ID, dbo.functionname(ID) from tablename
I'm trying to put a full-text index on this, but it doesn't seem to have a unique index that I can go off of. The tablename.ID is the unique identifier.
I tried creating an index on it, but it says it cannot schema bind view because the function is not schemabound.
What do I need to do to get the full text index created?
To be able to create an index view, the view must be deterministic, that is it must be the guarantied to be the same on every query of it.
Is your userfunction deterministic?
User-Defined Function Determinism
Whether a user-defined function is
deterministic or nondeterministic
depends on how the function is coded.
User-defined functions are
deterministic if:
* The function is schema-bound.
* All built-in or user-defined functions called by the user-defined
function are deterministic.
* The body of the function references no database objects outside
the scope of the function. For
example, a deterministic function
cannot reference tables other than
table variables that are local to the
function.
* The function does not call any extended stored procedures.
User-defined functions that do not
meet these criteria are marked as
nondeterministic. Built-in
nondeterministic functions are not
allowed in the body of user-defined
functions.
Is your function SchemaBound?
alter function [dbo].[UserFunction]
(#example int = 1 )
returns int
with schemabinding
as
begin
return 1
end
Is your view SchemaBound?
ALTER VIEW dbo.UserView
WITH SCHEMABINDING
AS
SELECT ID, [dbo].userFunction
To create an indexed view you must first create a unique clustered index(See FAQ a bottom).
I presume you mean't "not" schemabound in the comments above
Recreate your view "WITH SCHEMABINDING"
Then create a unique clusterred index
as explained here http://www.mssqltips.com/tip.asp?tip=1610
Then try adding your Full Text Index
Huge database in mssql2005 with big codebase depending on the structure of this database.
I have about 10 similar tables they all contain either the file name or the full path to the file. The full path is always dependent on the item id so it doesn't make sense to store it in the database. Getting useful data out of these tables goes a little like this:
SELECT a.item_id
, a.filename
FROM (
SELECT id_item AS item_id
, path AS filename
FROM xMedia
UNION ALL
-- media_path has a different collation
SELECT item_id AS item_id
, (media_path COLLATE SQL_Latin1_General_CP1_CI_AS) AS filename
FROM yMedia
UNION ALL
-- fullPath contains more than just the filename
SELECT itemId AS item_id
, RIGHT(fullPath, CHARINDEX('/', REVERSE(fullPath))-1) AS filename
FROM zMedia
-- real database has over 10 of these tables
) a
I'd like to create a single view of all these tables so that new code using this data-disaster doesn't need to know about all the different media tables. I'd also like use this view for insert and update statements. Obviously old code would still rely on the tables to be up to date.
After reading the msdn page about creating views in mssql2005 I don't think a view with SCHEMABINDING would be enough.
How would I create such an updateable view?
Is this the right way to go?
Scroll down on the page you linked and you'll see a paragraph about updatable views. You can not update a view based on unions, amongst other limitations. The logic behind this is probably simple, how should Sql Server decide on what source table/view should receive the update/insert?
You can modify partitioned views, provided they satisfy certain conditions.
These conditions include having a partitioning column as a part of the primary key on each table, and having a set on non-overlapping check constraints for the partitioning column.
This seems to be not your case.
In your case, you may do either of the following:
Recreate you tables as views (with computed columns) for your legacy soft to work, and refer to the whole table from the new soft
Use INSTEAD OF triggers to update the tables.
If a view is based on multiple base tables, UPDATE statement on the view may or may not work depending on the UPDATE statement. If the UPDATE statement affects multiple base tables, SQL server throws an error. Whereas, if the UPDATE affects only one base table in the view then the UPDATE will work (Not correctly always). The insert and delete statements will always fail.
INSTEAD OF Triggers, are used to correctly UPDATE, INSERT and DELETE from a view that is based on multiple base tables. The following links has examples along with a video tutorial on the same.
INSTEAD OF INSERT Trigger
INSTEAD OF UPDATE Trigger
INSTEAD OF DELETE Trigger
What is a view in Oracle?
A View in Oracle and in other database systems is simply the representation of a SQL statement that is stored in memory so that it can easily be re-used. For example, if we frequently issue the following query
SELECT customerid, customername FROM customers WHERE countryid='US';
To create a view use the CREATE VIEW command as seen in this example
CREATE VIEW view_uscustomers
AS
SELECT customerid, customername FROM customers WHERE countryid='US';
This command creates a new view called view_uscustomers. Note that this command does not result in anything being actually stored in the database at all except for a data dictionary entry that defines this view. This means that every time you query this view, Oracle has to go out and execute the view and query the database data. We can query the view like this:
SELECT * FROM view_uscustomers WHERE customerid BETWEEN 100 AND 200;
And Oracle will transform the query into this:
SELECT *
FROM (select customerid, customername from customers WHERE countryid='US')
WHERE customerid BETWEEN 100 AND 200
Benefits of using Views
Commonality of code being used. Since a view is based on one common set of SQL, this means that when it is called it’s less likely to require parsing.
Security. Views have long been used to hide the tables that actually contain the data you are querying. Also, views can be used to restrict the columns that a given user has access to.
Predicate pushing
You can find advanced topics in this article about "How to Create and Manage Views in Oracle."
If you like the idea of Views, but are worried about performance you can get Oracle to create a cached table representing the view which oracle keeps up to date.
See materialized views
regular view----->short name for a query,no additional space is used here
Materialised view---->similar to creating table whose data will refresh periodically based on data query used for creating the view
A view is a virtual table, which provides access to a subset of column from one or more table. A view can derive its data from one or more table. An output of query can be stored as a view. View act like small a table but it does not physically take any space. View is good way to present data in particular users from accessing the table directly. A view in oracle is nothing but a stored sql scripts. Views itself contain no data.
A view is simply any SELECT query that has been given a name and saved in the database. For this reason, a view is sometimes called a named query or a stored query. To create a view, you use the SQL syntax:
CREATE OR REPLACE VIEW <view_name> AS
SELECT <any valid select query>;