Problem with SQL Server client DB upgrade script - sql

SQL Server 2005, Win7, VS2008. I have to upgrade database from the old version of product to the newer one. I'd like to have one script that creates new database and upgrades old database to the new state. I am trying to do the following (SQL script below) and get the error (when running on machine with no database ):
Database 'MyDatabase' does not exist. Make sure that the name is
entered correctly.
The question is:
How can I specify database name in upgrade part
Is the better way to write create/upgrade exists ?
SQL code:
USE [master]
-- DB upgrade part
if exists (select name from sysdatabases where name = 'MyDatabase')
BEGIN
IF (<Some checks that DB is new>)
BEGIN
raiserror('MyDatabase database already exists and no upgrade required', 20, -1) with log
END
ELSE
BEGIN
USE [MyDatabase]
-- create some new tables
-- alter existing tables
raiserror('MyDatabase database upgraded successfully', 20, -1) with log
END
END
-- DB creating part
CREATE DATABASE [MyDatabase];
-- create new tables

You don't usually want to explicitly specify database name in a script. Rather, supply it exernally or pre-process the SQL to replace a $$DATABASENAME$$ token with the name of an actual database.

You're not going to be able to include the USE [MyDatabase] in your script since, if the database doesn't exist, the query won't parse.
Instead, what you can do is keep 2 separate scripts, one for an upgrade and one for a new database. Then you can call the scripts within the IF branches through xp_cmdshell and dynamic SQL. The following link has some examples that you can follow:
http://abhijitmore.wordpress.com/2011/06/21/how-to-execute-sql-using-t-sql/
PowerShell may make this task easier as well, but I don't have any direct experience using it.

Related

Creating an SQL Server Error Log using sp_readerror from multiple servers SQL Server 2012

I am attempting to create one single database to store all login errors.
insert into [dbo].[SQL_ErrorLog]
exec sp_readerrorlog 0, 1, 'error'
The above code gets me the information that I need for the current long and I understand that changing the 0 to a 1,2....etc will get me the previous days logs.
I have 4 different environments and instead of setting this same job up on each environment, I would like to control it all from 1 single job. I intend to add a field to determine which environment the log information is coming from.
I know that I could also set up staging tables on each environment and then run a select statement to pull in data from each staging table to the final table, however again I am trying to complete all the work from one environment if possible.
I have linked the other environments using the linked servers and can select data from any of them without a problem.
My question is more related on how I can run the exec sp_readerror stored procedure on the other server and insert that data into my master table.
An example would be:
Env0 - This is where the master table would be and where I would like to set everything up
Env1
Env2
Env3
I would like to be able to pull sp_readerror 0, 1, 'error' information from Env1, Env2, and Env3 and populate it on Env0 without using staging tables on each individual environment if possible.
Please let me know if this is not 100% clear. It makes sense in my head, however that does not always come out in text form. :)
Thanks in Advance.
If you are using linked servers it seems like you could link together multiple calls using go from the main source server. This will work assuming your linked servers are linked off one server.
INSERT INTO [Linked Server Name]. [some database name].[dbo].[SQL_ErrorLog]
EXEC [Linked Server Name].[some database name].[dbo].sp_readerrorlog
GO
INSERT INTO [Linked Server Name2]. [some database name].[dbo].[SQL_ErrorLog]
EXEC [Linked Server Name2].[some database name].[dbo].sp_readerrorlog
GO
INSERT INTO [Linked Server Name3]. [some database name].[dbo].[SQL_ErrorLog]
EXEC [Linked Server Name3].[some database name].[dbo].sp_readerrorlog
GO
INSERT INTO [Linked Server Name4]. [some database name].[dbo].[SQL_ErrorLog]
EXEC [Linked Server Name4].[some database name].[dbo].sp_readerrorlog
I think this will be your best bet. You can use the agent and then put all of these into the agent job and run the job. They will need to be fully qualified in order to run on the correct linked server.

SQL Server 2005 How to ignore errors during Create Procedure

I need to create a Stored Procedure in SQL Server 2005. Somewhere in the procedure, I have to join to a table which does not exist in the test environment but in the live environment (in a database in a linked server). I will not run the procedure in the test environment, but I need it to exist in order to create the ORM code in the application.
Naturally, SQL Server raises the error "Could not find server 'xxx' in sys.servers. Verify that the correct server name was specified. If necessary, execute the stored procedur sp_addlinkedserver to add the server to sys.servers.". However, I know that I can't add this server to the test environment, as it is not accessible from outside.
So, my question is, how can I create my stored procedure by ignoring the errors? Is there a way for it?
This is an old thread, but if other people are having the same problem, here's another solution:
You can have your server via text and the procedure will pass.
create proc test
as
declare #myserver varchar(50) = '[myserver\myinst]'
exec('select * from '+#myserver+'.dbo.table')
This way, the proc will compile on any environment, but will only run successfully on production
If you are certain that everything is correct and the procedure will work fine in live environment then create a fake linked server using sp_addlinkedserver.
What I mean is, if procedure body contains a linked server named test_linked and if it's not found then it will throw error.
Use sp_addlinkedserver and create a fake linked server named test_linked pointing to your test environment or even live environment. that will solve the issue cause it will try to check whether a linked server named test_linked does exist in sys.servers or not but unless you are running the procedure the actual linked server will not be accessed (AFAIK).
As Aaron Bertrand have mentioned in comment, Going by synonym would be a much cleaner approach though.

Troubleshooting A Simple SQL Server Trigger

I'm using SQL Server 2008 here. I inherited an old web app that is dying, and being replaced by a totally new web app. The new project is up and running but the old one will exist for the next month and a half for the transition period.
Here's the problem: action needs to be taken when someone adds a new record to a table in SQL Server using this app. The old source code is pretty hosed (seriously, no version control before my arrival) and I can't afford to take the time to hobble something together just so I can get an email notification using the old app.
My thought - use a SQL Server trigger to send an email AFTER INSERT. Really this is all I want: whenever a new record (and it's always one, not dozens) is entered into a table, I want to send myself and another lucky person an email. I've never done this in SQL Server but it seems doable.
Here's my SQL script as it currently stands:
CREATE TRIGGER NotificationMail
ON OldJunk.[dbo].[JunkTable]
AFTER INSERT
AS
BEGIN
EXEC msdb.dbo.sp_send_dbmail --QUESTION: I HAVE NO IDEA WHAT TO PUT HERE, WHAT FOLLOWS
-- IS JUST COPYPASTA FROM A FORUM
#recipients = 'shubniggurath#email.com, someoneelse#email.com',
#subject = 'Old Registration Request - New Record',
#body = 'Somebody decided to register using the old system.'
END
GO
I'm getting this error when I try to execute this create statement:
Cannot create trigger on 'OldJunk.dbo.JunkTable' as the target is not in the current database.
Thanks in advance for your help.
You have to be in the OldJunk database (by using the USE .... command in SQL Server Management Studio), and then create the trigger using these SQL statements:
USE OldJunk;
GO
CREATE TRIGGER NotificationMail ON [dbo].[JunkTable]
.....
You cannot use the three-part (database).(schema).(object) notation in the trigger definition.
If that doesn't work - then you probably don't have such a table - is there a typo? Or is this not really a table?

Script for creating database if it doesn't exist yet in SQL Azure

This question may related to Checking if database exists or not in SQL Azure.
In SQL Azure, I tried to use a script like this to check the existence of a database, and create the database if it doesn't exist yet (in both SQLCmd and SSMS):
IF db_id('databasename') IS NULL CREATE DATABASE databasename
GO
However, SQL Azure keeps telling me
Msg 40530, Level 16, State 1, Line 2
The CREATE DATABASE statement must be the only statement in the batch.
While the same script did work on a local SQL express instance.
Does this mean it is not supported on SQL Azure?
Or is there any work around?
Thanks in advance.
Eidt:
Let me clarify what I want to achieve:
I want a script which will create a certain database only if it doesn't exist before.
Is it possible to have such kind of script for SQL Azure?
We have a similar problem.
It looks like we can do something with SET NOEXEC ON, as in the following StackExchange answer.
IF (<condition>)
SET NOEXEC ON
ELSE
SET NOEXEC OFF
GO
CREATE DATABASE databasename
GO
SET NOEXEC OFF
GO
It's saying you can't do theck and create in the same piece of sql.
i.e you need to do Select IF db_id('databasename')
test the whether it returns null, and if so then execute the create database.

Modify table creation date

Is it possible to modify the table creation date of a table? The date which we see on right clicking a table > properties > Created date or in sys.tables.create_date.
Even though the tables were created months ago, I want it to look like they were created today.
No more than you can change your birthday, and why would you want to ?
You could just
select * into #tmp from [tablename]
drop table [tablename]
select * into [tablename] from #tmp
That would rebuild the table and preserve the structure (to a point). You could script a new table , copy data then drop and rename. As above.
In SQL Server 2000, you could do this by hacking into the system tables with the sp_configure option 'allow updates' set to 1.
This is not possible in SQL Server 2005 and up. From Books Online:
This option is still present in the sp_configure stored procedure,
although its functionality is unavailable in Microsoft SQL Server 2005
(the setting has no effect). In SQL Server 2005, direct updates to the
system tables are not supported.
In 2005 I believe you could "game the system" by using a dedicated administrator connection, but I think that was fixed shortly after RTM (or it needs a trace flag or some other undocumented setting to work). Even using DAC and with the sp_configure option set to 1, trying this on both SQL Server 2005 SP4 and SQL Server 2008 R2 SP1 yields:
Msg 259, Level 16, State 1
Ad hoc updates to system catalogs are not allowed.
Who are you trying to fool, and why?
EDIT
Now that we have more information on the why, you could create a virtual machine that is not attached to any domain, set the clock back to whatever date you want, create a database, create your objects, back up the database, copy it to the host, and restore it. The create_date for those objects should still reflect the earlier date, though the database itself might not (I haven't tested this).
You can do this by shifting the clock back on your own system, but I don't know if I'd want to mess with my clock this way after SQL Server has been installed and has been creating objects in what will become "the future" for a short period of time. VM definitely seems safer to me.