SELECT only values defined in INFORMATION SCHEMA - sql

Could you please help me with following issue?
Source table:
Columns defined from INFORMATION_SCHEMA.COLUMNS:
In output I'd like to take my source table, but show only values which column name is the same as column name defined in information schema. Meaning:
Is it possible? Many thanks in advance

You need to use dynamic SQL to do that:
declare #sql varchar(1000) 'select ';
select #sql = #sql + '[' + column_name + '] ,' from INFORMATION_SCHEMA.COLUMNS;
-- remove last character in a string which is comma
select #sql = left(#sql, len(#sql) - 1);
-- you need to change talbe name here
select #sql = #sql + ' from MyTable';
-- execute statement
exec(#sql)

Related

How to return all values in the first column of a table without specifying column's name?

I need to create a dynamic sql query in order to return all values in the first column of a table. The table's name needs to be a variable #tableName ( i will run this query for multiple tables depending on several conditions). Also, i don't know exactly the first column's name but it is formed out of Id_#tableName .
I need something like below but written dinamically:
select
(select column_name from INFORMATION_SCHEMA.columns where table_Name= #tableName and ordinal_position=1)
from #tableName
Could you please help me? Thank you in advance!
USE AdventureWorks;
GO
DECLARE #ObjectName SYSNAME = 'Sales.SalesOrderHeader';
DECLARE #SQL NVARCHAR(MAX);
SELECT
#SQL = 'SELECT ' + QUOTENAME(name) + ' FROM ' + #ObjectName
FROM
sys.columns
WHERE
object_id = OBJECT_ID(#ObjectName)
AND column_id = 1;
EXEC sp_executesql #SQL;

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'.

How to select output of XML Path query in SQL?

Doc table contains a lot of columns (even not used ones):
Doc_DdfID Doc_RentDate Doc_ReturnDate etc.
--------- ------------ -------------- ----
1 2012-07-28 2012-07-28
But I want to query just the used ones within Doc's table.
DocDefinitionFields list columsn that are in use by document:
SELECT Dfl_ColName
FROM DocDefinitionFields
WHERE Dfl_DdfID = 1
DocDefinitionFields:
Dfl_ColName
-----------
Doc_RentDate
Doc_ReturnDate
...........
So I want to select all columns (listed by second query) from Doc table.
Example (if 2 columns are added to document definition form I want to select just them):
Doc:
Doc_RentDate Doc_ReturnDate
------------ --------------
2012-07-28 2012-07-28
Tried to do that by subquerying select with concatenation of fields using XML PATH:
SELECT
(SELECT
Dfl_ColName + ', '
FROM DocDefinitionFields
FOR XML PATH('')
)
FROM Doc
It's not that simple tho. What do you suggest?
What you need here is dynamic SQL, something like this:
DECLARE #sql VARCHAR(MAX)
SET #sql = 'SELECT ' + STUFF((SELECT ', ' + Dfl_ColName FROM DocDefinitionFields FOR XML PATH('') ),1,1,'') + ' FROM Doc'
EXEC (#sql)
Also, in order to eliminate additional comma(,) at the end of columns I have added STUFF function along with FOR XML PATH.
To get the column names for a query dynamically and use these in a query you will need to use Dynamic SQL. Below is an example of how to create the string of available columns
DECLARE #Columns VARCHAR(MAX);
SELECT #Columns =
COALESCE(#Columns + ',
[' + CAST(COLUMN_NAME AS VARCHAR) + ']',
'[' + CAST(COLUMN_NAME AS VARCHAR) + ']')
FROM (SELECT DISTINCT COLUMN_NAME
FROM [SomeDatabase].INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = N'SomeTableName') AS H
ORDER BY COLUMN_NAME;
GO
You can now use the string of available columns in a Dynamic SQL query. Below we have adopted the above in an INSERT query that build the required fields dynamically. The reason why we need to do it in the below is the inclusion of the set field SomeFieldA along with the others.
DECLARE #SQL NVARCHAR(MAX);
SET #SQL =
N'INSERT INTO [' + #DbName + N']..[SomeOtherTable] ([SomeFieldA], ' + #Columns + N')
SELECT SomeFieldA, ' + #Columns + N'
FROM [SomeTableName];';
EXEC sp_executesql #SQL;
GO
You should be able to amend the above to provide what you need.
I hope this helps.

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

Aliasing columns based on cross-reference table

I have a table with over 400 columns, and these are named with our vendor's archaic naming system. I need to move this data into a new table which uses our company's naming conventions, so I have to change the names of these 400 columns.
Fortunately, I also have a table that cross-references the current column names with what they should become, like so:
Acronym | Name
----------------
A | ColumnNameA
B | ColumnNameB
C | ColumnNameC
etc...
So my question is this:
If it were only a few rows, I could easily do
SELECT
A AS ColumnNameA,
B AS ColumnNameB
FROM
Table
But there are just too many columns to do this by hand. What's the best way to dynamically change column names in a SELECT statement based off of a cross-ref table?
My effort so far:
I was thinking something along the lines of
SET #sqlCommand = 'SELECT ' + #columns + ' FROM Table'
EXEC (#sqlCommand)
but I have no idea how to set #columns to be a dynamically generated list of all the acronyms as the final column names. Is this even a viable approach?
DECLARE #sql NVARCHAR(MAX) = N'';
SELECT #sql += ',' + QUOTENAME(Acronym) + ' AS ' + QUOTENAME(Name)
FROM dbo.AcronymTable;
SET #sql = 'SELECT ' + STUFF(#sql, 1, 1, N'') + ' FROM dbo.Table;';
PRINT #sql;
--EXEC sp_executesql #sql;
The easiest way is to add an int field that determines the order of columns so it matches from source to target. Then you can:
DECLARE #sql varchar(max)
SET #SQL = 'INSERT INTO dbo.Target SELECT '
SELECT #SQL = #SQL + Acronym + ','
FROM ConversionTable
ORDER BY OrderColumn
SET #SQL = LEFT(#SQL, (LEN(#SQL) - 1))
SET #SQL = #SQL + ' FROM SourceTable'