As we know from BOL
"Updatable views can modify more than one table involved in the view. The DELETE, INSERT, and UPDATE statements can reference a view as long as SQL Server can translate the user's update request unambiguously to updates in the base tables referenced in the view's definition"
But I would like to share with you one method to prevent updating view that based on single table. Let's see the following
CREATE TABLE1 (col1 int,col2 int,col3 int,col4 int,col5 int)
GO
INSERT INTO t1 VALUES (1,1,11,2,12)
INSERT INTO t1 VALUES (8,10,15,25,55)
INSERT INTO t1 VALUES (9,1,11,2,5,81)
GO
CREATE VIEW V1 WITH VIEW_METADATA
AS
SELECT
col1,
col2+0 AS col2,
col3,
col4+0 AS col4,
col5
FROM T1
GO
--Usage
UPDATE v1 SET col1=100 where col2=10
The above statement is succeed, but what happened to the next one
UPDATE v1 SET col2=1000 where col3=15
--Update or insert of view or function 'v1' failed because it contains a derived or --constant field.
You cannot derived column ,as it should be referring to the update, not the view.
In SQL Server 2000, you can handle it using an INSTEAD OF trigger.
Tuesday, November 13, 2007
Thursday, October 11, 2007
Reading Registry
Sometimes we need to read registry by using T-SQL . I would like to show you some scripts to do the job.
--Getting MDAC
EXEC master..xp_regread
N'HKEY_LOCAL_MACHINE',
N'Software\Microsoft\DataAccess',
N'Version'
--Getting an account SQL Server runs under
DECLARE @serviceaccount varchar(100)
EXECUTE master.dbo.xp_instance_regread
N'HKEY_LOCAL_MACHINE',
N'SYSTEM\CurrentControlSet\Services\MSSQLSERVER',
N'ObjectName',
@ServiceAccount OUTPUT,
N'no_output'
SELECT @Serviceaccount
---Getting SQL Server path's installation and the data path
DECLARE @DataPath nvarchar( 512 ) , @SQLPath nvarchar( 512 ) ,
@ToolsPath nvarchar( 512 )
EXECUTE sp_MSget_setup_paths @SQLPath OUT , @DataPath OUT;
PRINT 'SQLPath : ' + QUOTENAME( @SQLPath , '"');
PRINT 'DataPath : ' + QUOTENAME( @DataPath , '"');
--Getting MDAC
EXEC master..xp_regread
N'HKEY_LOCAL_MACHINE',
N'Software\Microsoft\DataAccess',
N'Version'
--Getting an account SQL Server runs under
DECLARE @serviceaccount varchar(100)
EXECUTE master.dbo.xp_instance_regread
N'HKEY_LOCAL_MACHINE',
N'SYSTEM\CurrentControlSet\Services\MSSQLSERVER',
N'ObjectName',
@ServiceAccount OUTPUT,
N'no_output'
SELECT @Serviceaccount
---Getting SQL Server path's installation and the data path
DECLARE @DataPath nvarchar( 512 ) , @SQLPath nvarchar( 512 ) ,
@ToolsPath nvarchar( 512 )
EXECUTE sp_MSget_setup_paths @SQLPath OUT , @DataPath OUT;
PRINT 'SQLPath : ' + QUOTENAME( @SQLPath , '"');
PRINT 'DataPath : ' + QUOTENAME( @DataPath , '"');
Monday, October 8, 2007
How many times stored procedures have recompiled?
I have recently visited our client and we found out that He has a very high number of stored procedures that have recompiled. Certainly, we have observed some perfomance decreasing. Fortunately , the client has alredy upgraded to SQL Server 2005(SP2) and apart from running SQL Server Profile to indentify those stored procedures we came out with the following query.
It gives you the top 10 stored procedures that have been recompiled.
select *
from sys.dm_exec_query_optimizer_info
select top 10
sql_text.text,
sql_handle,
plan_generation_num,
execution_count,
dbid,
objectid
from
sys.dm_exec_query_stats
cross apply sys.dm_exec_sql_text(sql_handle) as sql_text
where
plan_generation_num >1
order by plan_generation_num desc
Note that the plan_generation_num indicates the number of times the stored procedure has recompiled. Very cool feature.
It gives you the top 10 stored procedures that have been recompiled.
select *
from sys.dm_exec_query_optimizer_info
select top 10
sql_text.text,
sql_handle,
plan_generation_num,
execution_count,
dbid,
objectid
from
sys.dm_exec_query_stats
cross apply sys.dm_exec_sql_text(sql_handle) as sql_text
where
plan_generation_num >1
order by plan_generation_num desc
Note that the plan_generation_num indicates the number of times the stored procedure has recompiled. Very cool feature.
Monday, October 1, 2007
RESTORE LOG file and WITH FILE behaviour
Recently I have been visited one of the our clients and have been asked the following question.
"What if I have 3 fileid within a backup file and when restore the log being done, I do not specify WITH FILE option,so do I get latest Log's data?". To answer the question I decide to conduct some test script.
CREATE DATABASE demo
GO
ALTER DATABASE demo SET RECOVERY FULL
GO
CREATE TABLE demo..t1(c1 INT NOT NULL PRIMARY KEY)
--insert one row
insert demo..t1 VALUES (1)
--BACKUP the data
BACKUP DATABASE demo TO DISK = 'c:\temp\demo.bak' WITH INIT
GO
insert demo..t1 VALUES (2)
--start BACKUP log data
BACKUP log demo TO DISK = 'c:\temp\demo_log.bak' WITH INIT
GO
insert demo..t1 VALUES (3)
--- BACKUP log FILE at this time WITH FILE =2
BACKUP log demo TO DISK = 'c:\temp\demo_log.bak' WITH NOINIT
GO
insert demo..t1 VALUES (4)
--- BACKUP log FILE at this time WITH FILE =3
BACKUP log demo TO DISK = 'c:\temp\demo_log.bak' WITH NOINIT
--Lets do RESTORE and see what is going on
RESTORE DATABASE demo FROM DISK = 'c:\temp\demo.bak' WITH FILE = 1, NORECOVERY
RESTORE LOG demo FROM DISK = 'c:\temp\demo_log.bak' WITH FILE = 1, NORECOVERY
RESTORE LOG demo FROM DISK = 'c:\temp\demo_log.bak' WITH RECOVERY ----Do you expect the last one?
GO
SELECT * FROM demo..t1
c1
-----------
1
2
It did not return rows 3 and 4.
So that means if you DO NOT specify WITH FILE in RESTORE LOG file you DO NOT get latest FILEID but only the first one.
"What if I have 3 fileid within a backup file and when restore the log being done, I do not specify WITH FILE option,so do I get latest Log's data?". To answer the question I decide to conduct some test script.
CREATE DATABASE demo
GO
ALTER DATABASE demo SET RECOVERY FULL
GO
CREATE TABLE demo..t1(c1 INT NOT NULL PRIMARY KEY)
--insert one row
insert demo..t1 VALUES (1)
--BACKUP the data
BACKUP DATABASE demo TO DISK = 'c:\temp\demo.bak' WITH INIT
GO
insert demo..t1 VALUES (2)
--start BACKUP log data
BACKUP log demo TO DISK = 'c:\temp\demo_log.bak' WITH INIT
GO
insert demo..t1 VALUES (3)
--- BACKUP log FILE at this time WITH FILE =2
BACKUP log demo TO DISK = 'c:\temp\demo_log.bak' WITH NOINIT
GO
insert demo..t1 VALUES (4)
--- BACKUP log FILE at this time WITH FILE =3
BACKUP log demo TO DISK = 'c:\temp\demo_log.bak' WITH NOINIT
--Lets do RESTORE and see what is going on
RESTORE DATABASE demo FROM DISK = 'c:\temp\demo.bak' WITH FILE = 1, NORECOVERY
RESTORE LOG demo FROM DISK = 'c:\temp\demo_log.bak' WITH FILE = 1, NORECOVERY
RESTORE LOG demo FROM DISK = 'c:\temp\demo_log.bak' WITH RECOVERY ----Do you expect the last one?
GO
SELECT * FROM demo..t1
c1
-----------
1
2
It did not return rows 3 and 4.
So that means if you DO NOT specify WITH FILE in RESTORE LOG file you DO NOT get latest FILEID but only the first one.
Sunday, September 23, 2007
Insert data into a Text File
As you propably know that MS introduced in SQL Server 2005 a new command utility called SQLCMD. In this article I would like to show the difference between SQLCMD and "old fashioned" OSQL in terms of formating the text file's output.
If you run these two statements and look at the files , you'll see that SQL Server inserts three dotted lines in myoutput2.txt, not so good for reading. Opposite, in myoutput1.txt you see very good reading format.
EXEC master..xp_cmdshell 'SQLCMD -S URID\SQLSERVERDEV2005 -E -Q "SELECT TOP 10 * FROM pubs.dbo.authors" -b -o c:\myoutput1.txt', no_output
EXEC master..xp_cmdshell 'OSQL -S URID\SQLSERVERDEV2005 -E -Q "SELECT TOP 10 * FROM pubs.dbo.authors" -b -o c:\myoutput2.txt', no_output
Despite that SQL Server 2005 supports OSQL utility, I strongly recommend you using SQLCMD.
If you run these two statements and look at the files , you'll see that SQL Server inserts three dotted lines in myoutput2.txt, not so good for reading. Opposite, in myoutput1.txt you see very good reading format.
EXEC master..xp_cmdshell 'SQLCMD -S URID\SQLSERVERDEV2005 -E -Q "SELECT TOP 10 * FROM pubs.dbo.authors" -b -o c:\myoutput1.txt', no_output
EXEC master..xp_cmdshell 'OSQL -S URID\SQLSERVERDEV2005 -E -Q "SELECT TOP 10 * FROM pubs.dbo.authors" -b -o c:\myoutput2.txt', no_output
Despite that SQL Server 2005 supports OSQL utility, I strongly recommend you using SQLCMD.
Sunday, September 16, 2007
Disable all Foreign Keys
Recently I was told to clear up all user tables in the client's database SQL Server 2000 SP3.There are lots of contsrtaints and for this purpose we would like to disable them in order to delete all data. Try it on Northwind database before using on production. If you want to enable constraints ,simple replace NOCHECK with CHECK.
DECLARE @TableName nvarchar(257),
@ForeignKeyConstraintName sysname,
@SQLStatement nvarchar(4000)
DECLARE TableList CURSOR
LOCAL FAST_FORWARD READ_ONLY FOR
SELECT
QUOTENAME(TABLE_SCHEMA) +
N'.' +
QUOTENAME(TABLE_NAME) AS TableName,
QUOTENAME(CONSTRAINT_NAME) AS ForeignKeyConstraintName
FROM
INFORMATION_SCHEMA.TABLE_CONSTRAINTS
WHERE
CONSTRAINT_TYPE = 'FOREIGN KEY' AND
OBJECTPROPERTY
(
OBJECT_ID
(
QUOTENAME(TABLE_SCHEMA) +
N'.' +
QUOTENAME(TABLE_NAME)
),
'IsMSShipped') = 0
OPEN TableList
WHILE 1 = 1
BEGIN
FETCH NEXT FROM TableList INTO
@TableName,
@ForeignKeyConstraintName
IF @@FETCH_STATUS = -1 BREAK
SET @SQLStatement =
N'ALTER TABLE ' +
@TableName +
N' NOCHECK CONSTRAINT ' +
@ForeignKeyConstraintName
RAISERROR (@SQLStatement, 0, 1) WITH NOWAIT
EXEC sp_executesql @SQLStatement
END
CLOSE TableList
DEALLOCATE TableList
GO
DECLARE @TableName nvarchar(257),
@ForeignKeyConstraintName sysname,
@SQLStatement nvarchar(4000)
DECLARE TableList CURSOR
LOCAL FAST_FORWARD READ_ONLY FOR
SELECT
QUOTENAME(TABLE_SCHEMA) +
N'.' +
QUOTENAME(TABLE_NAME) AS TableName,
QUOTENAME(CONSTRAINT_NAME) AS ForeignKeyConstraintName
FROM
INFORMATION_SCHEMA.TABLE_CONSTRAINTS
WHERE
CONSTRAINT_TYPE = 'FOREIGN KEY' AND
OBJECTPROPERTY
(
OBJECT_ID
(
QUOTENAME(TABLE_SCHEMA) +
N'.' +
QUOTENAME(TABLE_NAME)
),
'IsMSShipped') = 0
OPEN TableList
WHILE 1 = 1
BEGIN
FETCH NEXT FROM TableList INTO
@TableName,
@ForeignKeyConstraintName
IF @@FETCH_STATUS = -1 BREAK
SET @SQLStatement =
N'ALTER TABLE ' +
@TableName +
N' NOCHECK CONSTRAINT ' +
@ForeignKeyConstraintName
RAISERROR (@SQLStatement, 0, 1) WITH NOWAIT
EXEC sp_executesql @SQLStatement
END
CLOSE TableList
DEALLOCATE TableList
GO
Tuesday, August 28, 2007
Getting an index's information
I was asked by one of the client to get all info about the indexes i.e name of the index , column's name, table's name etc. Please take a look at following script to return the data for SQL Server 2000.
use pubs
SELECT tbl = object_name(i.id), i.name as index_name, c.name as column_name,
isunique = indexproperty(i.id, i.name, 'IsUnique'),
isclustered = indexproperty(i.id, i.name, 'IsClustered'),
constrtype = CASE o.type
WHEN 'PK' THEN 'PRIMARY KEY'
WHEN 'UQ' THEN 'UNIQUE'
END
FROM sysindexes i
JOIN syscolumns c on i.id = c.id
JOIN sysindexkeys k on i.id = k.id
and i.indid = k.indid
and c.colid = k.colid
LEFT JOIN sysobjects o ON o.name = i.name
AND o.xtype in ('PK', 'UQ')
AND o.parent_obj = i.id
WHERE indexproperty(i.id, i.name, 'IsHypothetical') = 0
AND indexproperty(i.id, i.name, 'IsStatistics') = 0
AND indexproperty(i.id, i.name, 'IsAutoStatistics') = 0
AND objectproperty(i.id,'IsMSShipped')=0
ORDER BY tbl, i.name, k.keyno
For SQL Server 2005 I use the script written by Kalen Delaney.Remember there is new type of index called INCLUDE.
CREATE VIEW get_index_columns
AS
SELECT object_name(ic.object_id) as object_name , index_name = i.name,
'column' = c.name,
'column usage' = CASE ic.is_included_column
WHEN 0 then 'KEY'
ELSE 'INCLUDED'
END
FROM sys.index_columns ic JOIN sys.columns c
ON ic.object_id = c.object_id
AND ic.column_id = c.column_id
JOIN sys.indexes i
ON i.object_id = ic.object_id
AND i.index_id = ic.index_id
After creating the view, you can select from it, and it will give you the
KEY columns and the INCLUDED columns in all the indexes in all the tables.
Or, you can add a WHERE clause for your own table or index:
SELECT * FROM get_index_columns
WHERE object_name = 'mytable'
use pubs
SELECT tbl = object_name(i.id), i.name as index_name, c.name as column_name,
isunique = indexproperty(i.id, i.name, 'IsUnique'),
isclustered = indexproperty(i.id, i.name, 'IsClustered'),
constrtype = CASE o.type
WHEN 'PK' THEN 'PRIMARY KEY'
WHEN 'UQ' THEN 'UNIQUE'
END
FROM sysindexes i
JOIN syscolumns c on i.id = c.id
JOIN sysindexkeys k on i.id = k.id
and i.indid = k.indid
and c.colid = k.colid
LEFT JOIN sysobjects o ON o.name = i.name
AND o.xtype in ('PK', 'UQ')
AND o.parent_obj = i.id
WHERE indexproperty(i.id, i.name, 'IsHypothetical') = 0
AND indexproperty(i.id, i.name, 'IsStatistics') = 0
AND indexproperty(i.id, i.name, 'IsAutoStatistics') = 0
AND objectproperty(i.id,'IsMSShipped')=0
ORDER BY tbl, i.name, k.keyno
For SQL Server 2005 I use the script written by Kalen Delaney.Remember there is new type of index called INCLUDE.
CREATE VIEW get_index_columns
AS
SELECT object_name(ic.object_id) as object_name , index_name = i.name,
'column' = c.name,
'column usage' = CASE ic.is_included_column
WHEN 0 then 'KEY'
ELSE 'INCLUDED'
END
FROM sys.index_columns ic JOIN sys.columns c
ON ic.object_id = c.object_id
AND ic.column_id = c.column_id
JOIN sys.indexes i
ON i.object_id = ic.object_id
AND i.index_id = ic.index_id
After creating the view, you can select from it, and it will give you the
KEY columns and the INCLUDED columns in all the indexes in all the tables.
Or, you can add a WHERE clause for your own table or index:
SELECT * FROM get_index_columns
WHERE object_name = 'mytable'
Subscribe to:
Posts (Atom)