Get table name from database field - sql

I use SQL Server Management Studio 17.0. I have a table which controls separate tables for different files, something like:
filename | tablename
---------+----------
file1 | table1
file2 | table2
I need to select from tablename, but not hardcoded. Filename comes from web, and I can fist get the tablename, like
select tablename
from filetables
where filename = "file1"
and use it to view the file table:
select *
from (table1)
Is there any way to do it in SQL? Something like
Select *
from
(select tablename
from filetables
where filename = "file1")

You can't select from a table that can only be determined at run time and/or depending on some parameter. Your only option is to use a Dynamic SQL in this case but make sure you don't expose yourself to SQL-Injection attacks.
Here's a link on how to safely create Dynamic SQL.

DECLARE #v_sql NVARCHAR(MAX),
#v_table_name NVARCHAR(MAX),
#v_file_name NVARCHAR(MAX)
SELECT #v_file_name = 'file1' -- Populated from web proc
SELECT #v_table_name = tablename
FROM filetables
WHERE filename = REPLACE(#v_file_name, '''', '')
SELECT #v_sql =
'SELECT *
FROM ' + #v_table_name + '
WHERE filename = ''' + #v_file_name + ''''
SELECT #v_sql -- Debug code to show you the statement prior to running
EXEC sp_executesql #v_sql
You will need to utilize dynamic SQL like other users here have answered. Give this a shot in your environment and see how it goes.

Related

How to check if a column exists in a csv file during sql server OpenRowset?

I got a very tricky question and not sure if there is a way to get it work.
Basically, I have user uploaded a csv file. The first row is header. I need to check if a column name does exists in this csv file. For example I want to know if that csv file has a StudentName column. How do I do that?
I tried to import the file to a temp table. Once I have it in a temp table, I can get everything I need.
select * into #temp
from openrowset('Microsoft.ACE.OLEDB.12.0'
, 'Text; Database='+#folder+'; HDR=NO; IMEX=1;'
,'select top 1 * from ' + #filename)
But that does not work because openrowset cannot have variable in it. In order to make it work, I have to put this whole thing into a #sql variable then exec it.
However, that would not work either because if I do exec (#sql) I cannot use #temp because #temp will not be available after exec(#sql).
Any other way to get this work?
I hope to have some function or stored procedure like this: IsColumnExists(#directory, #filename, #colName)
Thanks.
Great question. I've never had the need to do this, but I can see how useful it could be. I tested this on SQL 2012.
--We'll do this dynamically. Change these values for your scenario.
--If you want to make this into a stored proc, these next two variables would be the sp input params.
DECLARE #Folder NVARCHAR(256) = 'D:\' --Or other folder
DECLARE #FileName NVARCHAR(128) = 'Test.csv' --Or other file.
--Temp table. This will ultimately hold the names of the columns from the OPENROWSET query.
CREATE TABLE #ColNames (name SYSNAME)
--Build tsql string...
DECLARE #Tsql NVARCHAR(MAX) = '
SELECT *
INTO #Temp
FROM OPENROWSET (
''Microsoft.ACE.OLEDB.12.0'',
''Text;Database=' + #Folder + ';HDR=YES'',
''SELECT * FROM [' + #FileName + '] WHERE 1 = 2''
) dt;
SELECT name
FROM tempdb.sys.columns
WHERE object_id = object_id(''tempdb..#Temp'')
'
--...pass string to EXEC
INSERT INTO #ColNames
EXEC (#Tsql)
--Return a resultset of column names.
--Add additional logic to test for presence/absence of specific column.
SELECT *
FROM #ColNames
DROP TABLE #ColNames

Passing Multiple Values to Variable in Linked Server Connection String

I have the following query, which pulls data from an Oracle DB into SQL Server 2005:
SELECT *
FROM (
SELECT *
FROM OPENQUERY(LINKEDSERVERNAME, 'SELECT FOO, BAR, FROM TABLE
WHERE ID IN(' + #IDs + '
')) AS TMP
WHERE SOME_ID IN
(SELECT DISTINCT ID
FROM LOCALTABLE);
The runtime, however, is very long, as the query from the linked server results in a large number of rows. I am only interested in a small number of these rows, however the criteria limiting my query are held in the destination database.
Via another post on SO, I see I could potentially use a variable in dynamic sql that looks like:
DECLARE #IDs AS NVARCHAR(100);
SET #IDs = (SELECT ID FROM LOCALTABLE)
DECLARE #sql AS NVARCHAR(3000);
SET #sql = 'SELECT * FROM OPENQUERY(LINKEDSERVERNAME, ''SELECT FOO, BAR, FROM TABLE
WHERE ID IN(' + #IDs + '))'
EXEC sp_executesql #sql
However, I obviously cannot assign more than one value to the variable, and so the result set only contains results for the final ID placed in #IDs.
What is the best strategy for accomplishing this task for all distinct IDs in the local table?
Anup Shah has already pointed out what is wrong in his comment. Your SELECT assignment will only ever put one value into your variable. You need a way to convert your table results to a CSV style for the IN statement. Pinal Dave has a good post which shows a well known technique for doing this with XML PATH.
http://blog.sqlauthority.com/2009/11/25/sql-server-comma-separated-values-csv-from-table-column/
Worth noting that SELECT #var = #var + var FROM table IS NOT a valid way of doing this, although it may appear to work in some cases.
James

Search of table names

I use the following to search for strings within the stored procedures of a specific database:
USE DBname
SELECT Name
FROM sys.procedures
WHERE OBJECT_DEFINITION(OBJECT_ID) LIKE '%xxx%'
Is it easy to amend the above so that it searches Table names in a specific db "DBname" ?
I'm using this and works fine
SELECT * FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE '%%'
select name
from DBname.sys.tables
where name like '%xxx%'
and is_ms_shipped = 0; -- << comment out if you really want to see them
If you want to look in all tables in all Databases server-wide and get output you can make use of the undocumented sp_MSforeachdb procedure:
sp_MSforeachdb 'SELECT "?" AS DB, * FROM [?].sys.tables WHERE name like ''%Table_Names%'''
You can also use the Filter button to filter tables with a certain string in it.
You can do the same with stored procedures and views.
I am assuming you want to pass the database name as a parameter and not just run:
SELECT *
FROM DBName.sys.tables
WHERE Name LIKE '%XXX%'
If so, you could use dynamic SQL to add the dbname to the query:
DECLARE #DBName NVARCHAR(200) = 'YourDBName',
#TableName NVARCHAR(200) = 'SomeString';
IF NOT EXISTS (SELECT 1 FROM master.sys.databases WHERE Name = #DBName)
BEGIN
PRINT 'DATABASE NOT FOUND';
RETURN;
END;
DECLARE #SQL NVARCHAR(MAX) = ' SELECT Name
FROM ' + QUOTENAME(#DBName) + '.sys.tables
WHERE Name LIKE ''%'' + #Table + ''%''';
EXECUTE SP_EXECUTESQL #SQL, N'#Table NVARCHAR(200)', #TableName;
If you prefer case-insensitive searching:
SELECT * FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME ILIKE '%%'
or
SELECT * FROM INFORMATION_SCHEMA.TABLES
WHERE Lower(TABLE_NAME) LIKE Lower('%%')
Adding on to #[RichardTheKiwi]'s answer.
Whenever I search for a list of tables, in general I want to select from all of them or delete them. Below is a script that generates those scripts for you.
The generated select script also adds a tableName column so you know what table you're looking at:
select 'select ''' + name + ''' as TableName, * from ' + name as SelectTable,
'delete from ' + name as DeleteTable
from sys.tables
where name like '%xxxx%'
and is_ms_shipped = 0;
you can also use the show command.
show tables like '%tableName%'
I want to post a simple solution for every schema you've got. If you are using MySQL DB, you can simply get from your schema all the table's name and add the WHERE-LIKE condition on it. You also could do it with the usual command line as follows:
SHOW TABLES WHERE tables_in_<your_shcema_name> LIKE '%<table_partial_name>%';
where tables_in_<your_shcema_name> returns the column's name of SHOW TABLES command.
You can use below :
Select * from sys.tables where name like '%yourtablename%'
This will working fine....
SELECT * FROM sys.TABLES
WHERE name LIKE '%%'

How can I get tables name from sys.tables and store the output in a variable?

I have written a stored procedure where a table name and database name collect
using cursor from different two tables.
But my problem is when I run a query to find out a table exists in a database or not, then show a error.
Now how can I run the query and store output into a variable?
Declare #table_exist nvarchar(200),#val1 nvarchar(200),#return1 nvarchar(200);
SET #table_exist=
'SELECT 1 FROM '+#db_name+'.sys.tables
where name='+#table_name+'';
EXEC sp_executesql #table_exist,#return1 OUTPUT;
select #return1;
ERROR:
Invalid column name 'table name'
You should use quotename when building dynamic query:
SET #table_exist=
'SELECT 1 FROM '+ quotename(#db_name)+'.sys.tables
where name='+quotename(#table_name)+'';
When facing such an error the best would be to print #table_exists and see what is actually built.
I haven't looked properly at your query. You are missing apostrophes:
SET #table_exist=
'SELECT 1 FROM '+ quotename(#db_name)+'.sys.tables
where name=''' + #table_name +'''';
UPDATE:
When using output variable you should set it in a query:
SET #table_exist=
'SELECT #return1 = 1 FROM ' + quotename(#db_name) + '.sys.tables
where name='''+#table_name+'''';
To prevent result set from returning to client, create temporary table and insert result set into it. In this case this will leave only one result set, the result of select #return1:
declare #tbl table (exist bit)
insert into #tbl
EXEC sp_executesql #table_exist, N'#return1 nvarchar(200) out', #return1 OUT;
select #return1;
It is best to write your query by using ' and " properly . Which makes less mistakes while writing query.
The error on you code is that you are confused by using only '. Best to use ' for variable only.
Write your code as:
"SELECT 1 FROM ' "+#db_name+" '.sys.tables
where name=' "+#table_name+" ' ";

Accessing 400 tables in a single query

I want to delete rows with a condition from multiple tables.
DELETE
FROM table_1
WHERE lst_mod_ymdt = '2011-01-01'
The problem is that, the number of table is 400, from table_1 to table_400.
Can I apply the query to all the tables in a single query?
If you're using SQL Server 2005 and later you can try something like this (other versions and RDMS also have similar ways to do this):
DECLARE #sql VARCHAR(MAX)
SET #sql = (SELECT 'DELETE FROM [' + REPLACE(Name, '''','''''') + '] WHERE lst_mod_ymdt = ''' + #lst_mod_ymdt + ''';' FROM sys.tables WHERE Name LIKE 'table_%' FOR XML PATH(''))
--PRINT #sql;
EXEC ( #sql );
And as always with dynamic sql, remember to escape the ' character.
This will likely fall over if you have say table_341 which doesn't have a lst_mod_ymdt column.