SQL Server - Replace() in a select * query - sql-server

I have a procedure that does a "select * from view" and this output contains an inverted comma in one of the columns. I want to do a replace() to remove the extra inverted comma but I cannot change the "select *" as this is a dynamic query that is used in different scenarios.
As evident, the following query does not work
select replace(*, '"', '') from ReportRegistry
Some help appreciated.
I wanted to know if there is any way I can remove the quotes without knowing the column names. I want them to be removed from all columns. The columns names are different in different cases.
The view is defined within the procedure differently in different cases. The dynamic colum names are added as text and them executed using sp_executesql.

DECLARE #ColNames NVARCHAR(MAX) = ''
--Dynamically build a list of column names for the view, separated by commas.
SELECT #ColNames = #ColNames +
CASE
--Use the REPLACE function for "String" type data types. Did I leave any data types out?
--Change "x" to the character(s) you want to replace.
WHEN c.DATA_TYPE IN ('VARCHAR', 'CHAR', 'NVARCHAR', 'NCHAR') THEN 'REPLACE([' + c.COLUMN_NAME + '], ''x'', '''') AS [' + c.COLUMN_NAME + '],'
--All other data types.
ELSE '[' + c.COLUMN_NAME + '],'
END
--In addition to user tables, views are included in INFORMATION_SCHEMA.COLUMNS (and in INFORMATION_SCHEMA.TABLES).
FROM INFORMATION_SCHEMA.COLUMNS c
WHERE c.TABLE_NAME = 'ReportRegistry'
--Retain original order of the view's columns.
ORDER BY c.ORDINAL_POSITION
--Remove last comma
SET #ColNames = LEFT(#ColNames, LEN(#ColNames) - 1)
EXEC ('SELECT ' + #ColNames + ' FROM ReportRegistry ')

select replace(TargetColumnName, '"', '')
,Column2
,Column3
,..... and so on.....
from ReportRegistry

declare #tbl varchar(max) = 'table_or_view_name'
declare #cols varchar(max) =
(select case when data_type='varchar' then 'REPLACE('+column_name+',''"'','''')' else column_name end+char(10)+','
from information_schema.columns
where table_name = #tbl for xml path(''))
declare #sql varchar(max)='select '+left(#cols,len(#cols)-1)+' from '+#tbl
print #sql
exec(#sql)

Related

Search for a string in any column of all tables

For example this is my ID: 07E485
I need to find this ID in all tables wherever it is found
All columns, which might carry this value, are sort of string-type...
Something like: select * from **alltables** where **anyColumn**='07E485'
The following query will return all tables in the database yourDBName whose name contains 07E485.
SELECT TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE' AND
TABLE_CATALOG = 'yourDBName' AND
TABLE_NAME LIKE '%07E485%'
If I misread your requirement, and you instead wanted to find all tables precisely named 07E485 in any database, then you can use the following query:
SELECT TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE' AND
TABLE_NAME = '07E485'
In each database you have a view called INFORMATION_SCHEMA.COLUMNS, you can use this view to query through all of your tables.
This is the way I'ld do it, if anyone know a better way, feel free.. :)
SET NOCOUNT ON
DECLARE #Table varchar(255), #Schema varchar(255), #SQL varchar(MAX)
DECLARE table_cursor CURSOR FOR
SELECT TABLE_NAME, TABLE_SCHEMA
FROM INFORMATION_SCHEMA.COLUMNS -- This is a system view where you can see all columns of a database.
WHERE UPPER(COLUMN_NAME) = 'ID' -- This makes sure you don't loop through any tables that don't have a Column called 'ID'.
OPEN table_cursor
FETCH NEXT FROM table_cursor INTO #Table, #Schema
WHILE ##FETCH_STATUS = 0 BEGIN
-- This part creates your queries.
SET #SQL = 'SELECT * FROM '+#Schema+'.'+#Table+'
WHERE CAST(ID as varchar) = ''07E485''' -- Casting ID to varchar to avoid data type errors.
-- This executes the query.
EXEC(#SQL)
-- If a result is found, i.e. ID is equal to '07E485' somewhere in the table, Table name is printed on the "Messages" tab.
IF ##ROWCOUNT > 0 PRINT #Table
FETCH NEXT FROM table_cursor INTO #Table, #Schema
END
CLOSE table_cursor
DEALLOCATE table_cursor
To see which tables contain id = '07E485', go to "Messages" and you will have a list of them.
UPDATE My answer completely re-written
Try it like this: This dynamic SQL will check all string-type columns if they are equal to the given search string. You might want to add more data types to the output to get a better look onto the table's row. But one cannot simply put SELECT * as there are data types not allowed in XML without extra effort.
Secondly, by using QUOTENAME, I avoid syntax errors due to column or table names with blanks...
DECLARE #Search VARCHAR(10)='07E485';
DECLARE #cmd VARCHAR(MAX);
WITH TableNames AS
(
SELECT t.*
,t.TABLE_CATALOG + '.' + t.TABLE_SCHEMA + '.' + t.TABLE_NAME AS FullTblName
,QUOTENAME(t.TABLE_CATALOG)+ '.' + QUOTENAME(t.TABLE_SCHEMA) + '.' + QUOTENAME(t.TABLE_NAME) AS FullTblNameQuoted
,
STUFF(
(
SELECT 'OR ' + QUOTENAME(c.COLUMN_NAME) + '=''' + #Search + ''' '
FROM INFORMATION_SCHEMA.COLUMNS AS c
WHERE c.TABLE_CATALOG=t.TABLE_CATALOG AND c.TABLE_SCHEMA=t.TABLE_SCHEMA AND c.TABLE_NAME=t.TABLE_NAME
AND DATA_TYPE LIKE '%char%' --add more types if needed
FOR XML PATH('')
),1,3,'') AS WhereFilter
FROM INFORMATION_SCHEMA.TABLES AS t
WHERE TABLE_TYPE='BASE TABLE'
)
SELECT #cmd = STUFF(
(
SELECT DISTINCT 'UNION ALL SELECT (SELECT ' + (SELECT STUFF((SELECT ',' + QUOTENAME(COLUMN_NAME)
FROM INFORMATION_SCHEMA.COLUMNS AS c
WHERE c.TABLE_CATALOG=TableNames.TABLE_CATALOG
AND c.TABLE_NAME =TableNames.TABLE_NAME
AND c.DATA_TYPE LIKE '%char%'
FOR XML PATH('')),1,1,'')) + ' FROM ' + FullTblNameQuoted
+ ' WHERE ' + WhereFilter
+ ' FOR XML PATH(''row''),ROOT(''' + REPLACE(REPLACE(FullTblName,'.','_'),' ','') + '''),TYPE) AS XmlData '
FROM TableNames
WHERE WhereFilter IS NOT NULL
FOR XML PATH('')
),1,10,'')
SET #cmd='SELECT XmlData FROM(' + #cmd + ') AS tbl WHERE XmlData IS NOT NULL;'
PRINT LEN(#cmd)
EXEC(#cmd)

Exporting to Excel from SQL Server

I am stuck at a problem for which I cannot find any reason or solution.
I am running a SQL script to export some data to an Excel sheet. There is an application running on the other end which reads and processes the Excel sheet.
Problem: The column headers are being displayed at the bottom and the application is expecting them to be on the top row. I cannot change the functioning of the application.
This was working fine in SQL 2005, but we recently updated to SQL 2012 and this started happening.
I have not found anything over the internet to solve this issue.
This is the SQL script that I am executing
SELECT
#columnNames = COALESCE( #columnNames + ',', '') + '['+ column_name + ']',
#columnConvert = COALESCE( #columnConvert + ',', '') + 'convert(nvarchar(4000),'
+ '['+ column_name + ']' +
case
when data_type in ('datetime', 'smalldatetime') then ',121'
when data_type in ('numeric', 'decimal') then ',128'
when data_type in ('float', 'real', 'money', 'smallmoney') then ',2'
when data_type in ('datetime', 'smalldatetime') then ',120'
else ''
end + ') as ' + '['+ column_name + ']'
FROM tempdb.INFORMATION_SCHEMA.Columns
WHERE table_name = '##TempExportData'
-- execute select query to insert data and column names into new temp table
SELECT #sql = 'select ' + #columnNames + ' into ##TempExportData2 from (select ' + #columnConvert + ', ''2'' as [temp##SortID] from ##TempExportData union all select ''' + replace(replace(replace(#columnNames, ',', ''', '''),'[',''),']','') + ''', ''1'') t order by [temp##SortID]'
exec (#sql)
-- build full BCP query
DECLARE #bcpCommand VARCHAR(8000)
SET #bcpCommand = 'bcp " SELECT * from ##TempExportData2" queryout'
SET #bcpCommand = #bcpCommand + ' ' + #fullFileName + ' -T -w -S' + #serverInstance
EXEC master..xp_cmdshell #bcpCommand
Where TempExportData2 holds the data that along with column headers
I think I understand the problem: You are using the order by in the select into instead of in the final select statement.
You should know that data inside tables is considered unorderd and Sql Server (and any other rdbms I know, actually) does not guarantee the order of rows selected if the select statement does not contain an order by clause.
Therefor, you should add the [temp##SortID] column to your ##TempExportData2 table and use it to sort the last select statement:
SET #bcpCommand = 'bcp " SELECT * from ##TempExportData2 ORDER BY [temp##SortID]" queryout'
Since you don't need that column in the output query, so you might want to specify the column names in that select statement. However, if it's not causing damage to your application that reads the excel file or to the data it produces, I would suggest keeping the select * to make the query more readable.

SQL Server Dynamic Pivot Column Names

For the necessity of my application, I must return the column names of a query as the very first row.
Now I must PIVOT this result in order to UNION it with my result set, but the difficult part is: it must be dynamic, so if I ever add new columns to this table, the SELECT will bring all the names pivoted.
The following SELECT brings me the Column names:
SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'Codes'
ORDER BY INFORMATION_SCHEMA.COLUMNS.ORDINAL_POSITION
And my result set is:
COLUMN_NAME
Id
CodeName
Country
StartDate
EndDate
What I expect is:
Id CodeName Country StartDate EndDate (... whatever other columns I might have)
Is there any easy way to do that without hardcoding the column names?
Thank you in advance!
DECLARE #cols NVARCHAR (MAX)
SELECT #cols = COALESCE (#cols + ',[' + COLUMN_NAME + ']',
'[' + COLUMN_NAME + ']')
FROM (SELECT DISTINCT COLUMN_NAME,INFORMATION_SCHEMA.COLUMNS.ORDINAL_POSITION O
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'CODES') PV
ORDER BY O
DECLARE #query NVARCHAR(MAX)
SET #query = '
SELECT TOP 0 * FROM
(
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = ''CODES''
) x
PIVOT
(
MIN(COLUMN_NAME)
FOR [COLUMN_NAME] IN (' + #cols + ')
) p
'
EXEC SP_EXECUTESQL #query
Starting with SQL Server 2017, there's a function for this: STRING_AGG.
I used the QUOTENAME function as well here, to make adding the [ ] brackets easier.
DECLARE #ColumnNames NVARCHAR(MAX);
SELECT #ColumnNames = STRING_AGG(QUOTENAME(COLUMN_NAME), ',')
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME='Codes';
Simple way would be by declaring a variable and assigning the columns with comma separted. Try this.
DECLARE #col_list VARCHAR(max)=''
SELECT #col_list += '['+ COLUMN_NAME + '],'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'Codes'
ORDER BY INFORMATION_SCHEMA.COLUMNS.ORDINAL_POSITION
SELECT #col_list = LEFT(#col_list, Len(#col_list) - 1)
SELECT #col_list

SQL Server - select columns from given range

I have a table where I have columns like below
[Index], [Length],[N1],[N2]....[N99]
Now, is possible to select only [N2]] ... [N29] columns without writing all names.
No, it's not possible. You need to explicitly list the subset of columns you want to return.
This is not possible without writing all names.
You can of course drag and drop all the columns from the object browser and then delete the ones you don't want. At least that way you don;t have any typos.
I would be concerned about the design of a table with that many columns. Espceially if they really are N1-N99. You may need a redesign to a related table. Also wide tables can cause performance issues.
How about this:
DECLARE #columns VARCHAR(MAX),
#tablename VARCHAR(255),
#from VARCHAR(255),
#select VARCHAR(100)
SET #tablename = 'orderheader'
SELECT #columns = STUFF(
(
SELECT ',[' + column_name + ']'
FROM information_schema.columns
WHERE table_name = #tablename
AND NOT column_name IN ('N2', 'Index', 'Length')
FOR XML PATH('')
),1, 1, '')
SELECT #select = 'SELECT ', #from = ' from ' + #tablename
EXEC(#select + #columns + #from)
Using dynamic sql is the closest you can get to not writing the columns. Here is an example:
declare #sql varchar(max)
select #sql = coalesce(#sql+',', 'select ') + 'n' + cast(number as varchar(2))
from master..spt_values as N
where type = 'P' and
number between 2 and 29
set #sql = #sql + ' from <yourtable>'
--select #sql
exec (#sql)

Equivalent of sp_helptext for tables in SQL Server

When we need the query of stored procedures we use 'Sp_Helptext procedurename'
Can something similar be done for tables?
Use Alt+F1 while table name selected in a query window.
Pretty Simple :
sp_help YourTable
Please use followig query
select * from information_Schema.columns where table_name = 'TableName'
There does not appear to be a direct equivalent of sp_helptext that will work with tables.
The two methods that seem to be common on various message boards are:
Use Information_Schema.Columns and concatenate the results into the create statement.
Use SQL-DMO script
There is an article on the second method here
Try with this SP. It doesn't have all the notations required for a table like primary keys and foreign keys but is a start.
CREATE PROCEDURE [dbo].[GeneradorTablas]
#Tabla AS VARCHAR(100)
AS
BEGIN
DECLARE #Script AS VARCHAR(MAX) ='CREATE TABLE [dbo].[' + #Tabla + '](' + CHAR(13)
DECLARE #Columnas As TABLE(indice INT, Columna VARCHAR(1000))
INSERT INTO #Columnas
SELECT
ROW_NUMBER()OVER(ORDER BY C.column_id),
' [' + C.name + '] [' + TY.name + ']' +
CASE WHEN
TY.name='nvarchar' OR
TY.name='nchar' OR
TY.name='char' OR
TY.name='varbinary' OR
TY.name='varchar' OR
TY.name='text' THEN
'(' + CASE WHEN C.max_length>0 THEN CAST(C.max_length AS VARCHAR(10)) ELSE 'MAX' END + ')' ELSE ''
END +
CASE WHEN C.is_identity=1 THEN ' IDENTITY(1,1)' ELSE '' END +
' ' + CASE WHEN C.is_nullable=1 THEN 'NULL' ELSE 'NOT NULL' END + ','
FROM SYS.COLUMNS AS C
INNER JOIN SYS.TYPES AS TY ON C.system_type_id=TY.system_type_id
INNER JOIN SYS.TABLES AS T ON C.object_id=T.object_id
WHERE T.name=#Tabla
DECLARE #i AS INT
SELECT #i=MIN(indice) FROM #Columnas
WHILE #i IS NOT NULL
BEGIN
SELECT #Script+=Columna+CHAR(13) FROM #Columnas WHERE indice=#i
SELECT #i=MIN(indice) FROM #Columnas WHERE indice>#i
END
SET #Script=SUBSTRING(#Script,0,LEN(#Script)-1) + CHAR(13) + ')'
PRINT #Script
END
GO
review dba tools which can be installed as add on in powershell https://docs.dbatools.io/Get-DbaDbTable
will give you results in line like this
enter image description here

Resources