Using name of a database inside a sql script for a full table name - sql

I struggled for a while with a bug, and then found out the reason for it in a database stored procedure code, which contained the old name of a database in a table name, whereas the current database name was already different. So, I'd like to ask:
Is there a situation in which using a database name as a part of a full table name (database name + schema name + table name) can be justified (provided we don't touch tables in other databases) or is it always a bad practice? How to correctly use a database name in sql scripts to keep code neutral to a specific database?
Code just for an illustration:
CREATE PROCEDURE [dbo].[MyProc]
AS
BEGIN
DELETE FROM [MyDatabase].[dbo].[MyTable]
END

No, you shouldn't use database names in a stored procedure unless you need to address two databases.
It causes exactly the kinds of bugs you're seeing. When the database name changes, all your SP code breaks, or continues working, but on the old database.
It does make sense if you are sending a SQL query to the database, but only if the application dynamically picks the database name to insert into the query.
My suggestion is that you do a full export of your database schema, and search for database names that are hardcoded and remove them.

It really depends on how your scripts are implemented.
Even if you don't refer to a table as
[MyDatabase].[dbo].[MyTable]
you will still need to refer to the database by:
USE [MyDatabase]
earlier in the script.

It is possible to mix trusted database tables in a single query. When someone do this,it is justified and mandatory to include database on table 'path'.
I don't found a reason out of this scenario if stored procedure and table is on the same database.
You can search all database name occurencies through database catalog in order to fix your development. For SQL Server 2005:
SELECT Name
FROM sys.procedures
WHERE OBJECT_DEFINITION(OBJECT_ID) LIKE '%databasename%'
GO
For SQL Server 2000:
SELECT DISTINCT so.name
FROM syscomments sc
INNER JOIN sysobjects so ON sc.id=so.id
WHERE sc.TEXT LIKE '%databasename%'
GO

Related

If not exist clause SQL statement

so I found this sql query in a project I am succeeding. This is the first time I encountering this clause/statement. I understand that this is to look if the table exist before creating one and that Object_ID is the table name that is to be created.
My questions are:
Does sysobject mean the database?
What is the Object property?
I know that it is not the columns inside the table to be created.
The columns are : dtb_color_id and description.
can someone explain this to me. please?
IF NOT EXISTS(SELECT * FROM SYSOBJECTS WHERE ID = OBJECT_ID('DTB_COLOR') AND OBJECTPROPERTY(ID,'ISUserTable') = 1)
BEGIN
.......some query I understand
END
sysobjects, OBJECTPROPERTY and OBJECT_ID are used in Microsoft SQL Server. They are part of the SQL Server DMVs and system functions/procedures used to query and manipulate the metadata.
sys.sysobjects is simply the list of all objects (tables, views, SPs, functions, etc) on the server in the active database. Please note, that sys.sysobjects is deprecated and is only available for backward compatibility. Use sys.objects instead
https://learn.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/system-dynamic-management-views?view=sql-server-ver16
It has (as far as I know) no meaning in MySQL, unless somebody specifically created them.
You can also use INFORMATION_SCHEMA which is available in MySQL too (however slightly different in different RDBMS).
MSSQL INFORMATION_SCHEMA: https://learn.microsoft.com/en-us/sql/relational-databases/system-information-schema-views/system-information-schema-views-transact-sql?view=sql-server-ver16
MySQL INFORMATION_SCHEMA: https://dev.mysql.com/doc/refman/8.0/en/information-schema.html
SQL Server has no CREATE TABLE IF NOT EXISTS construct, a variation of the mentioned condition is commonly used to imitate that.
This is a way in SQL Server to check if a table exists in the active database and to perform actions according to the result, like creating the table.
OBJECTPROPERTY simply checks (in this case) if the table is a user created one.
https://learn.microsoft.com/en-us/sql/t-sql/functions/objectproperty-transact-sql?view=sql-server-ver16
I would remove the OBJECTPROPERTY condition in case the part you understand is a CREATE TABLE statement. You don't want to create a table which has a similar name to any system table/view, also you don't want to execute the CREATE TABLE if there is a VIEW with the same name (table creation will fail)
Yes sysobject means database.
The OBJECTPROPERTY() function returns information about schema-
scoped objects in the current database. Use this to check if an
object is a table, view, stored procedure, etc. You can also use
it to check if a table has a primary key, foreign key, foreign
key reference, etc.
For more details : https://learn.microsoft.com/en-us/sql/t-sql/functions/objectpropertyex-transact-sql?view=sql-server-ver16
In this scenario it is used to check whether it is user table or
not. The result of the ISUserTable property is 1 when it is user
table otherwise returns 0.
Here the following steps are followed:
First, it executes the select statement inside the IF Exists
If the select statement returns a value that condition is TRUE for IF Exists
It starts the code inside a begin statement
DTB_COLOR - May be a stored procedure

What does double dots .. mean in SQL Server?

I am using SQL Server. I found the following way to backup a database table:
-- Taking a backup
SELECT * INTO MY_BACKUP_DATABASE..CustomersTemporaryTable FROM Customers
I am trying to understand the .. in the syntax. From what I understand, the sentence means that Customers is the table that is going to be backed-up by placing it all of its content into the database called MY_BACKUP_DATABASE using CustomersTemporaryTable as the destination table. I assume when executing the sentence, CustomersTemporaryTable must already exist. Is my understanding of the sentence to take a backup correct?
Each MS SQL Table identifiers can have a name compound of three parts separates with a dot :
the database name
the SQL schema name (by default dbo)
the table, view or Table UDF name
Syntax :
db_name.schema_name.table_name
But it is not always necessary to specify the three parts.
Inside the current database, no need to specify the db_name. It's implicit...
By default every SQL user is associate with a specific default schema (frequently dbo too...).
So you can specify a table name with :
schema_name.table_name
...SQL Server will try to find the table into the current DB
db_name..table_name
...SQL Server will try to find the table into the specified DB and the default user schema
table_name
...SQL Server will try to find the table into the current DB and the
default user schema
To know with SQL schema is associated with your SQL user, use :
SELECT SCHEMA_NAME() AS DEFAULT_CURRENT_USER_SCHEMA
To know all the associations between SQL users and SQL schemas, do :
SELECT name AS USER_NAME, default_schema_name
FROM sys.database_principals
WHERE type_desc LIKE '%?_USER' ESCAPE '?'
First of all, understand that what you are doing is not "taking a backup", it is inserting data into a table from another table. If you have not created the destination table the syntax is like this:
Select *
INTO Destination_Table
FROM Source_Table
The destination table will be created automatically. This doesn't necessarily work so well if you will be inserting additional data that might be different lengths or data types, but for a one of select should work fine.

MySql to Sql Server migration questions

I did a succesful migration from MySql to Sql Server using the migration tool.
Unfortunately for some reason it labels the tables database.DBO.tablename instead of just database.tablename
I have never used Sql Server so perhaps this is just the way they name their tables.
When I do:
SELECT TOP 1000 [rid]
,[filename]
,[qcname]
,[compound]
,[response]
,[isid]
,[isidresp]
,[finalconc]
,[rowid]
FROM [test].[calibration]
it does not work
But, when I do:
SELECT TOP 1000 [rid]
,[filename]
,[qcname]
,[compound]
,[response]
,[isid]
,[isidresp]
,[finalconc]
,[rowid]
FROM [test].[dbo].[calibration]
it works.
Does anyone know why it prefixes with DBO?
dbo is the standard database owner for anything you create (tables, stored procedures, etc,..), hence the migration tool automatically prefixing everything with it.
When you access something in Sql Server, such as a table called calibration, the following are functionally equivalent:
calibration
dbo.calibration
database_name.dbo.calibration
server_name.database_name.dbo.calibration
MySql doesn't, as far as I remember (we migrated a solution from MySql to SqlServer about 12 months ago using custom scripts executed by nant) support database owner's when referencing objects, hence you're probably not familiar with four part (server_name.database_name.owner_name.object_name) references.
Basically, if you want to specify the database you're accessing, you also need to specify the "owner" of the object. i.e, the following are functionally identical:
USE [master]
GO
SELECT * FROM [mydatabase].[dbo].[calibration]
USE [mydatabase]
GO
SELECT * FROM [calibration]
SqlServer uses an owner name when it references tables. In this case, dbo is the owner.
MySQL doesn't use owner for table names, which is why you didn't see those names before.
SQL Server has something called schemas, in this case the default schema is dbo but it could be anything you wanted. Schemas are used to logically group objects. So you can create a Employee schema and have all the Employee tables, views, procs and functions in there, this then also enables you to give certain users only access to certain schemas
Tell me your migration tool you have used, and let me know the version of from and to databases.
Regards
Eugene
You do have an issue here with the default schema, if it's set to 'dbo' for the user you logged in as you don't need to specify it. See http://msdn.microsoft.com/en-us/library/ms176060.aspx

Re-runnable SQL Server Scripts

What are the best practices for ensuring that your SQL can be run repeatedly without receiving errors on subsequent runs?
e.g.
checking that tables don't already exist before creating them
checking that columns don't already exist before creating or renaming
transactions with rollback on error
If you drop tables that exist before creating them anew, drop their dependencies first too, and don't forget to recreate them after
Using CREATE OR ALTER PROCEDURE instead of CREATE PROCEDURE or ALTER PROCEDURE if your flavor of SQL supports it
Maintain an internal versioning scheme, so the same SQL just doesn't get run twice in the first place. This way you always know where you're at by looking at the version number.
Export the existing data to INSERT statements and completely recreate the entire DB from scratch.
dropping tables before creating them (not the safest thing ever, but will work in a pinch if you know what you're doing)
edit:
I was looking for something like this:
IF EXISTS ( SELECT *
FROM sys.objects
WHERE object_id = OBJECT_ID(N'[dbo].[foo]')
AND OBJECTPROPERTY(object_id, N'IsUserTable') = 1 )
DROP TABLE foo
Do others use statements like this or something better?
edit:
I like Jhonny's suggestion:
IF OBJECT_ID('table_name') IS NOT NULL DROP TABLE table_name
I do this for adding columns:
IF NOT EXISTS ( SELECT *
FROM SYSCOLUMNS sc
WHERE EXISTS ( SELECT id
FROM [dbo].[sysobjects]
WHERE NAME LIKE 'TableName'
AND sc.id = id )
AND sc.name = 'ColumnName' )
ALTER TABLE [dbo].[TableName] ADD [ColumnName]
To make things easier I configure management studio to script objects as rerunnable
Tools
Options
SQL Server Object Explorer
Scripting
Object scripting options
Include IF Not Exists Clause True
I think the most important practice in ensuring that your scripts are re-runnable is to....run them against a test database multiple times after any changes to the script. The errors you encounter should shape your practices.
EDIT
In response to your edit on syntax, in general I think it is best to avoid the system tables in favor of the system views e.g.
if exists(Select 1 from information_schema.tables where table_name = 'sometable')
drop sometable
go
if exists(Select 1 from information_schema.routines where
specific_name = 'someproc')
drop someproc
To add to your list:
If you drop tables that exist before creating them anew, drop their dependencies first too, and don't forget to recreate them after
Using CREATE OR ALTER PROCEDURE instead of CREATE PROCEDURE or ALTER PROCEDURE if your flavor of SQL supports it
But ultimately, I would go with one of the following:
Maintain an internal versioning scheme, so the same SQL just doesn't get run twice in the first place. This way you always know where you're at by looking at the version number.
Export the existing data to INSERT statements and completely recreate the entire DB from scratch.
I recently found a check-in for existence that i didn't know existed and i liked it because it's shorter
IF OBJECT_ID('table_name') IS NOT NULL DROP TABLE table_name
before, i used to use
IF EXISTS (SELECT * FROM information_schema.tables WHERE table_name = 'table_name')
DROP TABLE table_name
Which i found useful because it's a little more portable (MySql, Postgres, etc), taking into account the differences, of course
For maintaining schemas, look at a migration tool. I think LiquiBase would work for SQL Server.
You'll also need to check for foreign keys on any tables that you may be dropping/recreating. Also, consider any data changes that you might make - delete rows before trying to insert a second time, etc.
You also might want to put in code to check for data before deleting tables as a safeguard so that you don't drop tables that are already being used.
For a SQL batch statement, you can issue
This is just a FYI, I just ran it 10 times
IF EXISTS ( SELECT *
FROM sys.objects
WHERE object_id = OBJECT_ID(N'[dbo].[foo]')
AND OBJECTPROPERTY(object_id, N'IsUserTable') = 1 )
DROP TABLE foo
GO 10 -- run the batch 10 times
This is just a FYI, I just ran it 10 times
Beginning execution loop Batch
execution completed 10 times.
The "IF OBJECT_ID('table_name', 'U') IS NOT NULL" syntax is good, it can also be used for procedures:
IF OBJECT_ID('procname', 'P') IS NOT NULL
...
... and triggers, views, etc... Probably good practice to specify type (U for table, P for prog, etc.. dont remember the exact letters for all types) in case your naming strandards allow procedures and tables to have similar names...
Furthermore, a good idea might be to create your own procedures that changes tables, with error handling proper to your environment. For example:
prcTableDrop, Proc for droping a
table
prcTableColumnAdd, Proc for adding a column to a table
prcTableColumnRename, you get the idea
prcTableIndexCreate
Such procs makes creating repeatable (in same or other db) change scripts much easier.
/B
I've describe a few checks in my post DDL 'IF not Exists" conditions to make SQL scripts re-runnable
Just adding this for future searchers (including myself), such scripts are called idempotent (the noun being idempotency)

View Temporary Table Created from Stored Procedure

I have a stored procedure in SQL 2005. The Stored Procedure is actually creating temporary tables in the beginning of SP and deleting it in the end. I am now debugging the SP in VS 2005. In between the SP i would want to know the contents into the temporary table. Can anybody help in in viewing the contents of the temporary table at run time.
Thanks
Vinod T
There are several kinds of temporary tables, I think you could use the table which is not dropped after SP used it. Just make sure you don't call the same SP twice or you'll get an error trying to create an existing table. Or just drop the temp table after you see it's content. So instead of using a table variable (#table) just use #table or ##table
From http://arplis.com/temporary-tables-in-microsoft-sql-server/:
Local Temporary Tables
Local temporary tables prefix with single number sign (#) as the first character of their names, like (#table_name).
Local temporary tables are visible only in the current session OR you can say that they are visible only to the current connection for the user.
They are deleted when the user disconnects from instances of Microsoft SQL Server.
Global temporary tables
Global temporary tables prefix with double number sign (##) as the first character of their names, like (##table_name).
Global temporary tables are visible to all sessions OR you can say that they are visible to any user after they are created.
They are deleted when all users referencing the table disconnect from Microsoft SQL Server.
Edit the stored procedure to temporarily select * from the temp tables (possibly into another table or file, or just to the output pane) as it runs..?
You can then change it back afterwards. If you can't mess with the original procedure, copy it and edit the copy.
I built a few stored procedures which allow you to query the content of a temp table created in another session.
See sp_select project on github.
The content of the table can be displayed by running exec sp_select 'tempdb..#temp' from no matter which session.
Bottom line: the default Visual Studio Microsoft debugger is not in the same session as the SQL code being executed and debugged.
So you can ONLY look at #temp tables by switching them to global ##temp tables or permanent tables or whatever technique you like best that works across sessions.
note: this is VERY different from normal language debuggers... and I suspect kept
that way by Microsoft on purpose... I've seen third party SQL debugger tools decades ago
that didn't have this problem.
There is no good technical reason why the debugger cannot be in the same session as your SQL code, thus allowing you to examine all produced contructs including #temp tables.
To expand on previous suggestions that you drop the data into a permanent table, you could try the following:
-- Get rid of the table if it already exists
if object_id('TempData') is not null
drop table TempData
select * into TempData from #TempTable
This helped me.
SELECT * FROM #Name
USE [TEMPDB]
GO
SELECT * FROM syscolumns
WHERE id = ( SELECT id FROM sysobjects WHERE [Name] LIKE '#Name%')
this gives the details of all the temp table