Is it possible to create an indexed view from Xml Data in Sql Server 2008? - sql-server

I see from the 2005 documentation that you cannot create an indexed view from an Xml column.
Is this possible in 2008 or 2008R2? I can't find any documentation saying that it is something that was added but am looking for confirmation and I don't have handy access to a 2008 environment at the moment.
EDIT
My motivation behind this is that the amount of Xml is growing to the point where SSRS reports which aggregate data from the Xml are becoming slow.

Depending on your need, what you could do is this:
create a set of stored functions that extract certain bits of key information from your XML (function receives XML as input, extracts the info using XPath/XQuery, returns a VARCHAR or INT or something value)
CREATE FUNCTION dbo.SomeFunction(#Input XML)
RETURNS VARCHAR(20)
WITH SCHEMABINDING
AS BEGIN
......
END
add those key bits to your base table as computed columns that reference those functions, with the PERSISTED keyword:
ALTER TABLE dbo.YourTable
ADD ComputedColumns1 AS dbo.SomeFunction(XmlColumn) PERSISTED
create your view on the table and those computed columns, with schemabinding:
CREATE VIEW vYourView
WITH SCHEMABINDING
AS
SELECT (list of columns)
FROM dbo.YourTable
create a unique, clustered index on that view - unless you've violated any of the requirements of the indexed view, this should work just fine:
CREATE UNIQUE CLUSTERED INDEX CIX_YourView ON dbo.vYourView(.....)
This works fine if you need to extract a small number of key bits of information from an XML column - it's definitely not recommended for lots of XML elements / values.

I don't believe this is possible. Without a better explanation of what you are trying to do, one suggestion I can offer is to pull the XML apart before insert (perhaps using an instead of trigger, or doing this shredding at the application layer) and storing the part(s) you want to use for the indexed view in separate non-XML columns.

Related

Use column set for ALL_SPARSE_COLUMNS in the Sql View

I have a table where I add sparse columns dynamically:
CREATE TABLE [dbo].[my_table](
[id] [BIGINT] NOT NULL,
[column_set] XML COLUMN_SET FOR ALL_SPARSE_COLUMNS)
I add sparse columns at runtime with the following SQL:
ALTER TABLE my_table ADD my_sparse_column ... SPARSE
I want to create the SQL view for this table:
CREATE VIEW [dbo].[v_my_view]
AS
SELECT v.*
FROM my_table v
However I cannot query data from my sparse columns when I use the view:
SELECT my_sparse_column FROM v_my_view
However, I receive such an error:
This query works fine when executing it on the original table.
Is it possible to make it work?
This behaviour is documented for SPARSE columns when there is a COLUMN_SET present.
Warning:
Adding a column set changes the behavior of SELECT * queries. The query will return the column set as an XML column and not return the individual sparse columns. Schema designers and software developers must be careful not to break existing applications. Individual sparse columns can still be queried by name in a SELECT statement.
So the view will never contain that column, unless you specifically select it, not just using select *.
There is another issue that you would get even if it wasn't SPARSE.
You are adding the column after creating the view.
You need to then run the following statement:
EXEC sp_refreshview N'dbo.v_my_view';
When creating a view, the view is parsed into a compiled expression tree (without any optimizations). Then, when you use the view, the compiler does not simply dump the view text into the outer query. Instead, it parses the outer query into an expression tree, and uses the expression tree from the view in the correct place.
So when you add a column, the expression tree is not updated. So you need to refresh the view definition.
You also need to rebuild any stored procedures which access this table or the view, for the same reason.
EXEC sp_refreshsqlmodule N'dbo.YourProc';
db<>fiddle

How to dynamically exclude non-copyable fields in trigger tables

Background: I am trying to have an after update trigger which stores the changed values dynamically into another table. Since this trigger should be generic and easy to transfer to other tables and won't cause problems, if I add additional columns (If my whole code should be required to solve this, I'll update the question)
While trying to do this, I encounter following issue: I want to store the inserted table into an temporary table, which I do in this way:
SELECT *
INTO #tempINSERTED
FROM INSERTED
But the original table contains both: ntext and timestamp columns which aren't allowed in temporary tables.
Another approach I tried, was looping through the system table INFORMATION_SCHEMA.COLUMNS and build a SQL statement as a string excluding non-copyable columns, but this way I cannot access the inserted table. - I already figured I cannot access inserted if I use sp_executesql.
So my question: is there a way to access the inserted table and exclude non-copyable columns as ntext, text, image ?
Thanks in advance
You want the triggers to run fast. So the better approach would be to generate the create trigger code rather than looping through the fields in the trigger itself. Then if the table schema changes you will need to regenerate the trigger.
For your #TEMPINSERTED table you can use nvarchar(max) in place of ntext,
varchar(max) for text and varbinary(max) in place of image. You can also use and binary(8) or bigint in place of timestamp.
I would suggest using a table variable instead of an #temptable. I.e.:
declare #tempTable table (
fieldname int, -- and so on
)

Permanently sorting a table in SQLServer based on pre-existing data

I have made a table in SQL Server based on pre-existing data:
SELECT pre_existing_data
INTO new_table
FROM existing_table
I am trying to get the output to permanently sort by a particular field once the table is created. I thought this would be as simple as adding an ORDER BY clause at the end of the chunk of code that makes the table, but the data still won't sort properly.
There is no way to permanently sort a table in SQL.
You can create an index on the table and queries which use the index (in an ORDER BY clause) will be returned quicker, but the order the data is stored on the disk is not controllable.
You can create an index-organized table by using a CLUSTERED INDEX, which stores the data on disk in an ordered fashion on the clustering key. Then if you ORDER BY in your query based on the clustering key, data should come out very fast. Note that you have to use the ORDER BY in your query no matter what.
I have made a new table on SQL Server on pre-existing Schema
insert into new_table
select * from old_table
ORDER BY col ASC|DSC;
After it drop old_table and rename new table to old_table_name
drop table old_table_name;
rename new_table_name to old_table_name;
Try this trick to short your data in the table permanently

How To change the column order of An Existing Table in SQL Server 2008

I have situation where I need to change the order of the columns/adding new columns for existing Table in SQL Server 2008.
Existing column
MemberName
MemberAddress
Member_ID(pk)
and I want this order
Member_ID(pk)
MemberName
MemberAddress
I got the answer for the same ,
Go on SQL Server → Tools → Options → Designers → Table and Database Designers and unselect Prevent saving changes that require table re-creation
2- Open table design view and that scroll your column up and down and save your changes.
It is not possible with ALTER statement. If you wish to have the columns in a specific order, you will have to create a newtable, use INSERT INTO newtable (col-x,col-a,col-b) SELECT col-x,col-a,col-b FROM oldtable to transfer the data from the oldtable to the newtable, delete the oldtable and rename the newtable to the oldtable name.
This is not necessarily recommended because it does not matter which order the columns are in the database table. When you use a SELECT statement, you can name the columns and have them returned to you in the order that you desire.
If your table doesn't have any records you can just drop then create your table.
If it has records you can do it using your SQL Server Management Studio.
Just click your table > right click > click Design then you can now arrange the order of the columns by dragging the fields on the order that you want then click save.
Best Regards
I tried this and dont see any way of doing it.
here is my approach for it.
Right click on table and Script table for Create and have this on
one of the SQL Query window,
EXEC sp_rename 'Employee', 'Employee1' -- Original table name is Employee
Execute the Employee create script, make sure you arrange the columns in the way you need.
INSERT INTO TABLE2 SELECT * FROM TABLE1.
-- Insert into Employee select Name, Company from Employee1
DROP table Employee1.
Relying on column order is generally a bad idea in SQL. SQL is based on Relational theory where order is never guaranteed - by design. You should treat all your columns and rows as having no order and then change your queries to provide the correct results:
For Columns:
Try not to use SELECT *, but instead specify the order of columns in the select list as in: SELECT Member_ID, MemberName, MemberAddress from TableName. This will guarantee order and will ease maintenance if columns get added.
For Rows:
Row order in your result set is only guaranteed if you specify the ORDER BY clause.
If no ORDER BY clause is specified the result set may differ as the Query Plan might differ or the database pages might have changed.
Hope this helps...
This can be an issue when using Source Control and automated deployments to a shared development environment. Where I work we have a very large sample DB on our development tier to work with (a subset of our production data).
Recently I did some work to remove one column from a table and then add some extra ones on the end. I then had to undo my column removal so I re-added it on the end which means the table and all references are correct in the environment but the Source Control automated deployment will no longer work because it complains about the table definition changing.
The real problem here is that the table + indexes are ~120GB and the environment only has ~60GB free so I'll need to either:
a) Rename the existing columns which are in the wrong order, add new columns in the right order, update the data then drop the old columns
OR
b) Rename the table, create a new table with the correct order, insert to the new table from the old and delete from the old as I go along
The SSMS/TFS Schema compare option of using a temp table won't work because there isn't enough room on disc to do it.
I'm not trying to say this is the best way to go about things or that column order really matters, just that I have a scenario where it is an issue and I'm sharing the options I've thought of to fix the issue
SQL query to change the id column into first:
ALTER TABLE `student` CHANGE `id` `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT FIRST;
or by using:
ALTER TABLE `student` CHANGE `id` `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT AFTER 'column_name'

Is it bad to use ALTER TABLE to resize a varchar column to a larger size?

I need a simple resize of a column from VARCHAR(36) to VARCHAR(40).
If you try to use SQL Server Enterprise Manager, the script it generates is effectively creating a new table with the new structure, inserting all of the data from the existing table into it, dropping the existing table, renaming the new table, and recreating any indexes.
If you read the documentation (and many online resources including SO), you can use an ALTER statement for the resize.
Does the ALTER affect the way the data is stored in any way? Indexes? Statistics? I want to avoid performance hits because of this modification due to the fact that the table can get large.
Just use ALTER TABLE. SSMS is a bit, er, stupid sometimes
You'll need to drop and recreate dependent constraints (FK, unique, index, check etc)
However, this is only a metadata change and will be very quick for any size table (unless you also change NOT NULL to NULL or varchar to nvarchar or such)
No, ALTER TABLE (http://msdn.microsoft.com/de-de/library/ms190273.aspx) is the way how Microsoft intended to do this kind of change.
And if you do not add extra options to your command, no indexes or statistics should get harmed.
A possibility of data loss is also not given, because you are just making the column bigger.
Everything should be fine.
Changes to database structure should NEVER be made using SSMS on a porduction environment for just the reason you brought up. It can destroy performance in a large table. ALTER table is the prefered method, it is faster and it can be stored in source control as a change to push to prod after testing.
Following should be the better way to handle this
IF EXISTS (SELECT 1
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = '<tablename>'
AND COLUMN_NAME = '<field>')
BEGIN
ALTER TABLE <tablename> ALTER COLUMN [<field>] varchar(xxxx) null
END
ELSE

Resources