I have a question about select in SQL Server.
First I'm getting columns name from temp table with proper type query looks like this:
select
sc.name, st.name
from
tempdb.sys.columns sc
left join
sys.types st on sc.system_type_id = st.system_type_id
where
object_id = object_id('tempdb..#_tmpDocs')
and st.name in ('char', 'varchar', 'nvarchar')
Result is a list of columns with type I want, but next I want to select those columns in different query so if ill save result from above query into temp table with name #columns with it be possible to do something like
select (select * from #columns) from target_table
Here's a dynamic sql that will do what you need:
CREATE TABLE #_tmpDocs (id INT, x CHAR(10), y VARCHAR(100))
DECLARE #cols NVARCHAR(1000)
DECLARE #sql NVARCHAR(1000)
SELECT #cols = COALESCE(#cols + ',', '') + QUOTENAME(SC.name)
FROM tempdb.sys.columns sc
LEFT JOIN sys.types st ON sc.system_type_id = st.system_type_id
WHERE object_id = OBJECT_ID('tempdb..#_tmpDocs')
AND st.name IN ( 'char', 'varchar', 'nvarchar' )
SET #sql = 'select ' + #cols + ' from #_tmpDocs'
PRINT #sql
EXEC (#sql)
EXEC sp_executesql #sql
Chose between EXEC (#sql) and EXEC sp_executesql #sql based on you needs - see here to get an idea of what each is doing.
I don't think you can reference columns dynamically in SQL like that. Just doing a pure sql version, it won't work:
declare #x varchar(50) = 'MyColumn';
select #x from dbo.MyTable
You'll need to use dynamic sql, and build a string:
declare #x nvarchar(50) = 'MyColumn';
declare #y nvarchar(250) = 'select ' + #x + ' from dbo.MyTable';
EXECUTE sp_executesql #y
So in your case you may want to loop through your return result or otherwise turn it into a string of column names that can be concatenated to a larger query (like above).
Did you try this?
SELECT *
FROM tempdb.sys.columns
WHERE object_id = object_id('tempdb..#columns');
Related
I would like to use a query to loop through tables that are similar in names but added a number after that (ie. tableJan01, tableJan02, tableJan03, etc..., tableJan30)
Is there a way in SQL Server to use the same query statement while varying the table name within it. (similar to using parameter values) (need this to add different input to each different month's table)
declare #x nvarchar(50) ='abc'
declare #z int =1
while (#z<30)
BEGIN
SET #z = #z + 1;
select * from (#x)
END;
this shows error
Must declare the scalar variable "#CharVariable".
this script shows too syntax error
declare #x nvarchar(50) ='abc'
declare #z int =1
while (#z<30)
BEGIN
SET #z = #z + 1;
select * from (#x+#z)
END;
also, simple code like this doesn't work too
declare #x nvarchar(50) ='abc'
select * from #x
I agree with John Cappelletti that this requirement feels like a design flaw, however, to get your list of table names you can do something like this:
declare #x nvarchar(50) ='abc'
declare #z int =1
declare #ListOfTableNames TABLE (TableName nvarchar(50));
while (#z<30)
BEGIN
SET #z = #z + 1;
INSERT INTO #ListOfTableNames (TableName) VALUES (#x + CONVERT(NVARCHAR(20), #z))
END
SELECT * FROM #ListOfTableNames
To do dynamic SQL on these tables you could build a query string and then pass that string to the sp_executesql proc. You could put that logic in place of the line where we populate the table variable with the numbered table names. Like this:
declare #x nvarchar(50) ='abc'
declare #z int =1
declare #sql NVARCHAR(100)
while (#z<30)
BEGIN
SET #z = #z + 1;
SET #sql ='SELECT * FROM '+ (#x + CONVERT(NVARCHAR(20), #z))
EXEC sp_executesql #sql
END
I would completely avoid a WHILE loop just use some pattern matching:
DECLARE #Prefix sysname = N'abc';
DECLARE #SQL nvarchar(MAX),
#CRLF nchar(2) = NCHAR(13) + NCHAR(10);
SET #SQL = STUFF((SELECT #CRLF +
N'SELECT *' + #CRLF +
--N' ,N' + QUOTENAME(t.[name],'''') + N' AS TableName' + #CRLF + --Uncomment if wanted
N'FROM ' + QUOTENAME(s.[name]) + N'.' + QUOTENAME(t.[name]) + N';'
FROM sys.schemas s
JOIN sys.tables t ON s.schema_id = t.schema_id
WHERE t.[name] LIKE #Prefix + '%'
AND t.[name] NOT LIKE #Prefix + N'%[^0-9]'
ORDER BY t.[name]
FOR XML PATH(N''),TYPE).value('.','nvarchar(MAX)'),1,2,N'');
--PRINT #SQL;
EXEC sp_executesql #SQL;
DB<>Fiddle
But John is right, you certainly have a design flaw here.
Using dynamic SQL, it would look something like this:
declare
#Base_table_name nvarchar(50) = 'my_table'
,#Step int = 1
,#SQL nvarchar(max);
while(#Step < 30)
begin
set #SQL = 'select * from ' + #Base_table_name + right('00' + cast(#Step as nvarchar(50)),2);
print(#SQL); --this displays the SQL that would be run
--exec(#SQL) --uncomment this to run the dynamic SQL
set #Step+=1;
end;
Alternatively, you can be more precise by using the sys.schemas and sys.tables tables like so:
declare
#Base_table_name sysname = 'my_table'
,#schema_name sysname = 'my_schema'
,#Step int = 1
,#StepCount int = 0
,#SQL nvarchar(max);
/* This will create a table variable and populate it with all the tables you'll want to query */
declare #tables_to_query table (Step int identity, SchemaName sysname, TableName sysname);
insert into #tables_to_query(SchemaName, TableName)
select
s.name
,t.name
from
sys.schemas s
inner join
sys.tables t on s.schema_id = t.schema_id
where
s.name = #schema_name --this will limit the tables to this schema
and t.name like #Base_table_name + '%' --this will look for any table that starts with the base table name
/* this loops through all the tables in the table variable */
while(#Step <= #StepCount)
begin
select
#SQL = 'select * from ' + quotename(SchemaName) + '.' + quotename(TableName)
from
#tables_to_query
where
Step = #Step
print(#SQL); --this displays the SQL that would be run
--exec(#SQL) --uncomment this to run the dynamic SQL
set #Step+=1;
end;
The dynamic SQL approaches laid out in other answers will certainly get the job done for you, but if you find you're querying all of these tables frequently, it might server you well to build out a VIEW and query that as needed.
In keeping with Larnu's suggestion of putting the source table name into the result set, I'd probably do something like this:
CREATE VIEW dbo.vwJan
AS
SELECT
'tableJan01' AS SourceTable,
<Column List>
FROM dbo.tableJan01
UNION ALL
...<28 other iterations>
SELECT
'tableJan30' AS SourceTable,
<Column List>
FROM dbo.tableJan30;
From there, you can go ahead and query them all to your heart's content with a single statement.
SELECT
SourceTable,
<Any other columns you're interested in>
FROM
vwJan;
I need to prepare a dynamic query to find the length of all the rows in a column in sql server. let say if there are 10 columns for a table with 100 rows. I need to find the row length for each column dynamically.
Assuming that your all columns are string columns, though len function should work anyways.
-- replace 'mytable' with the actual table name
declare #tableName nvarchar(128) = 'mytable';
declare #queryToRun nvarchar(max) = '';
-- IMPORTANT: following query is putting each column name as len_columnName
select #queryToRun = #queryToRun + ', len([' + c.name + ']) as [len_' + c.name + ']
'
from sys.tables as t
inner join sys.columns as c on t.object_id = c.object_id
where t.name = #tableName
-- removing the first comma
set #queryToRun = SUBSTRING(#queryToRun, 2, len(#queryToRun) - 1);
-- creating the query with dynamic column names
set #queryToRun = 'select ' + #queryToRun + ' from ' + #tableName;
--print #queryToRun
exec (#queryToRun)
you can use sys.tables and sys.all_columns
declare #Sql nvarchar(max)='select '
select #Sql=#sql+'Sum(len('+QUOTENAME(c.name)+')) as Len'+QUOTENAME(c.name)+',' from sys.tables t join sys.all_columns c on t.object_id=c.object_id
where t.Name='YourTableName'
set #Sql = left(#Sql,len(#sql)-1)+' from YourTableName'
select #Sql
Try this Script you will get data length of each columns in table dynamically
IF OBJECT_ID('dbo.LenghtOfRows')IS NOT NULL
DROP TABLE LenghtOfRows
CREATE TABLE LenghtOfRows (
Id Int IDENTITY,
Sqlode nvarchar(max)
)
DECLARE #SQL NVARCHAR(max),
#MinId INT,
#MaxId INT,
#tableName Varchar(100) ='StudentLabExamScore', --Give Table name here
#GetSQL NVARCHAR(max)
SET #SQL = 'SELECT ''SELECT DATALENGTH(''+COLUMN_NAME+'') As Len_'' +COLUMN_NAME +'' FROM ''+TABLE_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = '''+#tableName+''''
PRINT #SQL
INSERT INTO LenghtOfRows(Sqlode)
EXEC ( #SQL)
SELECT #MinId = MIN(Id) from LenghtOfRows
SELECT #MaxId = MAX(Id) from LenghtOfRows
WHILE (#MInId <=#MaxId)
BEGIN
SELECT #GetSQL= Sqlode FROM LenghtOfRows WHERE id=#MInId
EXEC (#GetSQL)
PRINT #GetSQL
SET #MInId=#MInId+1
END
I have this table with this as name of the columns :
Name, Birthday, Year, Size
And I want to add a prefix to every column like this:
NY_Name, NY_Birthday, NY_Year, NY_Size
Obviously I have more columns than these 4, so this is the reason why I ask you for a query - how to add a prefix to column names with SQL Server?
Thank you very much ! :)
One idea is to generate a script from the table catalog (SELECT name FROM sys.objects WHERE type = 'U'), using the following procedure sp_rename (Transact-SQL)
for example:
USE DB;
GO
EXEC sp_rename 'Table.Name', 'NY_Name', 'COLUMN';
GO
One way to get it would be to use dynamic SQL, but try to avoid doing that if you can help it.
Here's one way:
/* --create table to test
CREATE TABLE dbo.WTF (
Name VARCHAR(10),
Birthday VARCHAR(10),
Year VARCHAR(10),
Size VARCHAR(10)
)
*/
DECLARE #prefix VARCHAR(10) = 'NY_'
DECLARE #sql NVARCHAR(1000) = N'';
DECLARE #columns VARCHAR(1000) = '';
SELECT #columns = #columns + c.name + ' ' + QUOTENAME(#prefix + c.name) + ',
'
FROM sys.tables t
INNER JOIN sys.columns c
ON t.object_id = c.object_id
WHERE t.name = 'WTF'
ORDER BY c.column_id
set #columns = left(#columns, len(#columns) - 3) --remove last comma and cr lf
set #sql = N'SELECT
' + #columns + '
FROM dbo.WTF'
select #sql
exec sp_executesql #sql
This returns:
SELECT
Name [NY_Name],
Birthday [NY_Birthday],
Year [NY_Year],
Size [NY_Size]
FROM dbo.WTF
NY_Name NY_Birthday NY_Year NY_Size
---------- ----------- ---------- ----------
Good luck!
I need to run some SQL which will return my columns from a table.
I need to use these columns in an INSERT statement.
I could run:
select *
from information_schema.columns
where table_name = 'tableName'
but I need to print something like this:
[table.custid], [table.address], [table.name]
I thought you may need them to use for example with dynamic sql, you can get the list of column in the format you want as:
DECLARE #ColNames VARCHAR(1000)
SELECT #ColNames = COALESCE(#ColNames+', ', '') + QUOTENAME('tableName.'+NAME,'[')
FROM SYS.COLUMNS
WHERE OBJECT_id = OBJECT_id('tableName')
SELECT #ColNames
Edit summary: adding tablename prefix to columns as wanted in question
Try this
SELECT * FROM SYS.COLUMNS
WHERE object_id = OBJECT_ID('dbo.TableName')
DECLARE #sql as VARCHAR(8000)
SET #sql = ' '
SELECT #sql += '[table.'+[Name] + '],' FROM SYS.COLUMNS
WHERE object_id = OBJECT_ID('dbo.TableName')
PRINT(#sql)
I have multiple table names like g_str_a , g_str_ab , g_str_abc . I would like to drop all those tables that start with g_str on SQL Server 2008.
Will DROP Tables like 'g_str' help?
Please help me with the script.
SELECT
'DROP TABLE ' + QUOTENAME(SCHEMA_NAME(schema_id)) + '.' + QUOTENAME(name) + ';'
FROM sys.tables
WHERE name LIKE 'g\_str%' ESCAPE '\'
Then review the script and run it.
You can also concatenate the result into a single string and execute with EXEC if you need an entirely automated solution.
You could use dynamic SQL:
DECLARE #SQL NVARCHAR(MAX) = '';
SELECT #SQL = #SQL + 'DROP TABLE ' + QUOTENAME(SCHEMA_NAME([Schema_ID])) + '.' + QUOTENAME([name]) + ';'
FROM sys.tables
WHERE Name LIKE 'g\_str%' ESCAPE('\');
EXECUTE SP_EXECUTESQL #SQL;
Following query will delete tables automatically:
BEGIN TRANSACTION
DECLARE #tmpTablesToDelete TABLE (
RowNumber INT PRIMARY KEY
,Query NVARCHAR(MAX)
)
INSERT INTO
#tmpTablesToDelete
SELECT
RowNumber = ROW_NUMBER() OVER (ORDER BY (SELECT (0)))
,'DROP TABLE '+schemas.name+'.'+objects.name AS Query
FROM
sys.objects
INNER JOIN
sys.schemas
ON
schemas.schema_id = objects.schema_id
WHERE
type = 'U' AND objects.name like 'g_str%'
DECLARE #Counter INT
SELECT #Counter = MAX(RowNumber) FROM #tmpTablesToDelete
WHILE(#Counter > 0) BEGIN
DECLARE #Query NVARCHAR(MAX)
SELECT #Query = Query FROM #tmpTablesToDelete WHERE RowNumber = #Counter
PRINT #Query
EXEC sp_executesql #statement = #Query
SET #Counter = #Counter - 1
END
COMMIT TRANSACTION