Get all not NULL column names from a SQL Server table - sql

I have a table with following columns: F1, F2, ...F10
Some of these columns contain only NULLS, let's say they are F2 and F7.
How can I get a string with the names of these columns, I would like to get 'F2,F7' as a return value.
This is a temporary table and column names and the number of columns is unknown. I need some very generic function to extract the column names containing NULLs
NOTE:
I know it is fairy easy in Oracle using some system objects (i.e. all_tab_columns, etc), not sure if possible in SQL Server as well.
Thank you.

To list all non-nullable columns in the 'dbo.Employee' Table in the database, run the following query:
SELECT TABLE_CATALOG AS Database_Name, TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, IS_NULLABLE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'dbo'
AND TABLE_NAME = 'Employee'
AND IS_NULLABLE = 'NO'

Not sure why you need this but something like this should help you
Select CASE WHEN Len(res) > 0 THEN LEFT(res, Len(res) - 1) ELSE '' END AS result
From
(
select case when Count(F1)= 0 then 'F1,' else '' End +
case when Count(F2)= 0 then 'F2,' else '' End +
case when Count(F3)= 0 then 'F3,' else '' End +
.....
case when Count(F10)= 0 then 'F10,' else '' End
End as res
From yourtable
) A
Here is dynamic approach that works for unknown column names
DECLARE #sql VARCHAR(max) =''
SET #sql = ' Select CASE WHEN Len(res) > 0 THEN LEFT(res, Len(res) - 1) ELSE '''' END AS result
From
(
select'
SET #sql += (SELECT ' case when Count(' + COLUMN_NAME + ')= 0 then ''' + COLUMN_NAME + ','' else '''' End+'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = 'TableA'
FOR xml path (''))
SET #sql = LEFT(#sql, Len(#sql) - 1)
SET #sql += ' From yourtable ) A (res)'
--SELECT #sql
EXEC (#sql)

SELECT t.name, c.name, c.is_nullable
FROM sys.tables t
JOIN sys.columns c on t.object_id = c.object_id
WHERE t.name = 'YourTableNameHere'
AND c.is_nullable = 0
If you are on MS SQL Server and trying to avoid INFORMATION_SCHEMA.

Related

Dynamic union of table if a certain field exists

I'm trying to build a dynamic union over tables that have certain fields (in my example field1 and field2). The union already works but over any table. Now I need to include only the ones that have field1 and field2.
DECLARE #SQL VARCHAR(max)
SET #SQL = ''
SELECT #SQL = #SQL + CASE Len(#SQL) WHEN 0 THEN '' ELSE ' UNION ALL ' END
+ ' SELECT [field1], [field2] FROM dbo.['
+ NAME + ']'
FROM sys.tables
WHERE NAME LIKE 'CUST_TABLE%'
EXEC (#SQL)
I guess I need to combine this query somehow:
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME like 'CUST_TABLE%'
and COLUMN_NAME='field1'
You are close. Query the view INFORMATION_SCHEMA.COLUMNS. Aggregate per table name and make sure both columns exist for the table by counting them in the HAVING clause.
DECLARE #SQL VARCHAR(max)
SET #SQL = ''
SELECT #SQL = #SQL + CASE Len(#SQL) WHEN 0 THEN '' ELSE ' UNION ALL ' END
+ ' SELECT [field1], [field2] FROM dbo.[' + table_name + ']'
FROM information_schema.columns
WHERE table_name LIKE 'CUST_TABLE%'
GROUP BY table_name
HAVING COUNT(CASE WHEN COLUMN_NAME = 'FIELD1' THEN 1 END) > 0
AND COUNT(CASE WHEN COLUMN_NAME = 'FIELD2' THEN 1 END) > 0
EXEC (#SQL)

Ambiguous column name when select a column to return value if column is available in table by Execute Dynamic SQL commands

I want to return a column value if column is available in table,if not, return a default value, then I face COLUMN_NAME ambiguous error when join two table SHAIN1 and RIREKI14. If select from only one table then query works ok but if I join two table, I face problem.
declare #sql nvarchar(max) = ' SELECT 1 as id, '+ (case when exists (SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA ='dbo' and TABLE_NAME='RIREKI14' and COLUMN_NAME='KOM001') then 'KOM001' else 'NULL' end) + ' as day ' + ' From RIREKI14 join SHAIN1 on RIREKI14.INCODE = SHAIN1.INCODE '; exec sp_executesql #sql
Help me please!
This is your logic:
declare #sql nvarchar(max) = '
SELECT 1 as id, '+
(case when exists (SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'dbo' and TABLE_NAME = 'RIREKI14' and COLUMN_NAME = 'KOM001')
then 'KOM001'
else 'NULL'
end) + ' as day ' + '
From RIREKI14 join
SHAIN1
on RIREKI14.INCODE = SHAIN1.INCODE
';
exec sp_executesql #sql;
The only possibility for an ambiguous column name is the name coming from the case. So, let's qualify it:
declare #sql nvarchar(max) = '
SELECT 1 as id, '+
(case when exists (SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'dbo' and TABLE_NAME = 'RIREKI14' and COLUMN_NAME = 'KOM001')
then 'r.KOM001'
else 'NULL'
end) + ' as day ' + '
From RIREKI14 r join
SHAIN1 s
on r.INCODE = s.INCODE
';
exec sp_executesql #sql;

Replace NULL with empty string in SQL for ALL columns

These questions (one, two, three) all identified how to return an empty string instead of NULL for a single column:
SELECT ISNULL(ColA,'') AS ColA FROM Table1
However, I have a query that returns a whole bunch of columns that I'm too lazy to select individually (don't worry - this isn't a production query)
SELECT * FROM Table1
Is there a way to return an empty string for all columns returned by the wildcard operator?
For Example, the following naive attempt won't work:
SELECT ISNull(*,'') FROM Table1
Maybe you can use this to generate a SQL query string in order to execute it dynamically, check if this works for you:
;WITH cte AS (
SELECT 'ISNULL(' + COLUMN_NAME + ',' +
CASE
WHEN DATA_TYPE = 'bit' THEN '0'
WHEN DATA_TYPE = 'int' THEN '0'
WHEN DATA_TYPE = 'decimal' THEN '0'
WHEN DATA_TYPE = 'date' THEN '''1/1/1900'''
WHEN DATA_TYPE = 'datetime' THEN '''1/1/1900'''
WHEN DATA_TYPE = 'uniqueidentifier' THEN '00000000-0000-0000-0000-000000000000'
ELSE ''''''
END + ') AS ' + COLUMN_NAME AS columnNameIsNull
FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'TableName'
)
SELECT
stuff((
SELECT ( ', ' + columnNameIsNull )
FROM cte
FOR XML PATH( '' )
), 1, 1, '' ) AS string
Why write complicated dynamic SQL queries if you can just use Column Select (ALT+Click+drag) to perform a multiline select in your query editor?
This way, you can type ISNULL(... once for all your columns. Just make sure the columns are aligned and you should be good to go. Supported as of SQL Server Management Studio 2012. Otherwise just use Notepad++.
This code will generate the SQL needed to replace all blank values with NULL values in ALL columns of a schema.table
Just copy the output into a new Query window and run.
DECLARE #TableName nvarchar(100) = N'YourTableName'
DECLARE #SchemaName nvarchar(100) = N'YourSchemaName'
SELECT 'UPDATE ' + #SchemaName + '.' + #TableName + ' SET ' + COLUMN_NAME + ' = NULL WHERE ' + COLUMN_NAME + ' = ''''' AS UpdateSQL
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #TableName

select columns with value NA

How to select columns in a table that only contain a specific value for all the rows? I am trying to find these columns to do an update on those values with a NULL value. In my columns I have varied range of values including NA
I am using SQL Server 2012.
I've tried doing: thsi only gives me column names. Can i add to this condition for columns with value 'NA'?
SELECT COLUMN_NAME AS NAMES,COLUMN_DEFAULT
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'dbo'
AND TABLE_NAME = 'ABC'
I am a beginner in SQL. Trying to figure out how to do this.
If min of column equals to max then that column contains same values:
Select
case when min(col1) = max(col1) then 1 else 0 end as Col1IsSame,
case when min(col2) = max(col2) then 1 else 0 end as Col2IsSame,
...
from Table
With dynamic query:
declare #s nvarchar(max) = 'select '
select #s = #s + 'case when min(' + COLUMN_NAME + ') = max(' +
COLUMN_NAME + ') then 1 else 0 end as ' + COLUMN_NAME + ','
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'dbo'
AND TABLE_NAME = 'Table'
Set #s = substring(#s, 1, len(#s) - 1) + ' from Table'
exec(#s)
TRY THIS QUERY
DECLARE #SQLQUERY NVARCHAR(MAX)
declare #tableName varchar(50)
DECLARE #NAME VARCHAR(50)
Declare #ParamDefinition AS NVarchar(2000)
Set #ParamDefinition = '#OIM VARCHAR(20)'
SELECT NAME
FROM sys.objects
WHERE [object_id]=#OIM
set #tableName= (SELECT NAME
FROM sys.objects
WHERE [object_id]=#OIM)
SET #NAME=(SELECT C.NAME
FROM sys.columns c
JOIN
sys.tables t ON c.object_id = t.object_id
WHERE c.name in (select distinct name
from sys.columns
where object_id=#OIM))
SET #SQLQUERY = ''
SELECT #SQLQUERY = #SQLQUERY + 'UPDATE ' + #tableName + ' SET ' + #NAME + ' = NULL WHERE ' + #NAME + ' = NA ; '
PRINT #SQLQUERY
Execute sp_Executesql #SQLQUERY , #ParamDefinition, #OIM
end

sql server conditionals

I am getting an error when I run this query because the data type money can't be implicitly converted to a varchar. However, I am using an if statemnt to make sure the data type is not money before I try the conversion. Clearly, the conversion is being executed anyways. Anyone know why?
table: BBH_NEW col: rebate2
datatype: money
if 'money'= 'money'
begin
if (select max([rebate2]) from [BBH_NEW]) = 0
and (select min([rebate2]) from [BBH_NEW]) = 0
print ' rebate2 '
print ' 1 '
end
if 'money'!= 'money'
begin
IF NOT EXISTS (SELECT top 1 * FROM [BBH_NEW] WHERE [rebate2] IS NOT NULL and
len([rebate2]) > 0 )
BEGIN
print ' rebate2 '
end
end
Error:
Msg 257, Level 16, State 3, Line 11
Implicit conversion from data type money to varchar is not allowed. Use the CONVERT function to run this query.
yes this code was generated. If it helps, this is the code which was used to produce it:
select #temp =
data_type FROM information_schema.columns
WHERE table_schema = 'dbo'
AND table_name = #tblname
AND column_name = #col
SELECT #hold =
'if '''+#temp+'''= ''money''
begin
if (select max(['+#col+']) from ['+#tblname+']) = 0
and (select min(['+#col+']) from ['+#tblname+']) = 0
print '' '+#col+' money''
end
if '''+#temp+'''!= ''money''
begin
IF NOT EXISTS (SELECT max([' + #col + ']) FROM ['+ #tblname + ']
WHERE len( [' + #col + ']) > 0 )
BEGIN
print '' ' + #col + ' ''
end
end'
As I understand it the column BBH_NEW.rebate2 is of type money when you get the error. In T-SQL you can't have a query that doesn't compile, and that is what you are encountering. Even though the query in the always-false if block won't run, it doesn't compile because the data types don't match.
First, a quick solution for you - use CONVERT or CAST to explicitly change the data type.
if 'money'!= 'money'
begin
IF NOT EXISTS (SELECT top 1 * FROM [BBH_NEW] WHERE [rebate2] IS NOT NULL and
len(CONVERT(VARCHAR(8000), [rebate2])) > 0 )
BEGIN
print ' rebate2 '
end
end
But, there has to be a better way to do whatever you are doing... When does that SQL get generated? If it is at runtime, can you just not generate the part that won't run? Maybe something like this?
SELECT #hold = CASE WHEN #temp = 'money' THEN
'if (select max(['+#col+']) from ['+#tblname+']) = 0
and (select min(['+#col+']) from ['+#tblname+']) = 0
print '' '+#col+' money'''
ELSE
'IF NOT EXISTS (SELECT max([' + #col + ']) FROM ['+ #tblname + ']
WHERE len( [' + #col + ']) > 0 )
BEGIN
print '' ' + #col + ' ''
end'
END
or maybe change the generation to this...
SELECT #temp = DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'dbo'
AND TABLE_NAME = #tblname
AND COLUMN_NAME = #col
IF(#temp = 'money')
SELECT #hold = 'IF(EXISTS(
SELECT 1
FROM ['+#tblname+']
HAVING MAX(['+#col+']) = 0
AND MIN(['+#col+']) = 0))
BEGIN
PRINT '' '+#col+' ''
END';
ELSE
SELECT #hold = 'IF(NOT EXISTS(
SELECT *
FROM ['+#tblname+']
WHERE ['+#col+'] IS NOT NULL
AND LEN(['+#col+']) > 0))
BEGIN
PRINT '' '+#col+' ''
END';
Some hints to optimize the generator
Rewrite
SELECT #hold =
'if '''+#temp+'''= ''money''
begin
...
end
as
if #temp = 'money'
begin
...
end
Second, I cannot think of a case when
[rebate2] IS NOT NULL
does not imply
len(CONVERT(VARCHAR(8000), [rebate2])) > 0
in other words, as soon as rebate2 is not NULL, its string length is greater 0