Replace NULL with empty string in SQL for ALL columns - sql

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

Related

Get all not NULL column names from a SQL Server table

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.

Counting rows in the table which have 1 or more missing values

Could you please advise how to find the number of rows in the table which have 1 or more missing values? The missing values are represented in my table by question marks = '?'. The table has 15 columns and ~50k rows. When I run the following query for some of the columns I can receive some results:
SELECT
COUNT(*)
FROM table_name
WHERE column_name ='?'
However I have also columns which bring me result: "Error converting data type varchar to float"
I would like to be able to find the number of rows in the table which have 1 or more missing values using 1 query/not run separately for each column.
Thank you in advance for your support!
Select Count(*)
From mySchema.myTable
Where Cast(Col1 As NVarChar(128)) +
Cast(Col2 As NVarChar(128)) +
Cast(Coln As NVarChar(128)) Like '%?%'
It's ugly and WILL be slow and you may need to modify the Casts accordingly, but should do the trick.
This should work for any column:
select count(*)
from table_name
where column_name is null or cast(column_name as varchar(255)) = '?';
Try following query:
Just set table name and it will get all columns
Also you can give value_to_match like '?' in your case or any other if you want.
DECLARE #table_name nvarchar(max) = 'table_name'
DECLARE #value_to_match nvarchar(max) = '1'
DECLARE #query nvarchar(max) = ''
DECLARE #Condition nvarchar(max) = ' OR ' -- 1 OR when you want to count row if any column has that value -- 2 when you want all all columns to have same value
SELECT #query = #query + ' cast(' + COLUMN_NAME + ' as nvarchar(500)) = ''' + #value_to_match + '''' + #Condition FROM informatioN_schema.columns WHERE table_name = #table_name
if ##rowcount = 0
BEGIN
SELECT 'Table doesn''t Exists'
RETURN
END
SELECT #query = LEFT(#query,LEN(#query)-3)
PRINT ('select count(9) FROM ' + #table_name + ' WHERE ' + #query)
EXEC ('select count(9) FROM ' + #table_name + ' WHERE ' + #query)

Is there a way to remove '_' from column name while selecting * in sql statement?

My table has all the column names
(There are more than 80 columns, I can't change the column names now)
in the format of '_'. Like First_Name, Last_Name,...
So i want to use select * from table instead
of using AS.
I want to select them by removing '_' in one statement. Anyway i can do it?
something like Replace(coulmnName, '_','') in select statement ?
Thanks
You can simply rename the column in your query. For example:
SELECT FIRST_NAME [First Name],
LAST_NAME [Last Name]
FROM UserTable
You can also use the AS keyword but this is optional. Also note that if you don't want to do this on every query you can use this process to create a view with renamed columns. Then you can use SELECT * the way you want to (although this is considered a bad idea for many reasons).
Best of luck!
Alternative - Map In The Client Code:
One other alternative is to do the mapping in the client code. This solution is going to depend greatly on your ORM. Most ORM's (such as LINQ or EF) will allow you to remap. If nothing else you could use AutoMapper or similar to rename the columns on the client using convention based naming.
You can't do this in a single statement unless you're using dynamic SQL. If you're just trying to generate code, you can run a query against Information_Schema and get the info you want ...
DECLARE #MaxColumns INT
DECLARE #TableName VARCHAR(20)
SET #TableName = 'Course'
SELECT #MaxColumns = MAX(ORDINAL_POSITION) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = #TableName
SELECT Col
FROM
(
SELECT 0 Num, 'SELECT' Col
UNION
SELECT ROW_NUMBER() OVER (PARTITION BY TABLE_NAME ORDER BY ORDINAL_POSITION) Num, ' [' + COLUMN_NAME + '] AS [' + REPLACE(COLUMN_NAME, '_', '') + ']' + CASE WHEN ORDINAL_POSITION = #MaxColumns THEN '' ELSE ',' END
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #TableName
UNION
SELECT #MaxColumns + 1 Num, 'FROM ' + #TableName
) s
ORDER BY num
The question intrigued me and I did find one way. It makes it happen but if you just wanted to give a lot of aliases one time in one query I wouldn't recommend it though.
First I made a stored procedure that extracts all the column names and gives them an alias without '_'.
USE [DataBase]
GO
IF OBJECT_ID('usp_AlterColumnDisplayName', 'P') IS NOT NULL
DROP PROCEDURE usp_AlterColumnDisplayName
GO
CREATE PROCEDURE usp_AlterColumnDisplayName
#TableName VARCHAR(50)
,
#ret nvarchar(MAX) OUTPUT
AS
Select #ret = #ret + [Column name]
From
(
SELECT ([name] + ' AS ' + '[' + REPLACE([name], '_', ' ') + '], ') [Column name]
FROM syscolumns
WHERE id =
(Select id
From sysobjects
Where type = 'U'
And [name] = #TableName
)
) T
GO
Then extract that string and throw it into another string with a query-structure.
Execute that and you are done.
DECLARE #out NVARCHAR(MAX), #DesiredTable VARCHAR(50), #Query NVARCHAR(MAX)
SET #out = ''
SET #DesiredTable = 'YourTable'
EXEC usp_AlterColumnDisplayName
#TableName = #DesiredTable,
#ret = #out OUTPUT
SET #out = LEFT(#out, LEN(#out)-1) --Removing trailing ', '
SET #Query = 'Select ' + #out + ' From ' + #DesiredTable + ' WHERE whatever'
EXEC sp_executesql #Query
If you just wanted to give a lot of aliases at once without sitting and typing it out for 80+ columns I would rather suggest doing that with one simple SELECT statement, like the one in the sp, or in Excel and then copy paste into your code.

SQL Wildcard instead of key in SELECT statement

Can I, in a neat way do:
SELECT *
FROM tablename
WHERE * LIKE '%something%';
Without having to do:
SELECT *
FROM tablename
WHERE ColA LIKE '%something%'
OR ColB LIKE '%something%' ...;
Running SQL Server 2008, I get error:
"Cannot use a CONTAINS or FREETEXT predicate on table or indexed view
'tablename' because it is not full-text indexed.
I don't have full text index :)
To build on #Bob Probst's idea, you might try dynamic SQL like this:
-- Set these!
declare #tableName nvarchar(128)= 'MyTableName'
declare #searchString nvarchar(max)= '%something%'
-- Build SQL query
declare #sql nvarchar(max)
select #sql = isnull(#sql + 'or ', 'select * from ' + #tableName + ' where ' )
+ '[' + column_name + '] like ''' + replace(#searchString, '''', '''''') + ''' '
from information_schema.columns
where table_name = #tableName
-- Could use this where clause for only comparing string fields (or eliminating image and such)
--and data_type in ('varchar', 'char','nvarchar', 'nchar')
-- Run SQL query
print (#sql) -- For debug
exec (#sql)
You could script it like this:
select 'select * from dbo.ACCOUNT_DIMENSION where '
union all
select c.name+' like ''%something%'' or '
from sys.tables t
inner join sys.columns c on (t.object_id=c.object_id)
where t.name = 'ACCOUNT_DIMENSION'
union all
select '1=1'
No. This is not possible. You have to write the fieldnames.
You should be able to use the + sign to bind ColA and ColB together:
SELECT
*
FROM
tablename
WHERE
ColA+ColB Like '%something%'
How's CONTAINS* sound?
Use AdventureWorks2008R2;
GO
SELECT Name, Color FROM Production.Product
WHERE CONTAINS((Name, Color), 'Red');
*This requires fulltext indices
Without a fulltext index the only way to do this dynamically is with a dynamically built statement;
declare #sql varchar(max) = 'select * from tablename where 1=0'
select #sql += ' or ' + quotename(column_name) + ' like ''%something%'''
from information_schema.columns
where TABLE_NAME = 'tablename'
and data_type in ('char', 'varchar', 'nchar', 'nvarchar')
exec(#sql)

Finding the data types of a SQL temporary table

I need to switch from using a #temp table to a #table variable so that I can use it in a function.
My query uses insert into #temp (from multiple tables) like so:
SELECT
a.col1,
a.col2,
b.col1...
INTO #temp
FROM ...
Is there an easy way to find out the data types of the columns in the #temp table so that I can create the #table variable with the same columns and data types as #temp?
You need to make sure sp_help runs in the same database where the table is located (tempdb). You can do this by prefixing the call directly:
EXEC tempdb.dbo.sp_help #objname = N'#temp';
Or by prefixing a join against tempdb.sys.columns:
SELECT [column] = c.name,
[type] = t.name, c.max_length, c.precision, c.scale, c.is_nullable
FROM tempdb.sys.columns AS c
INNER JOIN tempdb.sys.types AS t
ON c.system_type_id = t.system_type_id
AND t.system_type_id = t.user_type_id
WHERE [object_id] = OBJECT_ID(N'tempdb.dbo.#temp');
This doesn't handle nice things for you, like adjusting max_length for varchar differently from nvarchar, but it's a good start.
In SQL Server 2012 or better, you can use a new DMF to describe a resultset, which takes that issue away (and also assembles max_length/precision/scale for you). But it doesn't support #temp tables, so just inject the query without the INTO:
SELECT name, system_type_name, is_nullable
FROM sys.dm_exec_describe_first_result_set(N'SELECT
a.col1,
a.col2,
b.col1...
--INTO #temp
FROM ...;',NULL,1);
The accepted answer does not give the data type.Joining tempdb.sys.columns with sys.types gives the data type as mentioned in the comment of the answer.But joining on system_type_id yields one extra row with datatype "sysname". Instead "user_type_id" gives the exact solution as given below.
SELECT cols.NAME
,ty.NAME
FROM tempdb.sys.columns cols
JOIN sys.types ty ON cols.user_type_id = ty.user_type_id
WHERE object_id = OBJECT_ID('tempdb..#temp')
you need to qualify the sp_help process to run from the tempdb database to get details about a hash table, because that's where the hash table is actually stored. If you attempt to run sp_help from a different database you'll get an error that the table doesn't exist in that database.
If your query is executing outside of tempdb, as I assume it is, you can run the following:
exec tempdb..sp_help #temp
One benefit of this procedure is it includes a text description of the column datatypes for you. This makes it very easy to copy and paste into another query, e.g. if you're trying use the definition of a temp table to create a table variable.
You could find the same information in the Syscolumns table, but it will give you numeric indentifiers for the types which you'll have to map yourself. Using sp_help will save you a step.
The other answers will give you the information that you need, but still require you to type it all out when you define the table variable.
The following TSQL will allow you to quickly generate the table variable's definition for any given table.
This can save you a lot of time instead of manually typing table definitions like:
table(Field1Name nvarchar(4), Field2Name nvarchar(20), Field3Name int
, Field4Name numeric(28,12))
TSQL:
select top 10 *
into #temp
from db.dbo.myTable
declare #tableName nvarchar(max)
set #tableName = '#temp'
use tempdb
declare #tmp table(val nvarchar(max))
insert into #tmp
select case data_type
when 'binary' then COLUMN_NAME + ' ' + DATA_TYPE + '(' + cast(CHARACTER_MAXIMUM_LENGTH AS nvarchar(max)) + ')'
when 'char' then COLUMN_NAME + ' ' + DATA_TYPE + '(' + cast(CHARACTER_MAXIMUM_LENGTH AS nvarchar(max)) + ')'
when 'datetime2' then COLUMN_NAME + ' ' + DATA_TYPE + '(' + CAST(DATETIME_PRECISION as nvarchar(max)) + ')'
when 'datetimeoffset' then COLUMN_NAME + ' ' + DATA_TYPE + '(' + CAST(DATETIME_PRECISION as nvarchar(max)) + ')'
when 'decimal' then COLUMN_NAME + ' ' + DATA_TYPE + '(' + cast(NUMERIC_PRECISION as nvarchar(max)) + ',' + cast(NUMERIC_SCALE as nvarchar(max)) + ')'
when 'nchar' then COLUMN_NAME + ' ' + DATA_TYPE + '(' + cast(CHARACTER_MAXIMUM_LENGTH AS nvarchar(max)) + ')'
when 'numeric' then COLUMN_NAME + ' ' + DATA_TYPE + '(' + cast(NUMERIC_PRECISION as nvarchar(max)) + ',' + cast(NUMERIC_SCALE as nvarchar(max)) + ')'
when 'nvarchar' then COLUMN_NAME + ' ' + DATA_TYPE + '(' + cast(CHARACTER_MAXIMUM_LENGTH AS nvarchar(max)) + ')'
when 'time' then COLUMN_NAME + ' ' + DATA_TYPE + '(' + CAST(DATETIME_PRECISION as nvarchar(max)) + ')'
when 'varbinary' then COLUMN_NAME + ' ' + DATA_TYPE + '(' + cast(CHARACTER_MAXIMUM_LENGTH AS nvarchar(max)) + ')'
when 'varchar' then COLUMN_NAME + ' ' + DATA_TYPE + '(' + cast(CHARACTER_MAXIMUM_LENGTH AS nvarchar(max)) + ')'
-- Most standard data types follow the pattern in the other section.
-- Non-standard datatypes include: binary, char, datetime2, datetimeoffset, decimal, nvchar, numeric, nvarchar, time, varbinary, and varchar
else COLUMN_NAME + ' ' + DATA_TYPE
end + case when IS_NULLABLE <> 'YES' then ' NOT NULL' else '' end 'dataType'
from INFORMATION_SCHEMA.COLUMNS
where TABLE_NAME like #tableName + '%'
declare #result nvarchar(max)
set #result = ''
select #result = #result + [val] + N','
from #tmp
where val is not null
set #result = substring(#result, 1, (LEN(#result)-1))
-- The following will replce '-1' with 'max' in order to properly handle nvarchar(max) columns
set #result = REPLACE(#result, '-1', 'max')
select #result
Output:
Field1Name nvarchar(4), Field2Name nvarchar(20), Field3Name int
, Field4Name numeric(28,12)
to get columns name with data type use this
EXEC tempdb.dbo.sp_help N'#temp';
or
To get only columns name to use this
SELECT *
FROM tempdb.sys.columns
WHERE [object_id] = OBJECT_ID(N'tempdb..#temp');
Finding the data types of a SQL temporary table
METHOD 1 – Using SP_HELP
EXEC TempDB..SP_HELP #TempTable;
Note-
In the Table Structure, the Table Name shows something like ‘#TempTable__________________________________________________________________________________________________________0000000004CB’. Actually, the total length of each and every Temp Table name will be 128 . To handle the Same Temp Table name in Multiple Sessions differently, SQL Server will automatically add some underscores in between and alphanumeric’s at end.
METHOD 2 – Using SP_COLUMNS
EXEC TempDB..SP_COLUMNS '#TempTable';
METHOD 3 – Using System Tables like INFORMATION_SCHEMA.COLUMNS, SYS.COLUMNS, SYS.TABLES
SELECT * FROM TempDB.INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME IN (
SELECT NAME FROM TempDB.SYS.TABLES WHERE OBJECT_ID=OBJECT_ID('TempDB.dbo.#TempTable')
);
GO
SELECT * FROM TempDB.SYS.COLUMNS WHERE OBJECT_ID=OBJECT_ID('TempDB.dbo.#TempTable');
GO
SELECT * FROM TempDB.SYS.TABLES WHERE OBJECT_ID=OBJECT_ID('TempDB.dbo.#TempTable');
GO
I'd go the lazy route and use
use tempdb
GO
EXECUTE sp_help #temp
What you are trying to do is to get information about the system types of the columns you are querying.
For SQL Server 2012 and later you can use sys.dm_exec_describe_first_result_set function. It returns very detailed information about the columns and the system_type_column holds the complete system type definition (ready to use in your table definition):
For example:
SELECT *
FROM [sys].[dm_exec_describe_first_result_set] (N'SELECT object_id, name, type_desc FROM sys.indexes', null, 0);
Yes, the data types of the temp table will be the data types of the columns you are selecting and inserting into it. So just look at the select statement and determine each data type based on the column you select.