Query Result(NULL value/Datetime format) - sql

I have this query that I use for put all the rows in one column, is dynamic because I need to do this with at least 8 tables:
DECLARE #tblName VARCHAR(20) = 'Location'
DECLARE #columns NVARCHAR(MAX), #sql NVARCHAR(MAX)
SELECT #columns = COALESCE(#columns, '') + '+[' + COLUMN_NAME + '],+'''''','''''''
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #tblName and TABLE_SCHEMA='LES'
select #columns
SET #sql = 'SELECT CONCAT(''''''''' + STUFF(#columns, 103,9, '') + '+'''''') FROM ' + #tblName
select #sql
--------------------------------------------------------------------------
R1: SELECT CONCAT(''''+[Location],+''','''+[Location Type],+''','''+[Region],+''','''+[World Region],+''','''+[Refresh Date]+''') FROM Location
If I execute the query (without the datetime column (Refresh Date) that contains NULL values) the result will be
'0020319389','CMF','AJ','AJ'
'0031209263','CMF','AJ','AJ'
'01BM','DCL','EU','EU'
'01CR','DCL','EU','EU'
My problem here is that when I execute the query with the Refresh_date column, I get this error:
Conversion failed when converting date and/or time from character string.
Can anybody help me please?
Thanks

Your problem is that you're mixing old school concatenation, + with the 2012/2014 CONCAT function and data precedence rules are in effect.
This bit of code is using old school syntax
SELECT #columns = COALESCE(#columns, '') + '+[' + COLUMN_NAME + '],+'''''','''''''
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #tblName and TABLE_SCHEMA='LES'
Instead, make it use a CONCAT, then your data type precedence will convert your date times to a string as well as handle NULLs.

Related

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.

how do I select records that are like some string for any column in a table?

I know that I can search for a term in one column in a table in t-sql by using like %termToFind%. And I know I can get all columns in a table with this:
SELECT *
FROM MyDataBaseName.INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = N'MyTableName`
How can I perform a like comprparison on each of the columns of a table? I have a very large table so I can't just spell out LIKE for each column.
As always, I'll suggest xml for this (I'd suggest JSON if SQL Server had native support for it :) ). You can try to use this query, though it could perform not so well on large number of rows:
;with cte as (
select
*,
(select t.* for xml raw('data'), type) as data
from test as t
)
select *
from cte
where data.exist('data/#*[local-name() != "id" and contains(., sql:variable("#search"))]') = 1
see sql fiddle demo for more detailed example.
Important note by Alexander Fedorenko in comments: it should be understood that contains function is case-sensitive and uses xQuery default Unicode code point collation for the string comparison.
More general way would be to use dynamic SQL solution:
declare #search nvarchar(max)
declare #stmt nvarchar(max)
select #stmt = isnull(#stmt + ' or ', '') + quotename(name) + ' like #search'
from sys.columns as c
where c.[object_id] = object_id('dbo.test')
--
-- also possible
--
-- select #stmt = isnull(#stmt + ' or ', '') + quotename(column_name) + ' like #search'
-- from INFORMATION_SCHEMA.COLUMNS
-- where TABLE_NAME = 'test'
select #stmt = 'select * from test where ' + #stmt
exec sp_executesql
#stmt = #stmt,
#params = N'#search nvarchar(max)',
#search = #search
sql fiddle demo
I'd use dynamic SQL here.
Full credit - this answer was initially posted by another user, and deleted. I think it's a good answer so I'm re-adding it.
DECLARE #sql NVARCHAR(MAX);
DECLARE #table NVARCHAR(50);
DECLARE #term NVARCHAR(50);
SET #term = '%term to find%';
SET #table = 'TableName';
SET #sql = 'SELECT * FROM ' + #table + ' WHERE '
SELECT #sql = #sql + COALESCE('CAST('+ column_name
+ ' as NVARCHAR(MAX)) like N''' + #term + ''' OR ', '')
FROM INFORMATION_SCHEMA.COLUMNS WHERE [TABLE_NAME] = #table
SET #sql = #sql + ' 1 = 0'
SELECT #sql
EXEC sp_executesql #sql
The XML answer is cleaner (I prefer dynamic SQL only when necessary) but the benefit of this is that it will utilize any index you have on your table, and there is no overhead in constructing the XML CTE for querying.
In case someone is looking for PostgreSQL solution:
SELECT * FROM table_name WHERE position('your_value' IN (table_name.*)::text)>0
will select all records that have 'your_value' in any column. Didn't try this with any other database.
Unfortunately this works as combining all columns to a text string and then searches for a value in that string, so I don't know a way to make it match "whole cell" only. It will always match if any part of any cell matches 'your_value'.

SQL results to string with wildcard

Suppose you have a table like this:
ID FNAME LNAME
1 Bob Smith
2 Sally Jones
A simple SELECT * FROM [Table] will return all rows. But what if you wanted to build a single string out of the results, and the column names are unknown? In other words, this will not work:
SELECT ID + ',' + FNAME + ',' + LNAME FROM [Table]
because you don't know the column names. Additionally, COALESCE won't work because it doesn't accept wildcards. Ideally you want to execute something like this:
SELECT dbo.FunctionThatSplitsResultsToString(*) FROM [Table]
and have it return
1,Bob,Smith
2,Sally,Jones
Is this possible?
This is a corrected version of the answer #Igor gave. In addition to concatenating comma characters between the values, it converts NULL values to an empty string (because concatenating a string to NULL results in a NULL value).
DECLARE #sql NVARCHAR(max)='SELECT '
DECLARE #TableName NVARCHAR(max) = 'Table_Name' -- <-- Set the target table name here
SELECT #sql=#sql+N'ISNULL(CAST(' + name +' as NVARCHAR(max)), '''')+'',''+'
FROM sys.columns
WHERE object_id=OBJECT_ID(#TableName)
SELECT #sql=SUBSTRING(#sql,1,LEN(#sql)-5)+N' FROM ' + #TableName
--SELECT #sql -- uncomment to see the query string
EXEC sp_executesql #sql
As the first Igor noted, the solution is dynamic SQL. You need to construct the underlying SQL statement correctly.
The following code casts all columns to varchar() and then concatenates them together. The final form of the SQL removes the last "+" sign and adds the from statement:
declare #sql varchar(max);
select #sql = (select 'cast('+coalesce(column_name, '') + ' as varchar(255)) +'
from information_schema.columns
where table_name = <whatever>
for xml path ('')
);
select #sql = left(#sql, len(#sql - 2)) + ' from t';
exec(#sql);
I admit to being US-centric and rarely using internationalization. The whole thing also works with nvarchars().
Try the below one
GO
DECLARE #ColumnsList VARCHAR(MAX), #SelectStatement VARCHAR(MAX),#TargetTable VARCHAR(250) ,#FINALSQL NVARCHAR(MAX)
SET #TARGETTABLE ='TempData'
SELECT #ColumnsList = COALESCE( #ColumnsList+' + '','' +' ,'') + 'Cast('+ A.COLUMN_NAME + ' AS Varchar(250))'
FROM (select Column_Name from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME= #TARGETTABLE) A
SELECT #FinalSql = 'Select ' +#ColumnsList + ' FROM ' + #TARGETTABLE
EXEC SP_EXECUTESQL #FINALSQL
GO

SQL Server: How to perform Rtrim on all varchar columns of a table

I have over 30 columns in my table (sql server 2008). Columns type are varchar(x). I know that in every column there is two extra spaces at the end of column value. How to use rtrim function for all columns and save this modification into this existing table?
Edit: is there a way to do it using stored procedure or cursor where I don't have to manually declare all columns?
For a generic approach, you can use a script like this to generate the statement for you, for a given table (useful if you have many columns!):
DECLARE #SQL VARCHAR(MAX)
DECLARE #TableName NVARCHAR(128)
SET #TableName = 'YourTableName'
SELECT #SQL = COALESCE(#SQL + ',[', '[') +
COLUMN_NAME + ']=RTRIM([' + COLUMN_NAME + '])'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #TableName
AND DATA_TYPE = 'varchar'
SET #SQL = 'UPDATE [' + #TableName + '] SET ' + #SQL
PRINT #SQL
That will just print the SQL statement out. You can either then copy + run the statement, or just EXECUTE(#SQL). This is untested, so just try it out on a test table first :)
UPDATE xxx
SET col1 = RTRIM(col1),
col2 = RTRIM(col2),
col3 = RTRIM(col3),
...
We can have stored procedure to trim specific table under specific schema. If we have different schema names other than default dbo schema, it is better to use this SP by passing schema name and table name. This performs both LTRIM and RTRIM. This SP would check char, nchar, varchar, nvarchar columns.
CREATE PROCEDURE [dbo].[TrimAllColumnsOfTable] #SchemaName Varchar(100),#TableName Varchar(100)
AS
BEGIN
DECLARE #SQL VARCHAR(MAX)
SELECT #SQL = COALESCE(#SQL + ',[', '[') +
COLUMN_NAME + ']=LTRIM(RTRIM([' + COLUMN_NAME + ']))'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = #SchemaName AND TABLE_NAME = #TableName AND DATA_TYPE Like '%char%'
SET #SQL = 'UPDATE [' + #SchemaName + '].[' + #TableName + '] SET ' + #SQL
EXEC (#SQL)
END
USAGE: [TrimAllColumnsOfTable] 'SchemaName','TableName'
It is perfect... But remember to put also the where clause:
COLUMNPROPERTY(OBJECT_ID(TABLE_SCHEMA+'.'+TABLE_NAME),COLUMN_NAME,'IsComputed') = 0
Ohterwise you will get an error if the table has a computed column of "%char%" type!
The accepted answer works well. I ran into an issue with a temp table being named the same name. You can add
and TABLE_SCHEMA = 'dbo'
And that will get rid of collision on table names.