Get the table name using schema - sql-server

I have seen some query like this in a stored procedure
SELECT ORDINAL_POSITION 'column_id', column_name 'column_name',
column_name + ' : ' + data_type 'column_nametype',
data_type 'data_type',
CHARacter_maximum_length 'SIZE'
FROM information_schema.columns
WHERE table_name = #TableName
but i found that information_schema.columns is not a table name and it is a schema, but how it is retrieving the data?? and how can i know the actual table name?What is the use of a schema??

The INFORMATION_SCHEMA views reside in the Master database on the server and are a special type of view that will retrieve data from your database context. That is, although they are in the master database they will retrieve information for whatever database you are currently using.
Just like any other view you can see the source for these views. In the particular example given it uses sys.columns, sys.objects and sys.types which are themselves system views.
Although views such as sys.types is a view to which the source code is available some of the system tables/views within it are not available for direct reference. For example sys.sysscalartypes is not available to the user and neither is the system function sysconv.
The user of INFORMATION_SCHEMA views is not limited to SQL Server although the implementations appear to be platform specific. For example MySQL has its own INFORMATION_SCHEMA structures.
The use of the old sysobjects (as opposed to sys.objects) system tables is discouraged because there is no guarantee their use will continue in the future. It has to be said that INFORMATION_SCHEMA although generally useful doesn't always expose the level of information a DBA would require.

Try this query:
DECLARE #TableName NVARCHAR(MAX)
SET #TableName = 'tblTest'
SELECT
column_id 'column_id', columns.name 'column_name'
,columns.name + ' : ' + types.name 'column_nametype'
,types.name 'data_type'
,columns.max_length 'SIZE'
FROM
sys.columns
INNER JOIN
sys.types
ON
types.system_type_id = columns.system_type_id
WHERE
objecT_id = OBJECT_ID(#TableName)
ORDER BY
Column_id

Related

Get all the table names that are available in all the schemas

I do not have names of the schema that are available. According to my finding all the queries that i am using are specific to a schema name. I need name of all the tables irrespective of the schema name.
Can anyone help me with that.
I have used the following queries:
SELECT sch.name AS SchemaName , tbl.name AS TableName FROM sys.tables tbl INNER JOIN sys.schemas sch ON tbl.SCHEMA_ID = sch.SCHEMA_ID ORDER BY tbl.name;
select * from information.schema.tables where TABLE_TYPE='BASE TABLE';
select * from sys.tables;
select * from sysobjects where xtype='U';
All of these queries are schema specific. If we want to switch between schema we have to use USE %SCHEMA_NAME%. but i need to get all the table names irrespective of the schema name.
Apologies, but i meant to say databases
A database and a schema, in SQL Server, are very different objects. A schema is an object within a database, where as a database is on "object" in an instance. The sys and INFORMATION_SCHEMA objects are also database objects and so will only list the objects within the database context they are referenced in.
For example the below 2 examples would both return details of tables in the MyDB database:
USE master;
SELECT *
FROM MyDB.sys.tables;
GO
USE MyDB;
SELECT *
FROM sys.tables;
If you want to get the details of tables in every Database you'll either need to query them separately, or generate and run a dynamic statement. The dynamic approach would be something like this:
USE master;
GO
DECLARE #SQL nvarchar(MAX),
#CRLF nchar(2) = NCHAR(13) + NCHAR(10);
DECLARE #Delimiter nvarchar(30) = #CRLF + N'UNION ALL' + #CRLF;
SET #SQL = (SELECT STRING_AGG(N'SELECT N' + QUOTENAME(d.[name],'''') + N' AS DatabaseName, t.[name] AS TableName FROM ' + QUOTENAME(d.[name]) + N'.sys.tables t', #Delimiter) WITHIN GROUP (ORDER BY d.database_id)
FROM sys.databases d
WHERE d.database_id > 4) + N';' --skip system databases
--PRINT #SQL; --Your best friend
EXEC sys.sp_executesql #SQL;
If you're using an older version of SQL Server, you'll need to use the "old" FOR XML PATH method, rather than STRING_AGG.

exec sp_tables_ex returns nothing on a server I can find using exec sp_linkedservers

I'm trying to find data in a database which hasn't been used that much.
I've seen that it is a linked server using:
exec sp_linkedservers
which returns the servername, TheSRV along with for instance its catalog name S100.
I then try to find information about which tables are present in the linked server, TheSRV.
For this I try to use:
exec sp_tables_ex TheSRV
but this returns only the headers, without any data.
I can do a Query using openquery like this:
Select name, date From OPENQUERY(TheSRV, 'Select Name, Date from S100.F1.TableName')
which returns valid data.
How can I find the information I need about tables present, when I can't find a list of tables?
You should be able to use one of the standard ways of listing schema objects, qualifying server name as part of the four part naming convention:
SELECT *
FROM TheSRV.S100.INFORMATION_SCHEMA.TABLES T
WHERE T.TABLE_TYPE = 'BASE TABLE'
To see the columns in each of those tables:
SELECT C.*
FROM TheSRV.S100.INFORMATION_SCHEMA.TABLES T
INNER JOIN TheSRV.S100.INFORMATION_SCHEMA.COLUMNS C
ON T.TABLE_NAME = C.TABLE_NAME
AND T.TABLE_SCHEMA = C.TABLE_SCHEMA
WHERE T.TABLE_TYPE = 'BASE TABLE'
ORDER BY C.TABLE_NAME, C.ORDINAL_POSITION

Refactor rename field in many database tables

I am faced with renaming a field where the same fieldname is replicated across many tables.
Looking for a script or free/low cost tool which will go through all the tables and if fieldA exists, rename it to fieldB.
thanks
You can use SQL Server metadata tables to create dynamic sql statements for your purpose.
For list of available tables you can sys.tables for list of tables and sys.columns for list of columns. using these tables you can create a table of sql statements. For executing dynamic sqls you need to sp_executesql stored procedure.
This is a sample code just to show how to use metadata tables and sp_executesql:
And note that I used other metadata tables which I am more comfortable with. also you may use a cursor to run all the scripts returned by query.
CREATE Database TestDB
CREATE Table Table1 (Id int , fieldA varchar(50) )
Declare #update_query nvarchar(max)
select
#update_query = 'sp_rename ''' + t.TABLE_NAME + '.' + c.COLUMN_NAME + ''',''' + 'fieldB' + ''''
From INFORMATION_SCHEMA.COLUMNS c JOIN INFORMATION_SCHEMA.Tables t ON c.TABLE_CATALOG = t.TABLE_CATALOG AND c.TABLE_SCHEMA = t.TABLE_SCHEMA AND c.TABLE_NAME = t.TABLE_NAME
WHERE
c.COLUMN_NAME = 'fieldA'
SELECT #update_query
EXEC sp_executesql #update_query
Take a look at the Database project type in VS2010, if you haven't already. It has a lot of features that make DB refactoring easier than working SQL Server Management Studio.
For example if you rename a column, it will give you build errors for all the FKs that reference the old column name. And it does a lot of build-time validation to make sure your database objects don't reference objects which no longer exist. And because all of the database objects are just kept as text files, actions like rename are pretty much just search/replace.
Also, it has very handy "sync" feature which compares the DB project scripts & databases, generates a DIFF report, and generates the scripts to move selected changes between the two (either DB project to SQL Server, or vice versa).
Having said all that, it won't automatically do the renames for you -- in other words, when you rename a column it won't fix up all references to that column throughout the project. But if you make a mistake you will get build errors when it validates the database structure. So at least makes it easy to find the places that you need to change.
If you're using Azure SQL Server, you can use Sam's answer with another input parameter to sp_rename, #objtype = 'COLUMN'.
Declare #update_query nvarchar(max)
select
#update_query = 'sp_rename ''' + t.TABLE_NAME + '.' + c.COLUMN_NAME + ''',''' + 'fieldB' + ''',''' + 'COLUMN' + ''''
From INFORMATION_SCHEMA.COLUMNS c JOIN INFORMATION_SCHEMA.Tables t ON c.TABLE_CATALOG = t.TABLE_CATALOG AND c.TABLE_SCHEMA = t.TABLE_SCHEMA AND c.TABLE_NAME = t.TABLE_NAME
WHERE
c.COLUMN_NAME = 'fieldA'
SELECT #update_query
EXEC sp_executesql #update_query

Is there a succinct way to retrieve a list of table column names with T-SQL?

When I'm looking round a SQL Server database I often want to interactively retrieve a simple list of column names for a database table (no data type information etc., just the names) using sqlcmd.
I can do this:
EXEC sp_columns #table_name = 'tablename'
which gives me much more than I want and wraps in a command prompt to the extent that it is close to unintelligible, or I can do this:
SELECT col.name
FROM sysobjects obj
INNER JOIN syscolumns col
ON obj.id = col.id where obj.name = 'tablename'
which gives me what I want but is a bit verbose.
I'd like to be able to do something like this:
SELECT column_name
FROM (EXEC sp_columns #table_name = 'tablename')
but that doesn't work (see, for example, this question).
Is there a more succinct way to do this (i.e. one that is easier to type at the command line and therefore less error prone)?
Look at the ANSI-defined INFORMATION_SCHEMA views. Try SELECT * FROM INFORMATION_SCHEMA.COLUMNS for starters and go on from there.
Your example would require this SQL:
SELECT column_name
FROM information_schema.columns
WHERE table_name = 'tablename'
SELECT [name] FROM sys.columns WHERE [object_id] = OBJECT_ID('MyTable')
Catalog views:
We recommend that you use catalog
views because they are the most
general interface to the catalog
metadata and provide the most
efficient way to obtain, transform,
and present customized forms of this
information. All user-available
catalog metadata is exposed through
catalog views.
Purely personal, but I don't like the INFORMATION_SCHEMA views

OBJECT_ID of object in another database - how to find database ID or name/fully qualified object name?

Example:
USE AnotherDB
-- This works - same ID as from other DB
SELECT OBJECT_ID('AnotherDB.ASchema.ATable')
-- This works
SELECT OBJECT_NAME(OBJECT_ID('AnotherDB.ASchema.ATable'))
USE ThisDB
-- This works - same ID as from other DB
SELECT OBJECT_ID('AnotherDB.ASchema.ATable')
-- Gives NULL
SELECT OBJECT_NAME(OBJECT_ID('AnotherDB.ASchema.ATable'))
Obviously the metadata functions expect a current database. The BOL entries typically have language like this for functions like OBJECT_NAME etc.:
The Microsoft SQL Server 2005 Database
Engine assumes that object_id is in
the context of the current database. A
query that references an object_id in
another database returns NULL or
incorrect results.
The reasons I need to be able to do this:
I can't USE the other database from within an SP
I can't create a proxy UDF stub (or alter anything) in the other databases or in master (or any other database besides my own) to help me out.
So how can I get the database from OBJECT_ID('AnotherDB.ASchema.ATable') when I'm in ThisDB?
My goal is to take a possibly partially qualified name from a configuration table, resolving it in the current context to a fully qualified name, use PARSENAME to get the database name and then dynamic SQL to build a script to be able to get to the meta data tables directly with database.sys.* or USE db; sys.*
You should be able to do this:
SELECT
name
FROM
AnotherDB.sys.objects --changes context
WHERE
object_id = OBJECT_ID('AnotherDB.ASchema.ATable')
This is what you effectively do with OBJECT_ID('AnotherDB.ASchema.ATable')
This means that you could rely on dbname.sys.objects and avoid confusion with metadata functions.
Note: the new Catalog views are designed to be used and not change from version to version, as per the link. In the old days, it was consider bad practice to use system tables but the stigma still remains.
So, you can safely rely on sys.objects rather that the metadata functions.
Do I understand it correctly that you want the db id of AnotherDB?
SELECT *
FROM master..sysdatabases
WHERE name = 'AnotherDB'
Otherwise, you can USE other db's in dynamic SQL if it helps:
DECLARE #SQL NVARCHAR(MAX)
, #objId INT
SET #SQL = N'
USE AnotherDB
SELECT #id = OBJECT_ID(''customer'')
'
EXEC SP_EXECUTESQL #SQL
, N'#id INT OUTPUT'
, #id = #objId OUTPUT
SELECT #objId
OR Execute SP's in other dbs with:
EXEC AnotherDB.dbo.ProcedureName
#paramX = ...
, #paramY = ...
Take a look at the PARSENAME function in TSQL - will allow you to pull out any of the 4-part portions of a fully (or non-fully) qualified name. For the database in your example:
select parsename('AnotherDB.ASchema.ATable',3)
returns:
AnotherDB
select parsename('AnotherDB.ASchema.ATable',2)
returns:
ASchema
If non-fully qualified, you'll get null results if you ask for the portion of a name that isn't included in the string:
select parsename('ASchema.ATable',3)
returns:
NULL
I had the same issue but with OJBECT_SCHEMA_NAME as well. Following on from chadhoc's response using parsename works with OBJECT_NAME like:
DECLARE #OrigTableName NVARCHAR(MAX);
SELECT #OrigTableName = 'AnotherDB.ASchema.ATable'
SELECT OBJECT_NAME(OBJECT_ID(#OrigTableName), DB_ID(PARSENAME(#OrigTableName, 3)))
, OBJECT_SCHEMA_NAME(OBJECT_ID(#OrigTableName), DB_ID(PARSENAME(#OrigTableName, 3)))
I used the following solution:
DECLARE #SchemaName varchar(255) = 'SchemaName'
DECLARE #ObjectName varchar(255) = 'ObjectName'
SELECT o.*
FROM AnotherDB.sys.objects AS o
INNER JOIN AnotherDB.sys.schemas AS s ON o.schema_id = s.schema_id
WHERE s.name = #SchemaName
AND o.name = #ObjectName
IF NOT EXISTS (
SELECT si.name
FROM <DatabaseName>.sys.indexes si
INNER JOIN <DatabaseName>.sys.objects so
ON si.object_id = so.object_id
WHERE si.name = '<IndexName>'
AND so.name = '<TableName>'
)
BEGIN
CREATE INDEX [<IndexName>] ON [<DatabaseName>].[<Schema>].[<TableName>]
([column1])
INCLUDE ([<column2>],,,,
)
WITH (online = ON)
END

Resources