WHAT I EXPECT:
I want to create a Job in my SQL Server Agent that allows me to fire off a stored procedure to clean up a particular table. The spu would take two parameters: TableName and Days.
TableName would be the name of the table I'm looking for and Days would be how far back I wish to delete records.
WHAT I'VE DONE:
After having looked around online I've found sources on how to see if a User Database holds the supplied TableName:
SELECT *
FROM INFORMATION_SCHEMA.Tables
WHERE TABLE_NAME = #TableName
This results in a few rows looking a bit like this:
TABLE_CATALOG | TABLE_SCHEMA |TABLE_NAME |TABLE_TYPE
Database_A | table_schema |table_A |table_type
WHAT I DON'T UNDERSTAND:
How can I use the resulting rows of the previous query to find all rows of the supplied #TableName in a particular Database? In pseudo:
SELECT * FROM table_A WHERE database = database_A
I know I need to use a cursor somehow, that's not the problem.
What I'm simply struggling to understand is how I can use the database name and the table name to find the rows of the table in a particular database.
In my case I've got 10 or so databases that need to be iterated through to find the initial dataset (all user databases where #TableName exists) and then a secondary query to find all rows of the #TableName in the database that the cursor currently is pointing at.
You have to do select * from ..table_A
but you can't do that in a a simple TSQL. Possibly you could generate a sub script and execute.
IF EXISTS( SELECT * FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'SiteInformation'
AND COLUMN_NAME = 'Number_Injectors')
BEGIN
SELECT [Number_Injectors] as Injectors
FROM [BLEND].[dbo].[SiteInformation]
END
ELSE
BEGIN
IF EXISTS( SELECT * FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'SiteInformation'
AND COLUMN_NAME = 'Injectors')
BEGIN
SELECT [Injectors] as Injectors
FROM [BLEND].[dbo].[SiteInformation]
END
END
The basic premise is that I have Visual Studio code that references a table called SiteInfomation from different servers to collect information concerning a certain piece of machinery. Thing is that I found out that a couple of those servers have have different column names (Injectors and Number_Injectors). The data variable Injectors from Visual Studio is looking for columns named Injectors to collect information. When it comes to a SiteInformation table that has a column named Number_Injectors instead of Injectors, the value that is returned is NULL. Number_Injectors and Injectors are both one and the same except in name.
I checked StackOverflow and found a topic on how to check if a column exists and created the code mentioned above. The if exist portion of the code works fine but I get an error if I use this query on a server that doesn't contain one of the two column names.
Example: The SiteInformation table from Server A has the column Injectors. It would give me an error because of this code:
SELECT [Number_Injectors] as Injectors
FROM [BLEND].[dbo].[SiteInformation]
Likewise the SiteInformation table from Server B has the column Number_Injectors. It would give me an error because of this code:
SELECT [Number_Injectors] as Injectors
FROM [BLEND].[dbo].[SiteInformation]
I am a bit lost on how to correct it. It seems like both Select queries are ran at the same time despite the if-exist part. Any suggestions will be helpful.
The SQL compiler is going to try to validate both select statements, so you'd need to "hide" them from the compiler by embedding them in an EXEC like this:
EXEC ('SELECT [Number_Injectors] as Injectors
FROM [BLEND].[dbo].[SiteInformation]')
We have a script that must allow for being re-run several times.
We have an MS-SQL script that updates a table if a (now obsolete) column exists, then deletes the column. To ensure that the script can be run several times, it first checks for the existence of a column before performing the updates.
The script works as expected on our dev database, updating the data on the first run, then displaying the message 'Not updating' on subsequent runs.
On our test database the script runs fine on the first run, but errors with "Invalid column name 'OldColumn'" on subsequent runs; if I comment out the UPDATE and ALTER statements it runs as expected.
Is there a way to force the script to run even if there's a potential error, or is it something to do with how the database was set-up? (fingers crossed I'm not looking like a complete noob!)
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'MyTable' AND COLUMN_NAME = 'OldColumn')
BEGIN
PRINT 'Updating and removing old column...'
UPDATE MyTable SET NewColumn='X' WHERE OldColumn=1;
ALTER TABLE MyTable DROP COLUMN OldColumn;
END
ELSE
PRINT 'Not updating'
GO
As a work around you could do
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'MyTable' AND COLUMN_NAME = 'OldColumn')
BEGIN
PRINT 'Updating and removing old column...'
EXEC ('UPDATE MyTable SET NewColumn=''X'' WHERE OldColumn=1;');
ALTER TABLE MyTable DROP COLUMN OldColumn;
END
ELSE
PRINT 'Not updating'
I made a copy of a DB that is used for a web app to make a new instance of this web app. I am wondering how do I remove all data and transactions and what not so that it is just a clean empty shell of tables ready to be written with new data?
Sql Server Database Publishing Wizard. Create a script with just the schema, specifying to drop the existing objects.
run this script:
select 'TRUNCATE TABLE ' + name from sysobjects where xtype='U'
and then paste the results into a new script and run that
(And for God's sake, be careful!) :)
EDIT
From comments it seems TRUNCATE can't delete rows from tables with foreign keys.
You could use
select 'DELETE FROM ' + name from sysobjects where xtype='U'
and you would also have to rearrange the output to delete from child tables first. Others have suggested scripting a clean database and that is probably a better idea TBH.
Uncomment out the -- to actually run... BE CAREFUL!!
Declare #t varchar (1024)
Declare tbl_cur cursor for
select TABLE_NAME from INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'
OPEN tbl_cur
FETCH NEXT from tbl_cur INTO #t
WHILE ##FETCH_STATUS = 0
BEGIN
--EXEC ('TRUNCATE TABLE '+ #t)
FETCH NEXT from tbl_cur INTO #t
END
CLOSE tbl_cur
DEALLOCATE tbl_Cur
EDIT:
In answer to the comment question... damn good question. I imagine you could find all the foreign keys and save them off
SELECT 'ALTER TABLE ' + b.TABLE_NAME + ' WITH CHECK ADD CONSTRAINT [' + a.CONSTRAINT_NAME + '] FOREIGN KEY '
+ c.COLUMN_NAME + ' REFERENCES [' + d.TABLE_NAME +'] ([' + e.COLUMN_NAME + '])'
FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS a
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS b
ON a.CONSTRAINT_NAME = b.CONSTRAINT_NAME
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS d
ON a.UNIQUE_CONSTRAINT_NAME = d.CONSTRAINT_NAME
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE c
ON a.CONSTRAINT_NAME = c.CONSTRAINT_NAME
INNER JOIN (
SELECT
f.TABLE_NAME,
g.COLUMN_NAME
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS f
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE g
ON f.CONSTRAINT_NAME = g.CONSTRAINT_NAME
WHERE f.CONSTRAINT_TYPE = 'PRIMARY KEY'
) e
ON e.TABLE_NAME = d.TABLE_NAME
ORDER BY a.CONSTRAINT_NAME
and then you could drop all of them (I dont believe it matters in which order you drop the constraints)
SELECT 'ALTER TABLE ' + col.TABLE_NAME + ' DROP CONSTRAINT ' + u.CONSTRAINT_NAME
FROM INFORMATION_SCHEMA.COLUMNS col
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE u
ON col.TABLE_NAME = u.TABLE_NAME
AND col.COLUMN_NAME = u.COLUMN_NAME
INNER JOIN INFORMATION_SCHEMA.table_constraints t
ON u.CONSTRAINT_NAME = t.CONSTRAINT_NAME
WHERE t.CONSTRAINT_TYPE = 'FOREIGN KEY'
and THEN use the first cursor to truncate all the tables. Then you can use the results of the script you saved off to recreate all of the FK relationships.
I don't know of any one step magical silver bullet command to do so, but if you want to preserve your tables/schemas, you'd probably need to script a truncate table for each.
Alternatively, you could script out the whole database and use that one script to regenerate a new database after you drop the "used" one. Making sense?
Right click on the Database you want to deal with, select Script Database As (3rd option from the top), then the option DROP and CREATE to ... at which point maybe you want to do this to a file or the clipboard and paste it somewhere.
Then, with this file handy as your script, run it to create a clean nice database.
You could create an empty database, and then use something like SQL Compare to compare your existing database against the empty one to generate scripts to recreate the database entirely from scratch.
You could also use the following SQL:
--// Switch to the database to be modified
USE DatabaseName;
--// The following commands need to be run for each table
--// You could perhaps automate this by using a cursor
--// First truncate the table and remove all data
TRUNCATE TABLE MyTable;
--// Also reset the identity seed
DBCC CHECKIDENT (MyTable, reseed, 1)
I'd recommend re-creating the database structure from scratch, rather than doing a backup-and-restore-to-new-database, as this will give you a completely clean database without any 'residue' (like stuff in the transaction log).
Truncating will work if you no foreign keys defined (And if you don't please please add them).
If your using SQL Server 2005 (08 might be the same), you can generate a script for the entire database, from within Sql Server Management Studio. Right click on the database you want to script.
Then go to tasks, and generate scripts. Script out all the objects, then you can use this script to build a fresh copy of the DB based on just the schema.
This article presents store-procedure without any of the mentioned problems.
The key is to disable referential integrity :)
You may want to consider just generating a t-sql script that only includes the structure from your existing database. The SQL Server Management Console makes this very easy, as you just need to right click on your original database, select 'tasks->generate scripts'. From there, just click through the defaults and select the objects that you want to duplicate (tables, etc).
This generates a nice T-SQL script that you can apply to any blank database, giving you the structure that you are looking for without the data. To me, this seems to be a more appropriate option as compared to truncation.
you would just truncate each table as in
use [dbname]
truncate table [table]
where [dbname] is the name of the copied database, and you would copy the 2nd line for each table in the database.
I'm sure with about 5-10 minutes, you could create a script that would read over all the available tables listed in the systables and use that information to do a while loop so you didn't have to write "truncate table [table]" for each table, but that's the general idea.
--
Ok,
To all that answered after me, I'm getting this mental "guilt" thing going on because I didn't write up that he should have created a TSQL script and re-create a database off of that.
There were several reasons why I didn't go that route.
You don't know what sorts of
"static" data he has in the
database.
He specifically asked
about how to clear the database.
I don't currently know what the #OP
has built into the rest of the
system. there could potentially be
dependencies that he needs a copy of
the original in order to satisfy a
condition.
Had the gentleman asked this in a different manner, I may have indeed answered like so many have and simply stated to script the database out.
I have a lot of code I am trying to run where I'm querying the sysobjects table to check if an object exists before I drop it and create it again.
Issue being, sometimes if I go:
if not exists (select name from sysobjects o where o.name = 'my_table' and o.type = 'U')
CREATE TABLE my_table (..)
go
it works, no worries. However, when I came back to run it again, I get this lovely error:
SQL Server Error on (myserver) Error:2714 at Line:10 Message:There is already an object named 'my_table' in the database.
Thanks for that, SQL Programmer. I actually asked for you not to create this table if it already exists. -_-
Any ideas?
the logic to what you are doing doesn't seem quite right. based on your statement:
"I am trying to run where I'm querying the sysobjects table to check if an object exists before I drop it and create it again"
you should simply do a delete followed by a create. This way is usually better because it ensures that the table will be updated. if the table existed and you had changes, you are probably not getting what you want.
The immediate issue you are running into is an assumed db ownership that was not consistent between runs.
based on your clarification below - here is what you can do:
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[XXXX]') AND type in (N'U'))
DROP TABLE [dbo].[XXXX]
GO
CREATE TABLE [dbo].[XXXX(...
GO
you can run this over and over again...
The sybase parsers object validation pass is global and not based on conditional evaluation. Even though your code can not execute CREATE TABLE the statement is still checked for syntax and applicability which fails when the system sees that the table already exists.
The only way around this that I know of is to put your create statements inside of an EXEC() which would be evaluated only if the section was executed.
yes, the entire batch of SQL is normalized and compiled so as to create an "execution plan" for the entire batch. During normalization, the "possible" "create table" statement is a problem if it already exists at compile time.
My solution: rename -
if exists (select 1 from ....)
begin
drop table xyz
create table xyz_zzzz ( ... )
exec sp_rename 'xyz_zzzz','xyz'
end