Running query against all information schema in sql instance - sql

I know there are many variation of this question but I haven't found one that gives me exactly the results.
Edit: I am trying to get all columns from all tables and views in all databases from the sql server instance
I have narrowed down exactly the information I want returned from the information schema of each database but I can't quite get the syntax of the query right
declare #SQL nvarchar(max) = ''
select #SQL = #SQL + 'SELECT ''' + d.name + ''' as DatabaseName, TABLE_CATALOG, TABLE_SCHEMA ,
TABLE_NAME , COLUMN_NAME , ORDINAL_POSITION , COLUMN_DEFAULT , DATA_TYPE , CHARACTER_MAXIMUM_LENGTH
FROM ''' + d.name + '.INFORMATION_SCHEMA.COLUMNS'
from sys.databases d
where d.name not in('master', 'tempdb', 'msdb', 'model')
exec sp_executesql #SQL
I am missing something to complete my query but can't quite figure it out

Related

View columns from tables where name like 'ENG_Parameters_%'

I am trying to create a SQL View that will load columns:
[item],[manufacturer_item],[symbol],[footprint]
from any table that matches the name ENG_Parameter_%.
I need to leave it generic because, at any point in time, ENG_Parameter_% might have new or removed tables, so I cannot just hard-code any table names.
Is there a SQL command that could be made to generate this?
The dynamic sql to create the views:
DECLARE #SQL nvarchar(2000);
SET #SQL=N' SELECT
''CREATE VIEW [vw'' + t.name + '']
AS
SELECT [item],[manufacturer_item],[symbol],[footprint]
FROM ['' + t.name + '']'' AS sql_for_view
FROM sys.columns c
INNER JOIN sys.tables t
ON c.object_id=t.object_id
WHERE c.name LIKE ''ENG_Parameter_%''';
exec sp_executesql #SQL;
Thanks to #OwlsSleeping answer (StackOverflow SQL-UNION ALL), this ended up with exactly what I needed:
DECLARE #SQL nvarchar(max)
select #SQL = COALESCE(#SQL , '') + 'SELECT [item],[manufacturer_item],[symbol],
[footprint] FROM [' + TABLE_NAME + '] UNION ALL '
FROM INFORMATION_SCHEMA.TABLES where TABLE_NAME LIKE 'ENG_Parameters_%'
SELECT #SQL = LEFT(#SQL, LEN(#SQL) - 11)
exec sp_executesql #SQL;

Get list of databases, tables, columns, and column datatypes

I would like to get a collection of all user databases, all the tables within each database, and columns and their datatypes for each of the tables. I have a SQL script that gets the database names I am looking for (and excludes those I am not, like system databases)...
DECLARE #DatabaseIgnoreList AS VARCHAR(500);
SET #DatabaseIgnoreList = 'DatabaseNotToInclude';
SELECT name, database_id
FROM sys.databases
WHERE HAS_DBACCESS(name) = 1
AND name NOT IN ('msdb')
AND database_id > 4
AND name NOT LIKE '%$%'
AND name NOT IN (#DatabaseIgnoreList)
ORDER BY name ASC
I also have a separate SQL script that gets all the tables and columns from a specific database. I found this from this SO question/answer.
USE DatabaseName;
SELECT TABLE_SCHEMA ,
TABLE_NAME ,
COLUMN_NAME ,
ORDINAL_POSITION ,
COLUMN_DEFAULT ,
DATA_TYPE ,
CHARACTER_MAXIMUM_LENGTH ,
NUMERIC_PRECISION ,
NUMERIC_PRECISION_RADIX ,
NUMERIC_SCALE ,
DATETIME_PRECISION
FROM INFORMATION_SCHEMA.COLUMNS;
What I am not sure how to do is to link the two. For each database I would like to run the table/column discover script and end up with one single table that has the database name, table name, column name, and column datatype.
Is this a situation for a cursor? I am using SQL Server 2008+.
Here is another approach. This is not using any cursors or loops. It is a single result set with one extra column for the database name. There are several comments in the code to help.
FWIW - I just tested this on a dev server that has 60 databases. It returned all 165,000+ rows in just over 15 seconds.
DECLARE #DatabaseIgnoreList AS VARCHAR(500);
SET #DatabaseIgnoreList = 'DatabaseNotToInclude';
declare #SQL nvarchar(max) = ''
select #SQL = #SQL +
'SELECT ''' + quotename(name) + ''' as DatabaseName,
TABLE_SCHEMA = TABLE_SCHEMA collate database_default,
TABLE_NAME = TABLE_NAME COLLATE database_default ,
COLUMN_NAME = COLUMN_NAME COLLATE database_default ,
ORDINAL_POSITION ,
COLUMN_DEFAULT = COLUMN_DEFAULT COLLATE database_default ,
DATA_TYPE = DATA_TYPE COLLATE database_default ,
CHARACTER_MAXIMUM_LENGTH ,
NUMERIC_PRECISION ,
NUMERIC_PRECISION_RADIX ,
NUMERIC_SCALE ,
DATETIME_PRECISION
FROM ' + quotename(name) + '.INFORMATION_SCHEMA.COLUMNS union all '
FROM sys.databases
WHERE HAS_DBACCESS(name) = 1
--AND name NOT IN ('msdb') --why bother? You already exclude this with database_id > 4
AND database_id > 4
AND name NOT LIKE '%$%'
AND name <> #DatabaseIgnoreList --if you need to exclude more than 1 we need a little different approach here
and state_desc = 'ONLINE' --want to exclude any offline databases
ORDER BY name ASC
set #SQL = left(#SQL, LEN(#SQL) - 10) + ' order by DatabaseName, TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME' --This will order the entire result set
select #SQL
--uncomment the line below when you are satisfied the dynamic sql is correct
--exec sp_executesql #SQL
This is not the best way but it works
DECLARE #DatabaseIgnoreList AS VARCHAR(500);
SET #DatabaseIgnoreList = 'DatabaseNotToInclude';
SELECT name, database_id
into #temporaltable
FROM sys.databases
WHERE HAS_DBACCESS(name) = 1
AND name NOT IN ('msdb')
AND database_id > 4
AND name NOT LIKE '%$%'
AND name NOT IN (#DatabaseIgnoreList)
ORDER BY name ASC
declare
#target varchar(250),
#statement varchar(max)
declare #schemas as CURSOR;
set #schemas = CURSOR FOR
select name from #temporaltable;
open #schemas;
fetch next from #schemas INTO #target
while ##FETCH_STATUS = 0
begin
set #statement = '
use '+#target+'
SELECT TABLE_SCHEMA ,
TABLE_NAME ,
COLUMN_NAME ,
ORDINAL_POSITION ,
COLUMN_DEFAULT ,
DATA_TYPE ,
CHARACTER_MAXIMUM_LENGTH ,
NUMERIC_PRECISION ,
NUMERIC_PRECISION_RADIX ,
NUMERIC_SCALE ,
DATETIME_PRECISION,
TABLE_CATALOG
FROM INFORMATION_SCHEMA.COLUMNS'
EXEC (#statement)
fetch next from #schemas INTO #target
end
close #schemas;
deallocate #schemas
drop table #temporaltable

Set all integer columns in all tables to 0 where the value is currently null

I'm looking for a way in SQL Server to iteratively run the following query (or to achieve the same result):
UPDATE <table> SET <column> = 0 WHERE <column> IS NULL
I've used the following query to get all the columns of type 'int', but how can I achieve the above requirement?
SELECT table_name, column_name FROM information_schema.columns where data_type = 'int' and table_name not like 'v_%' and table_name not like 'sym_%'
This is reasonably simple with some dynamic sql. I would be EXTREMELY careful doing this on any system and would ask questions about why this is a good idea. I would never do this on my system but the code is actually fairly straight forward.
declare #SQL nvarchar(max) = ''
SELECT #SQL = #SQL + 'Update [' + TABLE_NAME + '] set [' + COLUMN_NAME + '] = 0 where [' + COLUMN_NAME + '] IS NULL;'
FROM information_schema.columns
where data_type = 'int'
and table_name not like 'v_%'
and table_name not like 'sym_%'
select #SQL
--exec sp_executesql #SQL

Associate Database Name with Table List

It is no problem to list all tables with schemas on a server
SELECT SCHEMA_NAME(schema_id), name FROM sys.tables
How can I determine which database the tables reside in ?
sys.tables exists in all databases so I am not following the fact that you don't know the db you are in. you can run DB_NAME(DB_ID()) to get the db name
SELECT DB_NAME(DB_ID()),SCHEMA_NAME(schema_id), name FROM sys.tables
but in this case DB_NAME(DB_ID()) will return the same value for every row
to do it for all database, you can do this
EXEC sp_msforeachdb 'use [?] SELECT ''?'',SCHEMA_NAME(schema_id), name
FROM sys.tables'
You can of course dump it into a table as well
CREATE TABLE #output (DatabaseName VARCHAR(1000),
SchemaName VARCHAR(1000),
TableName VARCHAR(1000))
INSERT #output
EXEC sp_msforeachdb 'use [?] SELECT ''?'',SCHEMA_NAME(schema_id), name
FROM sys.tables'
SELECT * FROM #output
Just as a FYI, the sp_msforeachdb proc is undocumented and you should not use it for production code, to quickly find something is fine, for production code roll your own version of this proc
See also Aaron Bertrand's posts here:
Making a more reliable and flexible sp_MSforeachdb
Execute a Command in the Context of Each Database in SQL Server
I ran into this problem when I was creating query that I wanted to be able to run against a different database on my server, and include the other database's name name without hard-coding it into the query.
The query essentially looked like this:
SELECT DB_NAME() db_name
, SCHEMA_NAME(schema_id) schema_name
, name table_name
FROM OtherDB.sys.tables --The OtherDB is to specify that I am running
--this for a different database than the one
--I'm logged in to for my current session.
The problem was that even though I specify OtherDB.sys.tables in the from clause, DB_NAME() always returned the current database I was in. Yes, I could put a USE OtherDB at the beginning, but it seemed like there should be another way. I looked through every sys view I could find, but could never find anything that would link sys.databases and sys.tables.
What I eventually found was SQL Server's INFORMATION_SCHEMA.TABLES This view includes the Database name as the first column (referred to as TABLE_CATAOLG).
SELECT TABLE_CATALOG
, TABLE_SCHEMA
, TABLE_NAME
, TABLE_TYPE
FROM INFORMATION_SCHEMA.TABLES
With these views, you can easily compare the tables in two databases:
SELECT a.TABLE_CATALOG
, a.TABLE_SCHEMA
, a.TABLE_NAME
, a.TABLE_TYPE
, b.TABLE_CATALOG
, b.TABLE_SCHEMA
, b.TABLE_NAME
, b.TABLE_TYPE
FROM OneDatabase.INFORMATION_SCHEMA.TABLES a
FULL OUTER JOIN TwoDatabase.INFORMATION_SCHEMA.TABLES b
ON a.TABLE_SCHEMA = b.TABLE_SCHEMA
AND a.TABLE_NAME = b.TABLE_NAME
If the databases are on separate servers that are linked you should be able to use this query by using all four parts of the Fully Qualified Table Name.
If your intention is just to include the current database name, why not just:
SELECT DB_NAME(), SCHEMA_NAME(schema_id), name FROM sys.tables;
If your intention is to pull all names from all databases, I personally prefer dynamic SQL like this instead of sp_msforeachdb:
DECLARE #sql NVARCHAR(MAX) = N'';
SELECT #sql += CHAR(13) + CHAR(10) + 'UNION ALL
SELECT ''' + name + ''', s.name, t.name
FROM ' + QUOTENAME(name) + '.sys.tables AS t
INNER JOIN ' + QUOTENAME(name) + '.sys.schemas AS s
ON t.schema_id = s.schema_id'
FROM sys.databases
WHERE database_id > 4;
SET #sql = STUFF(#sql, 1, 13, '');
PRINT #sql;
-- EXEC sp_executesql #sql;

sql select with column name like

I have a table with column names a1,a2...,b1.b2....
How can I select all those with column names like a%?
This will get you the list
select * from information_schema.columns
where table_name='table1' and column_name like 'a%'
If you want to use that to construct a query, you could do something like this:
declare #sql nvarchar(max)
set #sql = 'select '
select #sql = #sql + '[' + column_name +'],'
from information_schema.columns
where table_name='table1' and column_name like 'a%'
set #sql = left(#sql,len(#sql)-1) -- remove trailing comma
set #sql = #sql + ' from table1'
exec sp_executesql #sql
Note that the above is written for SQL Server.
You need to use view INFORMATION_SCHEMA.COLUMNS
select COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = my_table_name AND COLUMN_NAME like 'a%'
TO inline rows you can use PIVOT and for execution EXEC() function.
This will show you the table name and column name
select table_name,column_name from information_schema.columns
where column_name like '%breakfast%'
SELECT * FROM SysColumns WHERE Name like 'a%'
Will get you a list of columns, you will want to filter more to restrict it to your target table
From there you can construct some ad-hoc sql
Here is a nice way to display the information that you want:
SELECT B.table_catalog as 'Database_Name',
B.table_name as 'Table_Name',
stuff((select ', ' + A.column_name
from INFORMATION_SCHEMA.COLUMNS A
where A.Table_name = B.Table_Name
FOR XML PATH(''),TYPE).value('(./text())[1]','NVARCHAR(MAX)')
, 1, 2, '') as 'Columns'
FROM INFORMATION_SCHEMA.COLUMNS B
WHERE B.TABLE_NAME like '%%'
AND B.COLUMN_NAME like '%%'
GROUP BY B.Table_Catalog, B.Table_Name
Order by 1 asc
Add anything between either '%%' in the main select to narrow down what tables and/or column names you want.
You cannot with standard SQL. Column names are not treated like data in SQL.
If you use a SQL engine that has, say, meta-data tables storing column names, types, etc. you may select on that table instead.
Blorgbeard had a great answer for SQL server. If you have a MySQL server like mine then the following will allow you to select the information from columns where the name is like some key phrase. You just have to substitute the table name, database name, and keyword.
SET #columnnames = (SELECT concat("`",GROUP_CONCAT(`COLUMN_NAME` SEPARATOR "`, `"),"`")
FROM `INFORMATION_SCHEMA`.`COLUMNS`
WHERE `TABLE_SCHEMA`='your_database'
AND `TABLE_NAME`='your_table'
AND COLUMN_NAME LIKE "%keyword%");
SET #burrito = CONCAT("SELECT ",#columnnames," FROM your_table");
PREPARE result FROM #burrito;
EXECUTE result;
Thank you #Blorgbeard for the genious idea.
By the way Blorgbeard's query was not working for me so I edited it:
DECLARE #Table_Name as VARCHAR(50) SET #Table_Name = 'MyTable' -- put here you table name
DECLARE #Column_Like as VARCHAR(20) SET #Column_Like = '%something%' -- put here you element
DECLARE #sql NVARCHAR(MAX) SET #sql = 'select '
SELECT #sql = #sql + '[' + sys.columns.name + '],'
FROM sys.columns
JOIN sys.tables ON sys.columns.object_id = tables.object_id
WHERE sys.columns.name like #Column_Like
and sys.tables.name = #Table_Name
SET #sql = left(#sql,len(#sql)-1) -- remove trailing comma
SET #sql = #sql + ' from ' + #Table_Name
EXEC sp_executesql #sql