How to check which columns in my database hold data dynamically - sql-server

I am dealing with a problem that I need to make a sql query like this:
SELECT
SUM(CASE WHEN ID IS NOT NULL THEN 0 ELSE 1 END) AS column_ID_count,
SUM(CASE WHEN NAME IS NOT NULL THEN 0 ELSE 1 END) AS column_NAME_count,
SUM(CASE WHEN COMMENT IS NOT NULL THEN 1 ELSE 0 END) AS column_COMMENT_count
FROM
Table1
The problem is that I have more than 100 columns so making this query by hand will be a real pain. So I was thinking that there should be a way to select all column names and dump them to text file. The output would look like:
SUM(CASE WHEN NAME IS NOT NULL THEN 0 ELSE 1 END) AS column_NAME_count,
...
SUM(CASE WHEN COMMENT IS NOT NULL THEN 1 ELSE 0 END) AS column_COMMENT_count
I tried exec sp_help but that is not what I need. So is there a way to do this with a query?

This will give you column names for the table in question.
SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'yourtablename'

If you want a list of all column names in your table then you want something like this;
DECLARE #TableName varchar(50); SET #TableName = 'TableName'
SELECT c.name
INTO #ColumnNames
FROM sys.columns c
JOIN sys.objects o
ON c.object_id = o.object_id
WHERE o.name = #TableName
SELECT * FROM #ColumnNames
Drop the results to a text file if that's what you want and you're done.
If you want a script to return all columns in your database and whether they contain data, you could use this;
SELECT 'SELECT count([' + c.name + ']) as Data_Count, ''' + o.name + '.' + c.name + ''' AS Table_Column FROM [' + o.name + '] UNION ALL '
FROM sys.columns c
JOIN sys.objects o
ON c.object_id = o.object_id
WHERE c.is_nullable = 1
AND o.type = 'U'
And paste the results into a new window. You'll have to remove the final UNION ALL and this won't work with text or ntext data types so if you have some of these you'll have to remove them. You could filter them out in the query but then you'd never know about them.
Edit: If you want to exclude the incompatible data types then use this query;
SELECT 'SELECT count([' + c.name + ']) as Data_Count, ''' + o.name + '.' + c.name + ''' AS Table_Column FROM [' + o.name + '] UNION ALL '
FROM sys.columns c
JOIN sys.objects o
ON c.object_id = o.object_id
JOIN sys.types t
ON c.user_type_id = t.user_type_id
WHERE c.is_nullable = 1
AND o.type = 'U'
AND t.name NOT IN ('image','text','ntext')
Just remember to check these data types with a different query so you don't miss them.

try this query
declare #cnmae nvarchar(max)='select '
SELECT #cnmae+= 'sum( case when ' + COLUMN_NAME +
' is not null then 0 else 1 end) as column_'+COLUMN_NAME+'_count,'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'Table1'
select #cnmae=stuff(#cnmae,len(#cnmae),1,'') + ' from Table1'
exec sp_executesql #cnmae

Related

SQL Server Query to get Data from a Table where each row is a Table

I have a schema where I have multiple tables some with time and some without it. So I created a query where I have listed 3 tables say which has time like this :
WITH CTE AS
(
SELECT
CONCAT(schema_name(t.schema_id), '.', t.name) AS table_name,
c.name AS 'time'
FROM
sys.tables t
INNER JOIN
sys.columns c ON c.object_id = t.object_id
WHERE
schema_name(t.schema_id) = 'Prod'
AND c.name = 'mytime'
)
SELECT * FROM CTE
Now my output looks like ( I am showing 3 rows for the example):
Table O
table_name time
--------------------------
Prod.tableA mytime
Prod.tableB mytime
Prod.tableC mytime
So usually what I want is to get the max(mytime) from each Table/Schema combination . So for a single table I can do
SELECT MAX(mytime)
FROM Prod.tableA
However in this case I want to generate this from table O for each table and my output should look like:
Table F
table_name mymax(time)
--------------------------------------------
Prod.tableA max(mytime) from Prod.tableA
Prod.tableB max(mytime) from Prod.tableA
Prod.tableC max(mytime) from Prod.tableA
How to achieve this using another select/variable declaration etc? Any help or ideas will be extremely appreciated. Thanks in anticipation.
Can this help? You still have a bit of work, check if the output is what you like and then uncomment the exec.
DECLARE #SchemaName NVARCHAR(100) = 'foo',
#ColumnName NVARCHAR(100) = 'bar',
#sql NVARCHAR(max)
SELECT #SchemaName + '.'+ t.name AS [Schema.Table],'( SELECT MAX(' + #ColumnName + ') FROM ['+ #SchemaName +'].['+t.name+']) ' AS MaxValue
FROM sys.tables t
JOIN sys.schemas s ON t.schema_id = s.schema_id
WHERE s.name = #SchemaName
-------
SELECT #sql =
STUFF((
SELECT 'UNION ALL ' + 'SELECT ' + '''' + '[' + ISNULL(#SchemaName,'') + '].['+ t.name + ']' + '''' + ' AS [Schema.Table] ,( SELECT MAX(' + #ColumnName + ') FROM ['+ #SchemaName +'].['+t.name+']) AS Max' + #ColumnName + ' '
FROM sys.tables t
JOIN sys.schemas s ON t.schema_id = s.schema_id
WHERE s.name = #SchemaName
for xml path('')
),1,10,'')
PRINT #sql
--EXEC(#sql)

How to find matching columns in multiple tables in a SQL Server database?

How to find matching columns in multiple tables in a SQL Server database?
I have a SQL Server database with over 30 tables, is there a way to filter and/or produce a list of the common columns amongst the tables rather than going through each manually?
Maybe some code?
As explained in the comments, you want to use system table sys.columns to achieve your goal.
This query lists all column names that are present more than once in the database, along with the number of occurences :
SELECT name, COUNT(*)
FROM sys.columns
GROUP BY name
HAVING COUNT(*) > 1
You can join the results with sys.tables to recover the corresponding tables, like :
SELECT
C.name AS ColumnName,
T.name AS TableName
FROM
(SELECT name FROM sys.columns GROUP BY name HAVING COUNT(*) > 1 ) A
JOIN sys.columns C on C.name = A.name
JOIN sys.tables T ON T.object_id = C.object_id
ORDER BY
C.name,
T.name
I'd use something easy like this:
SELECT [Unique name #] = DENSE_RANK() OVER(ORDER BY c.name)
, [Column] = c.name
, [Column type] = t.name
, [Column max length] = c.max_length
, [Column precision] = c.precision
, [Table schema] = OBJECT_SCHEMA_NAME(c.object_id)
, [Table name] = OBJECT_NAME(c.object_id)
FROM sys.columns as c
INNER JOIN sys.systypes as t ON t.type = c.system_type_id
WHERE OBJECTPROPERTY(c.object_id,'IsTable') = 1
and OBJECT_SCHEMA_NAME(c.object_id) != 'sys'
ORDER BY c.name;
With this query you have all the columns with same name in different tables of your DB:
select object_name(c.id) + '.' + c.name + ' '
+ t.name
+ case when t.xtype = t.xusertype then '' else '[' + tr.name end
+ case
when tr.name in ('bit', 'tinyint', 'smallint', 'int', 'bigint',
'float', 'money', 'smallmoney', 'real', 'date', 'time',
'datetime', 'datetime2', 'smalldatetime', 'timestamp')
then ''
else
case when isNull(c.prec,0)=0 then ''
else '('
+ case when c.prec = - 1 then 'MAX' else cast(c.prec as varchar) end
+ case when c.scale is null then '' else ',' + cast(c.scale as varchar) end
+ ')'
end
end
+ case when t.xtype = t.xusertype then '' else ']' end
+ case when t.collationId <> c.collationId
then ' collate ' + c.collation collate Latin1_General_BIN else '' end
+ case c.isnullable when 0 then ' not null' else '' end
+ case c.colstat
when 1 then ' identity(' + Cast(Ident_seed(o.name) as varchar)
+ ',' + cast(Ident_incr(o.name) as varchar) + ')'
else ''
end
+ case when cm.text is null then ''
else ' default '
+ case when patindex('% as %', cm.text) > 0
then rtrim(substring(cm.text, patindex('% as %', cm.text) + 4, len(cm.text)))
else substring(cm.text, 2, len(cm.text) - 2)
end
end
as Columns
from syscolumns c
join systypes t on (t.xusertype = c.xusertype)
left join systypes tr
on (tr.xtype = t.xtype and tr.xusertype = t.xtype)
join sysobjects o
on (o.id = c.id)
left join syscomments cm
on (cm.id = c.cdefault)
where c.name in (
select cl.name
from syscolumns cl
join sysobjects ob on (cl.id = ob.id and ob.xtype = 'U')
group by cl.name
having count(*) > 1
)
order by c.name
this will work:
select COLUMN_NAME from ALL_TAB_COLS where TABLE_NAME = 'table1name'
intersect
select COLUMN_NAME from ALL_TAB_COLS where TABLE_NAME = 'table2name';
intersect
...
...
..
...
select COLUMN_NAME from ALL_TAB_COLS where TABLE_NAME = 'table30name';
sql server equivalent:
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'table1'
intersect
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'table2'
intersect
.....
....
...
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'table30';
Below is the query which will provide you the list of all tables where your "Column" is present.
SELECT c.name AS ColName, t.name AS TableName FROM sys.columns c
JOIN sys.tables t ON c.object_id = t.object_id WHERE c.name LIKE '%ColumnName%';
And based on that you can continue you task you want to perform.
Thumbs up if it is helpful.
select name as 'Column_Name' from syscolumns s1 where id = object_id('table1') and
exists(select 1 from syscolumns s2 where s2.name = s1.name and s2.id = object_id('table2'))
it will return the matched columns

SQL Server - is there option to generate insert script just to not null columns (required columns)?

I have a big table and for tests I would like to generate a script from SQL Server just for these columns. I think there isn't this option... just a full script and I'll need to remove each one.
Just to confirm.
Thanks! who knows.
You can set up the statement querying the system tables - probably more trouble than it's worth, but still doable:
DECLARE #tablename VARCHAR(255) = 'UnprocessedQueueData';
WITH columns
AS ( SELECT STUFF(( SELECT ',' + c.name
FROM sys.columns c
INNER JOIN sys.tables t ON t.object_id = c.object_id
WHERE t.name = #tablename
AND c.is_nullable = 0
AND c.is_identity = 0
ORDER BY c.name
FOR
XML PATH('')
), 1, 1, '') col
)
SELECT 'INSERT INTO ' + t.name + ' ( ' + columns.col
+ ' ) SELECT * FROM OtherTable;'
FROM sys.tables t
CROSS JOIN columns
WHERE t.name = #tablename

Generate **bare** CREATE TABLE and CREATE PROC statemnts in SQL Server

The deployment procedures in my company require that SQL scripts for creation of procedures and tables, etc. be bare.
Generating create scripts in SQL Server Management Studio gives you significantly more than a bare script, which is unfortunate in this case. For example, for a test table this is what SSMS generated for me:
USE [DemoDB]
GO
/****** Object: Table [dbo].[example] Script Date: 08/07/2012 15:46:32 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[example](
[fake_row] [int] NULL
) ON [PRIMARY]
GO
So, what I'd like to know is:
Can I somehow run a query on SQL Server in SSMS that would give me a script that was literally just the following?
create table example (
fake_row int
)
You can create your own "create table" statements, using information_schema (Aaron . . . I know, INFORMATION_SCHEMA ;).
I have written some code for this purpose, but it doesn't use INFORMATION_SCHEMA. I know, if uses older system tables that are probably scheduled to be removed. It also adds in some additional information (which you can remove, since you don't need it). Just put the list of tables in the #INCLUSIONLIST and run this in the database where the tables reside.
SET #INCLUSIONLIST = '|table1|table2|';
SELECT (CASE WHEN rownum = 1 THEN 'CREATE TABLE ['+a.t_name+'] ('
WHEN c.column_id IS NOT NULL
THEN ' ['+c.c_name+'] ' +
(CASE WHEN CHARINDEX('CHAR', datatype) > 0 THEN datatype+'('+(case when length < 0 then 'max' else cast(length as varchar) end)+')'
WHEN CHARINDEX('BINARY', datatype) > 0 THEN datatype+'('+cast(length as varchar)+')'
WHEN datatype = 'float' AND precision <> 24 THEN datatype+'('+cast(precision as varchar)+')'
WHEN datatype IN ('numeric', 'decimal') AND scale = 0 THEN datatype+'('+cast(precision as varchar)+')'
WHEN datatype IN ('numeric', 'decimal') AND scale > 0 THEN datatype+'('+cast(precision as varchar)+','+cast(scale as varchar)+')'
ELSE datatype END)+' '+
(CASE WHEN c.identity_seed IS NOT NULL
THEN 'IDENTITY(' + CAST(identity_seed AS VARCHAR) + ',' + CAST(identity_increment AS VARCHAR) + ') '
ELSE '' END) +
(CASE WHEN c.is_nullable = 0 THEN 'NOT NULL ' ELSE '' END) +
(CASE WHEN c.default_definition IS NOT NULL
THEN 'DEFAULT '+default_definition ELSE '' END) +
(CASE WHEN max_column_id = column_id AND pk.pk_name IS NULL THEN '' ELSE ',' END)
WHEN rownum = max_column_id + 2 and pk.pk_name IS NOT NULL
THEN ' PRIMARY KEY ('+pk.pk_columns+')'
WHEN rownum = max_column_id + 3 THEN ') /* CREATE TABLE '+a.t_name+' */'
WHEN rownum = max_column_id + 4 THEN 'GO'
WHEN rownum = max_column_id + 5 THEN ''
END)
FROM (SELECT t.t_name, rownum, max_column_id
FROM (SELECT t.name as t_name, MAX(c.column_id) as max_column_id
FROM sys.columns c join
(SELECT * FROM sys.tables WHERE CHARINDEX('|'+name+'|', #INCLUSIONLIST) > 0 ) t
ON c.object_id = t.object_id
GROUP BY t.name) t join
(SELECT ROW_NUMBER() OVER (ORDER BY object_id) as rownum FROM sys.columns c) ctr
ON ctr.rownum <= t.max_column_id + 5
) a LEFT OUTER JOIN
(SELECT t.name as t_name, c.column_id, c.name AS c_name, u.name as datatype,
ISNULL(baset.name, N'') AS systemtype,
CAST(CASE WHEN baset.name IN (N'nchar', N'nvarchar') AND c.max_length <> -1
THEN c.max_length/2 ELSE c.max_length END AS INT) AS length,
c.precision AS precision,
c.scale as scale,
c.is_nullable,
dc.definition as default_definition,
idc.seed_value as identity_seed, idc.increment_value as identity_increment
FROM sys.tables t JOIN
sys.all_columns AS c
ON c.object_id = t.object_id LEFT OUTER JOIN
sys.types u
ON u.user_type_id = c.user_type_id LEFT OUTER JOIN
sys.types baset
ON baset.user_type_id = c.system_type_id AND
baset.user_type_id = baset.system_type_id LEFT OUTER JOIN
sys.default_constraints dc
ON c.object_id = dc.parent_object_id AND
c.column_id = dc.parent_column_id LEFT OUTER JOIN
sys.identity_columns idc
ON c.object_id = idc.object_id AND
c.column_id = idc.column_id
) c
ON a.t_name = c.t_name AND
c.column_id + 1 = a.rownum LEFT OUTER JOIN
(SELECT t.name as t_name, kc.name as pk_name,
(MAX(CASE WHEN index_column_id = 1 THEN '['+c.name+']' ELSE '' END) +
MAX(CASE WHEN index_column_id = 2 THEN ','+'['+c.name+']' ELSE '' END) +
MAX(CASE WHEN index_column_id = 3 THEN ','+'['+c.name+']' ELSE '' END) +
MAX(CASE WHEN index_column_id = 4 THEN ','+'['+c.name+']' ELSE '' END) +
MAX(CASE WHEN index_column_id = 5 THEN ','+'['+c.name+']' ELSE '' END) +
MAX(CASE WHEN index_column_id = 6 THEN ','+'['+c.name+']' ELSE '' END) +
MAX(CASE WHEN index_column_id = 7 THEN ','+'['+c.name+']' ELSE '' END) +
MAX(CASE WHEN index_column_id = 8 THEN ','+'['+c.name+']' ELSE '' END) +
MAX(CASE WHEN index_column_id = 9 THEN ','+'['+c.name+']' ELSE '' END) +
MAX(CASE WHEN index_column_id = 10 THEN ','+'['+c.name+']' ELSE '' END)
) as pk_columns
FROM sys.indexes i JOIN
sys.key_constraints kc
ON i.name = kc.name AND
kc.type = 'PK' JOIN
sys.tables t
ON i.object_id = t.object_id JOIN
sys.index_columns ic
ON i.object_id = ic.object_id AND
i.index_id = ic.index_id JOIN
sys.columns c
ON ic.index_column_id = c.column_id AND
ic.object_id = c.object_id
GROUP BY t.name, kc.name
) pk
ON pk.t_name = a.t_name
ORDER BY a.t_name, rownum
Apologies for the self-answer, marking other good answers +1.
It turns out you can get pretty much all of the way there with utility in SSMS.
Right click on the database in the object explorer
Click "Tasks"
Click "Generate Scripts"
Select "Script Specific Objects" and choose tables, or whatever else
Select "Save To File" & "Single File Per Object" (or just spool to query window)
Click "Advanced" and you can enable/disable the generation of virtually every part of the statements you're generating including constraints, use statements, etc.
If further removal is required (e.g. removing GO), it's minimal
Optionally, you can control the general scripting behavior of SSMS like so: Options for scripting SQL Server database objects.
I would create stored procs that read from the INFORMATION_SCHEMA views.
Getting the stored proc text is just:
DECLARE #SQL VARCHAR(8000)
SET #SQL=' '
select #SQL = #SQL + ROUTINE_DEFINITION
from INFORMATION_SCHEMA.ROUTINES
where ROUTINE_TYPE='PROCEDURE'
AND SPECIFIC_NAME = 'updateComments'
PRINT #SQL
The one to script the table would looks something like:
DECLARE #tableName VARCHAR(50)
SET #tableName = 'Location'
-- Need to know how many columns
DECLARE #NumColumns int
SELECT #NumColumns = MAX(ORDINAL_POSITION)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #tableName
DECLARE #SQL VARCHAR(8000)
SET #SQL=' '
DECLARE #Results TABLE
(LineNumber int,
Line VARCHAR(1000))
INSERT INTO #Results
SELECT 0 AS ORDINAL_POSITION,
'CREATE TABLE '+TABLE_SCHEMA+'.'+#tableName+' (' AS Line
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = #tableName
UNION ALL
SELECT ORDINAL_POSITION,
'['+COLUMN_NAME+'] '+ DATA_TYPE +
CASE WHEN DATA_TYPE = 'varchar' OR DATA_TYPE = 'char'
THEN '('+ CAST(CHARACTER_MAXIMUM_LENGTH AS VARCHAR) +')'
ELSE '' END +
CASE WHEN IS_NULLABLE = 'NO'
THEN ' NULL '
ELSE ' NOT NULL' END +
CASE WHEN ORDINAL_POSITION < #NumColumns
THEN ', '
ELSE ' ' END
AS LINE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #tableName
UNION ALL
SELECT 999, ' )'
SELECT Line
FROM #Results
ORDER BY LineNumber
SELECT #SQL = #SQL + Line
FROM #Results
ORDER BY LineNumber
SELECT #SQL
PRINT #SQL
This creates the simple table script that you want, but it is not complete - doesn't do numeric precision, primary key, etc. But this is enough to get you started.
I would just make each one of these into a stored proc that takes the object name as a parameter.

How Can I Find All Columns That Contain A String and Null Those Values

My goal is to write a SQL Server script (2008 R2 if it matters) that nulls out all values in all tables where the column name contains "Qualifiers".
E.g. Table A contains columns named "TemperatureQualifiers" and "SalinityQualifiers". For all rows in that table, those values should be set to null. There are also several other tables that have columns with similar names.
This will generate the update statements for you. You can extend this to execute them as dynamic SQL or simply cut/paste the results to another SSMS query window and run them.
select 'update [' + s.name + '].[' + t.name + '] set [' + c.name + '] = NULL'
from sys.columns c
inner join sys.tables t
on c.object_id = t.object_id
inner join sys.schemas s
on t.schema_id = s.schema_id
where c.name like '%Qualifiers%'
and t.type = 'U'
Bit late on this one. This will generate a script that consolidates updates where there are multiple columns in the same table to be updated.
DECLARE #Script nvarchar(MAX);
SET #Script = '';
WITH Cols AS
( SELECT c.object_id,
c.name,
schema_name(t.schema_id) AS SchemaName,
t.name AS TableName
FROM sys.columns c INNER JOIN
sys.tables t ON c.object_id = t.object_id
WHERE c.name LIKE '%Qualifiers%'
AND is_computed=0
AND is_rowguidcol=0
AND is_identity=0
AND is_nullable=1
AND objectproperty(c.object_id, N'IsUserTable')=1
)
,
Tables AS
( SELECT DISTINCT object_id, TableName, SchemaName
FROM Cols
)
,
Statements AS
( SELECT 'UPDATE ' + QUOTENAME(SchemaName) + '.' + QUOTENAME(TableName) + ' SET ' + STUFF(
( SELECT ',' + c.name + '=NULL'
FROM Cols c
WHERE c.object_id = t.object_id FOR XML PATH('')
)
, 1, 1, '') AS Statement
FROM Tables t
)
SELECT #Script = #Script + '
' +Statement
FROM Statements
SELECT #Script AS [processing-instruction(x)] FOR XML PATH('')

Resources