SQL Server select resultset values as a comma-separated string - sql

I have the following query in a stored procedure.
set #result1='EmpId,EmpName,Phone,City'
set #result2='select '+ #result1+ ' from [emptable]'+' where EmpId=1 and
EmpjoinDate= ''May-2014'''
exec(#result2)
The query returns
EmpId | EmpName | Phone | City
----------------------------------
1 | John | 832942 | NewYork
Now how to add query so that stored procedure returns single column result
| EmpInfo .........................|
------------------------------------
1,John,832942,NewYork
Please reply. Thanks.

set #result1='CONCAT(EmpId,',',EmpName,',',Phone,',',City)'
set #result2='select '+ #result1+ ' as EmpInfo from [emptable]'+' where EmpId=1 and
EmpjoinDate= ''May-2014'''
exec(#result2)

You have to build the string in the #result1 variable:
set #result1='EmpId+'',''+EmpName+'',''+Phone+'',''+City'
In Management Studio, you can also go to the Query Menu and select "Results To" -> "Results to Text" if that is enough for you.

If I get you clearly then this is who you want.
You have to concatenate the fields with the commas
set #result1='EmpId+'',''+EmpName''+'',''+''Phone''+'',''+''City'
set #result2='select '+#result1+' as EmpInfo from [emptable]'+' where EmpId=1 and
EmpjoinDate= ''May-2014'''
exec(#result2)

Using For XML and STUFF re-write the query as:
declare #result1 varchar(max),
#result2 varchar(max)
--Modify all input columns using Cast function to cast int datatype columns
--to varchar .Also this way you can add as many columns from table 'emptable'
--as you want
set #result1=''','' + cast(EmpId as varchar(20)) + '','' + EmpName + '',''
+ cast(Phone as varchar(20)) + '','' + City'
set #result2='select STUFF((SELECT '+ #result1+ ' from [emptable]
'+' where EmpId=1 FOR XML PATH('''')), 1, 1, '''') as EmpInfo'
exec(#result2)
Check Demo here

What you can do, is after receiving #result1 you replace data as you wish:
set #result1='EmpId,EmpName,Phone,City'
SET #result1 = REPLACE (#result1, ',', ' + '','' + ')
--SET #result1 = 'CONCAT ( ' + REPLACE (#result1, ',', ' , '','' , ') + ')' -- OR THIS IF you have INT inside this columns
set #result2='select '+ #result1+ ' from [emptable]'+' where EmpId=1 and
EmpjoinDate= ''May-2014'''
exec(#result2)
With CONCAT function looks better, if you have Server 2012. If not you will need CAST INT values into String

Related

Replacing more than 1 period to 1 period in sql

I have the following code to convert more than one period to one period in a column of a table.
alter proc replace_characters_1
#COLUMN_NAME varchar(30),
#TABLE_NAME varchar(30)
as
declare #SQL varchar(MAX)
while #COLUMN_NAME like '%..%'
begin
set #SQL= 'update [' +#TABLE_NAME+ '] set [' +#COLUMN_NAME+ '] = replace([' +#COLUMN_NAME+ '],''..'',''.'')';
exec(#SQL)
end
I want to change the Anna...Amal to Anna.Amal with one go, but the loop is not working. What should I do?`
One possible approach is to use nested REPLACE()s:
SET ColumnName = REPLACE(REPLACE(REPLACE(ColumnName, '.', '<>'), '><', ''), '<>', '.')
After the first REPLACE() the part from the text that contains periods (.) looks like <><><>. After the second REPLACE() the result is only <> and the final REPLACE() returns single period (.). If the characters < and > exist in the input text, you can choose another pair of characters.
Table:
CREATE TABLE Data (Name varchar(100))
INSERT INTO Data (Name)
VALUES
('ANNA..Amal'),
('ANNA..Amal.'),
('ANNA.Amal.'),
('ANNA...........Amal.'),
('ANNA.....Amal')
Procedure:
CREATE PROC replace_characters_1
#COLUMN_NAME sysname,
#TABLE_NAME sysname
AS
BEGIN
DECLARE #SQL nvarchar(MAX)
DECLARE #RC int
SET #SQL =
N'UPDATE ' + QUOTENAME(#TABLE_NAME) + N' ' +
N'SET ' + QUOTENAME(#COLUMN_NAME) + N' = ' +
N'REPLACE(REPLACE(REPLACE(' + QUOTENAME(#COLUMN_NAME) + ', ''.'', ''<>''), ''><'', ''''), ''<>'', ''.'') ' +
N'WHERE ' + QUOTENAME(#COLUMN_NAME) + N' LIKE ''%..%'''
EXEC #RC = sp_executesql #SQL
RETURN #RC
END
Result:
EXEC replace_characters_1 N'Name', N'Data'
SELECT * FROM Data
Name
ANNA.Amal
ANNA.Amal.
ANNA.Amal.
ANNA.Amal.
ANNA.Amal
Here is an approach that will reduce repeating characters.
Example
Declare #YourTable Table ([SomeCol] varchar(50))
Insert Into #YourTable Values
('Anna...Amal')
,('Anna........Amal')
,('Anna.Amal')
,('Anna Amal')
Select *
,NewVal = replace(replace(replace(SomeCol,'.','†‡'),'‡†',''),'†‡','.')
from #YourTable
Returns
SomeCol NewVal
Anna...Amal Anna.Amal
Anna........Amal Anna.Amal
Anna.Amal Anna.Amal
Anna Amal Anna Amal
Please check Zhorov's answer as it avoids multiple operations like this one.
CREATE PROCEDURE replace_characters_1
#COLUMN_NAME varchar(30),
#TABLE_NAME varchar(30)
AS
BEGIN
DECLARE #SQL NVARCHAR(MAX) = N'
UPDATE T SET
' + QUOTENAME(#COLUMN_NAME) + N' = REPLACE(' + QUOTENAME(#COLUMN_NAME) + N',''..'',''.'')
FROM
' + QUOTENAME(#TABLE_NAME) + N' AS T
WHERE
T.' + QUOTENAME(#COLUMN_NAME) + N' LIKE ''%..%'';
SET #UpdatedRowsOut = ##ROWCOUNT;';
DECLARE #UpdatedRows INT = 1;
WHILE #UpdatedRows > 0
BEGIN
EXECUTE sp_executesql
#SQL,
N'#UpdatedRowsOut INT OUTPUT',
#UpdatedRowsOut = #UpdatedRows OUTPUT;
END
END
Dynamic SQL is now returning the amount of rows that were updated, so it keeps going as long as there are values with .. for that column (note that there is a WHERE filter, you don't want to update all rows every time!).
SQL Server isn't the best for regex expressions, maybe you want to consider using a CLR function if you need to do different kind of stuff with regex.
I am using CHARINDEX and STUFF to derive the resultset
DECLARE #sqlstring Varchar(max) = 'Anna...Amal'
-- Getting first index of .
DECLARE #firstidx INT = CHARINDEX('.',#sqlstring)
-- Getting last index of .
Declare #lastidx int = (LEN(#sqlstring) - CHARINDEX('.',REVERSE(#sqlstring))) + 1
-- Stuffing the gap with emptystring
SELECT STUFF(#sqlstring,#firstidx+1,(#lastidx-#firstidx),'') as result
Result
+-----------+
| result |
+-----------+
| Anna.Amal |
+-----------+
UPDATE: If there are multiple comma separated values
DECLARE #sqlstring Varchar(max) = 'Anna...Amal,Vimal...Mathew'
SELECT STRING_agg(removedvalues,',') as values
FROM
(SELECT STUFF(value, CHARINDEX('.',value)+1
,(LEN(value) - CHARINDEX('.',REVERSE(value)) + 1) - CHARINDEX('.',value),'') AS removedvalues
FROM string_split(#sqlstring,',') ) AS t
+------------------------+
| Values |
+------------------------+
| Anna.Amal,Vimal.Mathew |
+------------------------+

SQL dynamic string filter

I'm trying to get the user to select which columns they want to see from a table and be able to get results even when they don't fill out someone's whole name (like a filter). When the code below is not in a SET string it does work fine but when it is, I do have a bug I can't see. The error is on the 'WHERE' line, well that's what SQL server is telling me.
DECLARE #SQL NVARCHAR(Max) = ''
SET #SQL =
'
SELECT ' + #TableList + ' FROM People
WHERE (IsNull(Input.Name, '''') LIKE ''%'' '+ #Name +' ''%'')
'
EXEC(#SQL)
Below is what the query looks like when it's not in a string and does work normally.
SELECT [Name], [Age], [City] FROM People
WHERE (IsNull(Input.Name, '') LIKE '%' + #Name + '%')
And let's say a user enters the name 'Tom', they will get the following results...
Name Age City
Tom 28 NY
Tommy 35 LA
The error message I am getting is...
The data types varchar and varchar are incompatible in the modulo operator.
Which does confuse me a bit since it does work fine when it's not in a string.
You have too many ' in your statement.
DECLARE #SQL NVARCHAR(Max) = ''
SET #SQL =
'
SELECT ' + #TableList + ' FROM People
WHERE (IsNull(Input.Name, '''') LIKE ''%'+ #Name +'%'')
'
EXEC(#SQL)

Is there a way to Replace(*) in sql?

So simply I'm doing something similar to:
select
[BadData], [WorseDate], [IQuitData]
into
#BadDataTempTable
from
SomeoneElsesMess
what I want to do now is something similar to:
Select
Replace(#BadDataTempTable.*, ',', ' ')
from
#BadDataTempTable -- Replace all commas in every column `with a space--`
Is this possible? If so please show me the easiest (non-function) way to do so.
Thanks. SQL Server 2012 I think. I'm using SSMS 17
No, the columns have to be specified. You could use dynamic SQL to build your update / query. Then just copy the command you want from the results.
Maybe this will help get you started:
BEGIN
-- Set the replace value
DECLARE #ls_replaceValue NVARCHAR(MAX) = ',';
-- Set the with value
DECLARE #ls_withValue NVARCHAR(MAX) = ' ';
-- Set the table name we want to query
DECLARE #ls_table NVARCHAR(MAX) = 'some_table';
-- Get all of the columns and provide the replace parameters
DECLARE #ls_columns NVARCHAR(MAX) = '';
SELECT #ls_columns = #ls_columns + ', ' + name + ' = REPLACE(' + name + ', ' + '' + '''' + REPLACE(#ls_replaceValue, '''', '''''''') + '''' + ', ' + '''' + REPLACE(#ls_withValue, '''', '''''''') + '''' + ')'
FROM sys.all_columns
WHERE object_id = OBJECT_ID(#ls_table)
AND collation_name IS NOT NULL; -- Skip columns that aren't character based
-- Remove the first ', ' from the column list
SET #ls_columns = SUBSTRING(#ls_columns, 3, LEN(#ls_columns));
IF #ls_columns = ''
BEGIN
PRINT 'Table not found'
RETURN
END
-- Build a query
DECLARE #ls_query_sql NVARCHAR(MAX) = '';
SET #ls_query_sql = 'SELECT ' + #ls_columns + ' FROM ' + #ls_table;
-- Show the results
SELECT #ls_query_sql AS querySQL;
END
Just since the OP asked about how you might do this in dynamic SQL, here's how I'd approach it. Basically get the table schema information and concatenate all the columns, plus the REPLACE logic you want using FOR XML. This basically constructs the statement Rigerta posted, but does it dynamically.
use tempdb
go
if object_id('tempdb.dbo.#SomeoneElsesBadData') is not null drop table #SomeoneElsesBadData
create table #SomeoneElsesBadData
(
BadData varchar(250),
WorseData varchar(250),
IQuitData varchar(250)
)
declare #sql nvarchar(max)
select #sql = 'select '
+ stuff((select ', '
+ name
+ ' = replace(' + name + ''','', '''')'
from tempdb.sys.columns
where object_id = object_id('tempdb.dbo.#SomeoneElsesBadData')
for xml path('')), 1, 1, '')
+ ' into #BadDataTempTable
from #SomeoneElsesBadData'
exec sp_executesql #sql
All things being equal, the data should probably be cleaned before it gets into SQL, but reality is rarely fair.

Return SELECT query result as a CSV string

I have the following Sql Server 2016 SELECT statement that returns only 1 row:
SELECT TOP 1 * FROM tempdb.dbo.IMTD
How can I concatenate the values as a comma delimited string? NOTE: the column names of this temporary table are unknown as they can variate.
Thank you.
Something like this perhaps:
-- Sample data
DECLARE #someTable TABLE (SomeID int identity, SomeTxt varchar(100));
INSERT #someTable VALUES ('row1'),('row2'),('row3');
-- Solution
SELECT ConcatinatedString =
STUFF
((
SELECT ','+SomeTxt
FROM #someTable
FOR XML PATH(''), TYPE
).value('.','varchar(100)'),1,1,'');
You can use Dynamic query as below:
DECLARE #COLS VARCHAR(MAX) = ''
SELECT #COLS = #COLS + ',' + COLUMN_NAME
FROM tempdb.INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME LIKE '#table[_]%' -- Dynamic Table (here, Temporary table)
DECLARE #COLNAMES VARCHAR(MAX) = REPLACE(STUFF(#COLS, 1, 1, ''), ',', '+ '','' +')
Declare #cmd varchar(max) = 'Select ' + #COLNAMES + ' as CSVCol from #table'
-- will generate
-- Select Column1+ ',' +Column2+ ',' +Column3 as CSVCol from #table
EXEC (#cmd)
Another solution you can try is this.
SELECT LTRIM(RTRIM(<ColumnName1>)) + ',',
LTRIM(RTRIM(<ColumnName2>)) + ',',
...
LTRIM(RTRIM(<ColumnNamen>)) + ','
FROM tempdb.dbo.IMTD
If you only want one row keep that top 1 In there like
SELECT TOP 1
LTRIM(RTRIM(<ColumnName1>)) + ',',
LTRIM(RTRIM(<ColumnName2>)) + ',',
...
LTRIM(RTRIM(<ColumnNamen>)) + ','
FROM tempdb.dbo.IMTD
The LTRIM and RTRIM will remove any white space and this should allow you to copy and paste the result set anywhere you may need it. You will need to do this for each columnname.
You can use the query below to get the column names from your temp table.
DECLARE #ColumnNames NVARCHAR(MAX)
SELECT
#ColumnNames= COALESCE(#ColumnNames +',','')+COLUMN_NAME
FROM
TempDB.INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_NAME = '#TempTableName'

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