Get table's column names which are always null - sql

I have a table with a lot of columns. Some of them are always NULL and does not contain any value.
Is there a way to list those columns using a SQL query instead testing them one by one ?
I'd like to avoid :
SELECT Col1 from MyTable where Col1 IS NOT NULL
SELECT Col2 from MyTable where Col2 IS NOT NULL
...

Assuming you are using Sql-Server, just assign your table name to #strTablename
In this example i assumed that dbo.MyTable is the table name
DECLARE #strTablename varchar(100) = 'dbo.MyTable'
DECLARE #strQuery varchar(max) = ''
DECLARE #strUnPivot as varchar(max) = ' UNPIVOT ([Count] for [Column] IN ('
CREATE TABLE ##tblTemp([Column] varchar(50), [Count] Int)
SELECT #strQuery = ISNULL(#strQuery,'') + 'Count([' + name + ']) as [' + name + '] ,' from sys.columns where object_id = object_id(#strTablename) and is_nullable = 1
SELECT #strUnPivot = ISNULL(#strUnPivot,'') + '[' + name + '] ,' from sys.columns where object_id = object_id(#strTablename) and is_nullable = 1
SET #strQuery = 'SELECT [Column],[Count] FROM ( SELECT ' + SUBSTRING(#strQuery,1,LEN(#strQuery) - 1) + ' FROM ' + #strTablename + ') AS p ' + SUBSTRING(#strUnPivot,1,LEN(#strUnPivot) - 1) + ')) AS unpvt '
INSERT INTO ##tblTemp EXEC (#strQuery)
SELECT [Column] from ##tblTemp Where [Count] =0
DROP TABLE ##tblTemp

MAX(col) is null only when all rows are null for this column. So check this for every column and concatenate those names for which the expression is null.
select
'null columns: ' ||
case when max(col1) is null then 'col1 ' else '' end ||
case when max(col2) is null then 'col2 ' else '' end ||
case when max(col3) is null then 'col3 ' else '' end ||
case when max(col4) is null then 'col4 ' else '' end ||
...
from mytable;

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)

How to check a condition against all the columns of a table?

I have a table which has more than 30 columns(all are varchar). I need to list out all the columns which contains blank i.e.' ' values.
I tried using 'coalesce' but it is only for NULL.
The following query will give you all the columns in a table that might have null or '' values.
It is written so that you can run it for all tables in your database but you can limit it to a single table, as I have done for this specific example, checking a table called testingNulls:
--two variables needed for table name and column name, when looping through all tables
declare #table varchar(255), #col varchar(255), #sql varchar(max)
--this will be used to store the result, to have one result set instead of one row per each cursor cycle
if object_id('tempdb..#nullcolumns') is not null drop table #nullcolumns
create table #nullcolumns (tablename varchar(255), columnname varchar(255))
declare getinfo cursor for
select t.name tablename, c.name
from sys.tables t join sys.columns c on t.object_id = c.object_id
where t.name = 'testingnulls' --here the condition for the table name
open getinfo
fetch next from getinfo into #table, #col
while ##fetch_status = 0
begin
select #sql = 'if exists (select top 1 * from [' + #table + '] where [' + #col + '] is null or [' + #col + '] like '''' ) begin insert into #nullcolumns select ''' + #table + ''' as tablename, ''' + #col + ''' as all_nulls end'
print(#sql)
exec(#sql)
fetch next from getinfo into #table, #col
end
close getinfo
deallocate getinfo
--this should be the result you need:
select * from #nullcolumns
You can see a working example here. I hope this is what you need.
List all columns that contain a blank in some record? You'd use a query per column and collect the results with UNION ALL:
select 'COL1' where exists (select * from mytable where col1 like '% %')
union all
select 'COL2' where exists (select * from mytable where col2 like '% %')
union all
...
union all
select 'COL30' where exists (select * from mytable where col30 like '% %');
If you want like select * from [your_table_name] where [col1] = '' and [col2] = ''....., then use dynamic sql query like below.
Query
declare #sql as varchar(max);
select #sql = 'select * from [your_table_name] where '
+ stuff((
select ' and [' + [column_name] + '] = ' + char(39) + char(39)
from information_schema.columns
where table_name = 'your_table_name'
for xml path('')
)
, 1, 5, ''
);
exec(#sql);
Update
Or else if you want to list the column names which have a blank value, then you can use the below dynamic sql query.
Query
declare #sql as varchar(max);
select #sql = stuff((
select ' union all select ' + [column_name] + ' as [col1], '
+ char(39) + [column_name] + char(39) + ' as [col2]'
+ ' from your_table_name'
from information_schema.columns
where table_name = 'your_table_name'
for xml path('')
)
, 1, 11, ''
);
set #sql = 'select distinct t.col2 as [blank_cols] from(' + #sql
+ ')t
where coalesce(ltrim(rtrim(t.col1)), ' + char(39) + char(39) + ') = '
+ char(39) + char(39) + ';';
exec(#sql);
Find a demo here
But still I'm not sure that this is what you are looking out for.
you have not many choices but to specify all the columns in your where clause
WHERE COL1 = '' AND COL2 = '' AND COL3 = '' AND . . .
or you can use Dynamic SQL to form your query, but that is not an easy path to go
If you want to count number of columns having '' value in a table (not for each row) then use the following
SELECT max(CASE WHEN col1 = '' THEN 1 ELSE 0 END) +
max(CASE WHEN col2 = '' THEN 1 ELSE 0 END) +
max(CASE WHEN col3 = '' THEN 1 ELSE 0 END) +
...
FROM t
demo
I created a dynamic SQL script that you can use by providing the table name only
Here it is
declare #sql nvarchar(max)
declare #table sysname = 'ProductAttributes'
select #sql =
'select * from ' + #table + ' where ' +
string_agg('[' + name + '] = '' '' ', ' and ')
from sys.columns
where object_id = OBJECT_ID(#table)
select #sql
exec sp_executesql #sql
Unfortunately, for SQL string concatenation String_Agg function is new with SQL Server 2017
But it is also possible to use SQL XML Path to concatenate WHERE clause fragments
SELECT #sql = 'select * from ' + #table + ' where ' +
STUFF(
(
SELECT
' and ' + '[' + [name] + '] = '' '' '
from sys.columns
where object_id = OBJECT_ID(#table)
FOR XML PATH(''),TYPE
).value('.','VARCHAR(MAX)'
), 1, 5, ''
)
select #sql as sqlscript
exec sp_executesql #sql

T-SQL dynamic row checking

I am trying to run a check on a table where, for each row, I want to see whether the column has a a null in it and add a 1 like here:
SELECT
((CASE WHEN col1 IS NULL THEN 1 ELSE 0 END)
+ (CASE WHEN col2 IS NULL THEN 1 ELSE 0 END)
+ (CASE WHEN col3 IS NULL THEN 1 ELSE 0 END)
...
...
+ (CASE WHEN col10 IS NULL THEN 1 ELSE 0 END)) AS sum_of_nulls
FROM table
WHERE Customer=some_cust_id'
This method does what its supposed to in a static way but is it possible to dynamically build the columns based on the table as opposed to writing out each case statement.
Many thanks!
Here's what I came up with
declare
#sql nvarchar(max),
#columns nvarchar(max),
#table nvarchar(128) = '<your table here>'
select
#columns = stuff((select '+case when ' + quotename(column_name) + ' is null then 1 else 0 end'
from information_schema.columns
where table_name = #table
order by ordinal_position
for xml path('')), 1, 1, ''),
#sql = 'select sum_of_nulls = ' + #columns + ', *
from dbo.' + quotename(#table)
exec sp_executesql #sql
You can slot in a where clause after the table name if you want also. Right now, it just returns for everything in the table.

Dynamic Create column in sql server with datatype

I have table TAB_A
COL_NAME DATATYPE MAX_LENGTH
A VARCHAR 255
B INT 4
C FLOAT 8
I want to create A,B,C as column in TAB_B with DATATYPE and MAX_LENGTH.
The TAB_B columns look like this: Before
X Y Z
I want the TAB_B look like this: After
X Y Z A B C
with datatype.
How can I write dynamic SQL so my A,B,C,... columns will get created in existing table.
Try below,
I have created sample table like your example:
CREATE TABLE Tab_A
(
COL_NAME CHAR(1),
DATATYPE VARCHAR(100),
MAX_LENGTH INT
)
insert into Tab_A values('A', 'VARCHAR', 255)
insert into Tab_A values('B', 'INT' , 4)
insert into Tab_A values('C', 'FLOAT' , 8)
Now I have created other table Tab_B,
CREATE TABLE Tab_B
(
X CHAR(1),
Y VARCHAR(100),
Z INT
)
SELECT * from Tab_B
Now, Finally I'm using dynamic query,
DECLARE #ColumnName AS NVARCHAR(MAX)
SELECT #ColumnName = ISNULL(#ColumnName + ',', '')
+ QUOTENAME(COL_NAME) + ' ' + DATATYPE + CASE WHEN DATATYPE = 'INT' THEN '' ELSE '(' + CAST(MAX_LENGTH AS VARCHAR(10)) +')' END
FROM (
SELECT DISTINCT *
FROM Tab_A
) AS Courses
DECLARE #SQL VARCHAR(1000)
SELECT #SQL = 'ALTER TABLE Tab_B ADD ' + #ColumnName + ''
EXEC (#SQL)
SELECT * FROM Tab_B
This statement will provide the desired query:
DECLARE #TAB_A SYSNAME = 'dbo.Tab_A'
, #TAB_B SYSNAME = 'dbo.Tab_B'
DECLARE #dynsql NVARCHAR(MAX)
SELECT #dynsql = COALESCE(#dynsql,'') + qry
FROM (
SELECT
'ALTER TABLE ' + #TAB_B + ' ADD COLUMN '
+ COLUMN_NAME
+ ' ' + DATA_TYPE
+ CASE WHEN CHARACTER_MAXIMUM_LENGTH IS NULL THEN ' ' WHEN CHARACTER_MAXIMUM_LENGTH = -1 THEN '(MAX) ' ELSE '(' + CAST(CHARACTER_MAXIMUM_LENGTH AS VARCHAR(10)) + ') ' END
+ CASE WHEN IS_NULLABLE = 'NO' THEN 'NOT NULL' ELSE 'NULL' END
+ CASE WHEN COLUMN_DEFAULT IS NULL THEN '' ELSE ' DEFAULT ' + COLUMN_DEFAULT END
+ '; ' AS qry
from INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = PARSENAME(#TAB_A,1)
AND TABLE_SCHEMA = COALESCE(PARSENAME(#TAB_A,2),'dbo')
) r
SELECT #dynsql
Now you can also replace the
SELECT #dynsql
with
EXEC(#dynsql)
but be aware that your table A will be altered when executing.

Transpose rows to columns - SQL2005

I have the following result set
Status Wage --Columns Names (Table)
====== =====
Employed 10,000
What I need is:
Key Value DataType
=== ===== ========
Status Employed column data type e.g varchar
Wage 10,000 decimal(18,2)
How can this be achieved using TSQL in SQL 2005
What you are looking for is PIVOT.
http://msdn.microsoft.com/en-us/library/ms177410(v=SQL.90).aspx
It can be done using INFORMATION_SCHEMA, UNPIVOT, CAST and EXEC. Here's a working solution.
CREATE TABLE #Data ([Status] int, [Wage] varchar(100), [Tax] decimal(10,3), BigText nvarchar(max))
INSERT #Data VALUES (7, '$12m', 123123.22, 'small island')
SELECT ORDINAL_POSITION, COLUMN_NAME, DATA_TYPE
+ CASE WHEN CHARACTER_MAXIMUM_LENGTH > 0 THEN '(' + CAST(CHARACTER_MAXIMUM_LENGTH AS nvarchar(10)) + ')' WHEN CHARACTER_MAXIMUM_LENGTH = -1 THEN '(max)' ELSE '' END
+ CASE WHEN DATA_TYPE IN ('numeric', 'decimal') AND NUMERIC_PRECISION > 0 THEN '(' + CAST(NUMERIC_PRECISION AS nvarchar(10))
+ CASE WHEN NUMERIC_SCALE > 0 THEN ',' + CAST(NUMERIC_SCALE AS NVARCHAR(10)) ELSE '' END
+ ')' ELSE '' END DATA_TYPE
INTO #Columns
FROM INFORMATION_SCHEMA.COLUMNS C
WHERE C.TABLE_NAME LIKE '#Data%'
ORDER BY C.ORDINAL_POSITION
DECLARE #selectList nvarchar(max), #columnNames nvarchar(max)
SELECT #selectList = ISNULL(#selectList + ',', '') + 'CAST(' + QUOTENAME(COLUMN_NAME) + ' AS nvarchar(max)) ' + QUOTENAME(COLUMN_NAME),
#columnNames = ISNULL(#columnNames + ',', '') + QUOTENAME(COLUMN_NAME)
FROM #Columns
DECLARE #unpivot nvarchar(max)
SET #unpivot = '
SELECT b.Column_Name, b.DataValue, c.Data_Type
FROM
(
SELECT ' + #selectList + ' FROM #Data
) a
UNPIVOT (DataValue FOR Column_Name IN (' + #columnNames + ')) b
JOIN #Columns c ON c.Column_Name = b.Column_Name
'
EXEC (#unpivot)