Search
Wednesday, December 8, 2010
Fixing “Extra or Invalid Key...” Error Message
Tuesday, December 7, 2010
A Story of the Deleted Transaction Log
/*Stop SQL service, rename DbLive.mdf to DbBad.mdf.started SQL service, created fake DbLive db (with log etc)Stopped SQL serviceDeleted DbLIve.mdf Renamed DbBad.MDF to DbLive.MDFStarted SQL service.Ran following script:*/ALTER DATABASE DbLive SET EMERGENCYsp_dboption 'DbLive', 'single user', 'true' DBCC CHECKDB ('DbLive', REPAIR_ALLOW_DATA_LOSS)sp_dboption 'DbLive', 'single user', 'false' Ref: http://www.sqlservercentral.com
How to Fix “Error: 823” in Microsoft SQL Server
Are you getting system-level errors while accessing your Microsoft SQL Server database? Are you unable to perform any I/O (Input/Output) operation on your database? Well, the problem generally occurs due to either conflicts of Windows API used by SQL Server or SQL Server database corruption. It leaves your database in an unusable state and leads to severe data loss situations. In order to get your mission critical data back in such cases, you must go for SQL database recovery solutions.
For instance, you may run across an error message similar to the following one in Windows Application Event Log or Microsoft SQL Server ERRORLOG:
“2010-03-06 22:41:19.55 spid58 Error: 823, Severity: 24, State: 2. 2010-03-06 22:41:19.55 spid58 The operating system returned error 38(Reached the end of the file.) to SQL Server during a read at offset 0x000000a72c0000 in file 'C:\Program Files\Microsoft SQL Server\MSSQL10.SQL2008\MSSQL\DATA\my_db.mdf'. Additional messages in the SQL Server error log and system event log may provide more detail. This is a severe system-level error condition that threatens database integrity and must be corrected immediately. Complete a full database consistency check (DBCC CHECKDB). This error can be caused by many factors; for more information, see SQL Server Books Online.”
When a program encounters the above error message while modifying or querying the data, error is returned to that program and SQL Server database connected is closed.
Root of the problem: The problem is caused by Windows APIs, used by Microsoft SQL Server. These APIs (such as WriteFile, ReadFile, WriteFileGather, and ReadFileScatter) are used to perform Input/Output operations. Upon completion of I/O operations, MS SQL Server examines for errors associated with API calls. When API calls betrays with OS error, you come across this behavior of SQL Server. The problem may also occur due to severe corruption to Microsoft SQL Server database.
Solution: Go through the below steps to recover SQL server database from corruption:
- Review suspect pages table.
- Check database consistency.
- Review Windows Application Event Log to find operating system and file system related errors.
- Restore database from current backup.
If the above methods fail to perform SQL Server recovery, you are required to opt for advanced third-party applications. The MS SQL recovery applications ensure absolute recovery by throughly scanning the database using advanced scanning algorithms. They offer easy and safe recovery with simple user interface and non-destructive behavior.
Stellar Phoenix SQL Recovery is the most efficient and result-oriented utility to offer assured recovery of corrupted database. This software is designed to restore corrupt databases of MS SQL Server 2008, 2005, 2000, and 7.0. It retrieves tables, reports, macros, forms, triggers, stored procedures, constraints, default constraints, and other MS SQL Server database objects.
Ref : hubpages.com
Cannot attach SQL MDF file due to corrupt or missing Log file (Error 1813)
Transaction Log is corrupted. The transaction log ate the 80GB hardisk space which was not normal, so I tried to detach the database, delete the log and rebuild it. Unfortunately the mdf file cannot be re-attach anymore. It prompts the following error:
"Error 1813: Could not open new database '. CREATE DATABASE is aborted.
Device activation error. The physical file name 'C:\ ...\db_name.LDF' may be incorrect."
After a long research for answer I finally arrived in to a solution. Here are the step-by-step procedure I created to resolve the problem:
1. Created a new database with same MDF and LDF name
2. Stop sql server and delete the new MDF file and copy the old MDF file
3. Started SQL Server and verify the status of the database. If the database status is suspect do the following scripts in Query Analyzer:
a. Override updates in Master Table
Use Master
Go
sp_configure 'allow updates', 1
reconfigure with override
Go
b. Get the value of the status column in sysdatabase table
select * from sysdatabases where name = 'db_name'
-- note the value of the status column for later use in # 6
begin tran
c. Set status of the database to suspect (327768)
update sysdatabases set status = 32768 where name ='db_name'
commit tran
d. Rebuild transaction log
DBCC rebuild_log('db_name','db_log_path')
e. Set the database to single user access
sp_dboption '', 'single user', 'true'
DBCC checkdb('db_name')
Go
f. Restore the status of the database in sysdatabases table
begin tran
update sysdatabases set status = previous_value where name = 'db_name'
-- verify one row is updated before committing
commit tran
Go
g. Restore the override property of Master table
sp_configure 'allow updates', 0
reconfigure with override
Go
4. Now open or refresh the enterprise manager you can now see the tables inside the fixed database.
If any problems persist, you can import all tables into temporary database and drop the original database. Create a new database with same name then re-import all the tables from the temporary database
Ref: fryan0911.com
Monday, December 6, 2010
Scripts to use XML to insert and update rows in a SQL Server table
Problem
Over the years I have had to adapt to many issues presented before me as a Database Administrator and I have gathered many scripts to deal with them. One that has become quite a topic is XML integration for transactions to the database. In developing this process, my research of resources on the topic throughout the internet, seemed to only discuss primary functions and fundamental application. The following production code is what I used for inserting and updating database tables using XML as the input. These scripts are for processing data for any table to insert or update data. The support functions provided, retrieve the table schema with their data types, functions to deal with XML dates, primary keys of the table and what fields can be updated. The following article breaks down this process from beginning to end.
Solution
First, we need to deal with what data is in the transaction and the format it needs to conform to. For this example, I will be using the pubs database and work with transactions to authors.
Basically, the correctly formatted XML is generated with the table name (authors) as the parent node, rows are delimited by
|
172-32-1176 White Johnson 408 496-7223 10932 Bigge Rd.Menlo Park CA 94025 1
Note: XML is case-sensitive therefore whatever you have for table names and column names must exactly match the XML.
For those wondering how this is done auto-magically, this select query will generate a sample XML document from the authors table in the pubs database:
SELECT
(
SELECT
(
SELECT au.*
FROM authors au
WHERE au_lname = 'White'
FOR XML PATH('Row'), ELEMENTS, TYPE
) FOR XML PATH ('authors'), TYPE
) "*" FOR XML PATH('BookInfo')Now that we know what we are working with, we can move onto processing the transaction.
I have two processes one for inserting data and another for updating data. I will walk through the Insert and Update processes, so you have a better understanding of how the stored procedures work.
INSERT
In this section, I will walk through the different processes within the Insert stored procedure, which are to extract the NodePath and Table names from the XML, retrieve the schema datatypes, primary keys for that table, prepare the statement and then lastly loop through the XML to perform the request. You can download all of the code for this tip.
The following breaks apart the INSERT stored procedure and I'll explain each step in the process.
This is the first part of the procedure.
-- =============================================
-- Author: WA
-- Create date: 12/24/2009
-- Description: Translate XML to SQL RecordSet for INSERT
-- Dependencies: [dbo].[fnGetTableSchemaInsert], [dbo].[fnSetTableSchemaSelect],
[dbo].[fnGetTableSchemaSelectInto],[dbo].[fnIsDate]
-- =============================================
CREATE PROCEDURE [dbo].[prXMLDataInsert]
(
@XmlData XML
)
AS
BEGIN
SET NOCOUNT ON
SET ARITHABORT ON
SET CONCAT_NULL_YIELDS_NULL ON
SET QUOTED_IDENTIFIER ON
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
SET NUMERIC_ROUNDABORT OFF
DECLARE @hdoc INT
-- Prepare XML document
EXEC sp_xml_preparedocument @hdoc OUTPUT, @xmlDataAfter testing several XML methods, the quickest way I found was to use the sp_xml_preparedocument then insert the results into a temporary dataset in order to quickly query values from the XML to process.
-- Set Raw XML Schema
SELECT *
INTO #xmlDoc
FROM OPENXML( @hdoc, '//*',2)Once we have the dataset, our example XML data would appear as below:
The next step is to get the NodePath and table names from our temp dataset by using the query below:
-- Set Primary Table to use
SELECT DISTINCT IDENTITY(INT,1,1) id, rt.localname + '/' + tbl.localname + '/'
+ col.localname AS NodePath, tbl.localname AS NodeRow
INTO #xml
FROM #xmlDoc rt
INNER JOIN #xmlDoc tbl
ON rt.id = tbl.parentID AND rt.parentID IS NULL
INNER JOIN #xmlDoc col
ON tbl.id = col.parentedThe results of the query would then appear as follows:
At this point, we are ready to loop through the XML data as illustrated below. A few points of interest, I used a while loop verses a cursor to keep down the resource overhead and keep the speed up, and for those that haven’t learned the hard way with sp_executesql since we have to pass in the XML into the statement, we only have nvarchar(4000) to store the statement, which causes chaos when you have tables with many columns.
DECLARE @i INT, @NodePath VARCHAR(255), @NodeRow VARCHAR(50),
@NodeKeys VARCHAR(255), @NodeCol VARCHAR(2000),
@UpdateNodes VARCHAR(2000), @sSql NVARCHAR(4000),
@SetSchemaSelect VARCHAR(4000), @iVars VARCHAR(2000)
-- Set id of first row
SELECT @i = MIN(id) FROM #xml
-- Begin looping through xml recordset
WHILE @i IS NOT NULL
BEGIN
SELECT @NodePath = NodePath, @NodeRow = NodeRow FROM #xml WHERE id = @iWhat I found in order to build out the statements correctly, we need to get the column schema for the table were inserting into, but not any auto increment keys. Build the SELECT statement for the INTO portion of the statement and our OPENXML WITH fields with the correct datatypes, using the following functions illustrated below.
-- Get Table Schema for XML data columns
SELECT @NodeCol =[dbo].[fnGetTableSchemaInsert](@NodeRow)
SELECT @SetSchemaSelect = [dbo].[fnSetTableSchemaSelect](@NodeRow)
SELECT @ivars = [dbo].[fnGetTableSchemaSelectInto](@NodeRow)
DECLARE @param NVARCHAR(50), @pkID INT, @pkIDOUT INT
SET @param = N'@hdoc INT, @pkIDOUT INT OUTPUT'For our sp_executesql we need to SET the @hdoc and can pass the identity value back if there is one for the table. As we continue, we have set our INSERT variables and now can build our final statement to execute.
-- This updates xml Recordset on primary keys of a given table
SET @sSql = 'INSERT INTO ' + @NodeRow + '(' + @iVars + ') SELECT ' + @SetSchemaSelect +
' FROM OPENXML( @hdoc, ''' + @NodePath + ''',2) WITH (' + @NodeCol + ') as xm SELECT @pkIDOUT = SCOPE_IDENTITY()'A sample of the final statement generated from the above line of code would appear as:
INSERT INTO authors(au_id,au_lname,au_fname,phone,address,city,state,zip,contract) SELECT [au_id],[au_lname], [au_fname], [phone], [address], [city], [state], [zip], [contract] FROM OPENXML( @hdoc,'BookInfo/authors/Row',2) WITH ([au_id] VARCHAR(11), [au_lname] VARCHAR(40), [au_fname] VARCHAR(20), [phone]CHAR(12), [address] VARCHAR(40), [city] VARCHAR(20), [state] CHAR(2), [zip] CHAR(5), [contract] bit) AS xmSELECT @pkIDOUT = SCOPE_IDENTITY()Note: Here is where we can get in trouble with the nvarchar(4000) limit when the statement is dynamically assembled.
/******* Execute the query and pass in the @hdoc for update *******/
EXEC sp_executesql @sSql, @param, @hdoc, @pkIDOUT=@pkID OUTPUT
/***** Movenext *****/
SELECT @i = MIN(id) FROM #xml WHERE id > @I
END
-- Release @hdoc
EXEC sp_xml_removedocument @hdoc
DROP TABLE #xmlDoc
DROP TABLE #xml
ENDUPDATE
Well I have explained the XML INSERT, now to we can step through the UPDATE process, which fundamentally goes through the same steps as the INSERT, but the functions for this stored procedure generate update values for the sp_executesql loop.
-- =============================================
-- Author: WA
-- Create date: 12/24/2009
-- Description: Translate XML to SQL RecordSet for UPDATE
-- Dependencies: [dbo].[fnGetTableSchema], [dbo].[fnGetTableUpdate],
-- [dbo].[fnGetPrimaryKeys],[dbo].[fnIsDate], [dbo].[fnGetTableKeys]
-- =============================================
ALTER PROCEDURE [dbo].[prXMLDataUpdate]
(
@XmlData XML
)
AS
BEGIN
SET NOCOUNT ON
SET ARITHABORT ON
SET CONCAT_NULL_YIELDS_NULL ON
SET QUOTED_IDENTIFIER ON
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
SET NUMERIC_ROUNDABORT OFF
DECLARE @hdoc INT
-- Prepare XML document
EXEC sp_xml_preparedocument @hdoc OUTPUT, @xmlData
-- Set Raw XML Schema
SELECT *
INTO #xmlDoc
FROM OPENXML( @hdoc, '//*',2)
-- Set Primary Table to use
SELECT DISTINCT IDENTITY(INT,1,1) id, rt.localname + '/' + tbl.localname + '/'
+ col.localname AS NodePath, tbl.localname AS NodeRow
INTO #xml
FROM #xmlDoc rt
INNER JOIN #xmlDoc tbl
ON rt.id = tbl.parentID AND rt.parentID IS NULL
INNER JOIN #xmlDoc col
ON tbl.id = col.parented
DECLARE @i INT, @NodePath VARCHAR(255), @NodeRow VARCHAR(50), @NodeKeys VARCHAR(255), @NodeColVARCHAR(4000), @UpdateNodes VARCHAR(4000), @sSql NVARCHAR;-- -
--Set id of first row
SELECT @i = MIN(id) FROM #xml;
-- Begin looping through XML recordset to check for exists
WHILE @i IS NOT NULL
BEGIN
SELECT @NodePath = NodePath, @NodeRow = NodeRow
FROM #xml
WHERE id = @i
-- Get Table Schema for XML data columns
SELECT @NodeCol = [dbo].[fnGetTableSchema](@NodeRow)
SELECT @UpdateNodes =[dbo].[fnGetTableUpdate](@NodeRow)
SELECT @NodeKeys = [dbo].[fnGetPrimaryKeys](@NodeRow)Just as the INSERT our sp_executesql will need to SET the @hdoc parameter and optionally pass the identity value back if there is one for the table.
DECLARE @param NVARCHAR(50)
SET @param = N'@hdoc INT'At this point, we have set our UPDATE variables and can now build our final statement to execute.
SET @sSql = 'UPDATE ' + @NodeRow + ' SET ' + @UpdateNodes + ' FROM
OPENXML( @hdoc, ''' + @NodePath + ''',2) WITH (' +
@NodeCol + ') as xm INNER JOIN ' + @NodeRow + ' ON ' +
@NodeKeysA sample of the final statement generated would appear as:
UPDATE authors SET [au_lname] = xm.au_lname, [au_fname] = xm.au_fname, [phone] = xm.phone, [address] =xm.address, [city] = xm.city, [state] = xm.state, [zip] = xm.zip, [contract] = xm.contract FROM OPENXML(@hdoc, 'BookInfo/authors/Row',2) WITH ([au_id] VARCHAR(11), [au_lname] VARCHAR(40), [au_fname] VARCHAR(20),[phone] CHAR(12), [address] VARCHAR(40), [city] VARCHAR(20), [state] CHAR(2), [zip] CHAR(5), [contract] bit)AS xm INNER JOIN authors ON authors.au_id=xm.au_idNote: Let me pass a few words of wisdom concerning the OPENXML and WITH function. First the XML field values are all for practical purposes varchar, which is why we declare the Datatypes in the WITH section. When we have a datetime value to process, a value of NULL is translated to 1900-01-01 00:00:00.000, which is why I created the fnIsDate() function to turn it back to NULL.
-- Execute the query and pass in the @hdoc for UPDATE
EXEC sp_executesql @sSql, @param, @hdoc
/***** Movenext *****/
SELECT @i = MIN(id) FROM #xml WHERE id > @I
END Finally, need to insure that we release the variables before returning
-- Release @hdoc
EXEC sp_xml_removedocument @hdoc
DROP TABLE #xmlDoc
DROP TABLE #xml
ENDPutting It Together
Now that we have walked through the code for the Insert and Update these are functions that are required and are all part of the code download.
Functions:
- [dbo].[fnGetTableSchemaInsert]
- [dbo].[fnSetTableSchemaSelect]
- [dbo].[fnGetTableSchemaSelectInto]
- [dbo].[fnIsDate]
- [dbo].[fnGetTableSchema]
- [dbo].[fnGetTableUpdate]
- [dbo].[fnGetPrimaryKeys]
- [dbo].[fnGetTableKeys]
Stored Procedures:
- prXMLDataInsert
- prXMLDataUpdate
Examples
After you have created all of these objects in your database (in our case the pubs database) we can then use them to create new records or update existing records.
In this first example I have modified the fname to be "John" and the lname to be "Doe".
SELECT * FROM authors WHERE au_id = '172-32-1176';
EXEC dbo.prXMLDataUpdate
'
172-32-1176
John
Doe
408 496-7223
10932 Bigge Rd.
Menlo Park
CA
94025
1
|
';
SELECT * FROM authors WHERE au_id = '172-32-1176';Here are the before and after values in the table.
In this example we will create a new author with an ID = '999-99-9999'
SELECT * FROM authors WHERE au_id = '999-99-9999';
EXEC dbo.prXMLDataInsert
'
999-99-9999
Doe
John
408 496-7223
10932 Bigge Rd.
Menlo Park
CA
94025
1
|
';
SELECT * FROM authors WHERE au_id = '999-99-9999';Here are the before and after values in the table.