I am using SQL Server 2008 R2 on dev, and SQL Azure for test and live.
I wish to write a little procedure to reset the identity seeds since SQL Azure does not support DBCC.
I have some workaround code which works, but I do not want to write it out for each table, so was trying to write a routine that iterates through the DB tables.
Tables:
SELECT * FROM information_schema.tables
Code:
delete from TABLE_NAME where Id>150000
GO
SET IDENTITY_INSERT [TABLE_NAME] ON
GO
INSERT INTO [TABLE_NAME](Id) VALUES(150000)
GO
delete from TABLE_NAME where Id=150000
GO
SET IDENTITY_INSERT [TABLE_NAME] OFF
GO
I guess I need to wrap this in a loop. Sorry my T-SQL is not that strong, hence the request for help.
Also it would be helpful to omit all tables with TABLE_NAME starting with aspnet_ and use only TABLE_TYPE = "BASE TABLE"
Any help hugely appreciated.
Unless somebody else knows a trick that I don't, you're probably stuck using dynamic SQL and iterating through a list of table names using either a cursor or a temporary table. The cursor approach would look something like this:
declare #TableName nvarchar(257);
declare #sql nvarchar(max);
declare TableCursor cursor read_only for
select
TABLE_SCHEMA + '.' + TABLE_NAME
from
INFORMATION_SCHEMA.TABLES
where
TABLE_NAME not like 'aspnet\_%' escape '\' and
TABLE_TYPE = 'BASE TABLE';
open TableCursor;
fetch next from TableCursor into #TableName;
while ##fetch_status = 0
begin
set #sql = 'select top 1 * from ' + #TableName;
exec sp_executesql #sql;
fetch next from TableCursor into #TableName;
end
close TableCursor;
deallocate TableCursor;
You can read more about cursors here. Alternatively, you could do it with an in-memory table like this:
declare #Tables table (RowId int identity(1, 1), TableName nvarchar(257));
declare #TableName nvarchar(257);
declare #Index int;
declare #TableCount int;
declare #sql nvarchar(max);
insert into #Tables (TableName)
select
TABLE_SCHEMA + '.' + TABLE_NAME
from
INFORMATION_SCHEMA.TABLES
where
TABLE_NAME not like 'aspnet\_%' escape '\' and
TABLE_TYPE = 'BASE TABLE';
set #TableCount = ##rowcount;
set #Index = 1
while #Index <= #TableCount
begin
select #TableName = TableName from #Tables where RowId = #Index;
set #sql = 'select top 1 * from ' + #TableName;
exec sp_executesql #sql;
set #Index = #Index + 1;
end
In the interest of brevity, my examples use a much simpler SQL statement than yours—I'm just selecting one record from each table—but this ought to be enough to illustrate how you can get this done.
Related
I am newbie here. I have many databases in my SSMS, so I need to find the database name using the given table name using stored procedures.
And I am not good at writing SP's and handling errors.
I apologize for my English.
Thank you
I tried it using cursors in stored procedure.
But I am getting errors as I am not good at handling errors.
You could create the stored procedure in the following:
CREATE PROCEDURE sp_Get_Tables
#schema VARCHAR(50) = 'dbo',
#table_name VARCHAR(100) = 'Default_Table_Name'
AS
SELECT name
FROM sys.databases
WHERE CASE WHEN state_desc = 'ONLINE' THEN OBJECT_ID(QUOTENAME(name) + '.' + #schema + '.' + #table_name, 'U') END IS NOT NULL
And execute the stored procedure you can in the following:
EXEC sp_Get_Names 'Schema', 'Table_Name'
Try This:
Create PROCEDURE Pro_FindTable
(#tableName VARCHAR(MAX))
AS
BEGIN
SET NOCOUNT ON;
DECLARE #name VARCHAR(MAX),
#dbid INT;
DECLARE C CURSOR FAST_FORWARD FOR(
SELECT name,
database_id
FROM sys.databases);
OPEN C;
FETCH NEXT FROM C
INTO #name,
#dbid;
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #query NVARCHAR(MAX)
= 'IF EXISTS(SELECT name FROM(SELECT name, COUNT(*)Over(Order By (Select Null)) as RN FROM(SELECT '''
+ #name + ''' AS name UNION ALL SELECT name FROM [' + #name
+ '].sys.tables WHERE type=''U'' AND name = ''' + #tableName
+ ''') as K)as K Where RN>1)
Select '''+ #name + '''';
EXEC (#query);
FETCH NEXT FROM C
INTO #name,
#dbid;
END;
CLOSE C;
DEALLOCATE C;
END;
And call it like this:
EXEC Pro_FindTable 'MyTable'
Result will be all databases which has a table named 'MyTable'
I try this but didn't work
ALTER Procedure [dbo].[SP_TruncateDTS] as
begin
declare #Table Varchar(200)
declare cur1 cursor for
SELECT TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME like '%DTS%' and TABLE_TYPE = 'BASE TABLE'
open cur1
fetch next from cur1 into #Table
while ##FETCH_STATUS <> -1
begin
TRUNCATE TABLE #Table
fetch next from cur1 into #Table
end
close cur1
deallocate cur1
end
You cannot pass identifiers (such as table names, column names, and so forth) as parameters in queries. Instead, you need to use dynamic SQL.
So replace the inner loop with:
declare #sql nvarchar(max);
set #sql = 'TRUNCATE TABLE [Table]';
set #sql = replace(#sql, '[Table]', #table);
exec sp_executesql #sql;
The example below uses the sys.tables catalog view and aggregate string concatenation instead of a cursor for the task.
DECLARE #SQL nvarchar(MAX) = (
SELECT N'TRUNCATE TABLE ' + QUOTENAME(OBJECT_SCHEMA_NAME(object_id)) + N'.' + QUOTENAME(name) +N';'
FROM sys.tables
WHERE name like N'%DTS%'
FOR XML PATH(''), TYPE).value('.', 'nvarchar(MAX)');
EXECUTE sp_executesql #SQL;
In SQL Serveer 2017 and later, you can use STRING_AGG:
DECLARE #SQL nvarchar(MAX) = (
SELECT STRING_AGG ('TRUNCATE TABLE ' + QUOTENAME(OBJECT_SCHEMA_NAME(object_id)) + N'.' + QUOTENAME(name),';')
FROM sys.tables
WHERE name like N'%DTS%'
);
EXECUTE sp_executesql #SQL;
Note that this schema-qualifies names and uses QUOTENAME to handle cases where the name doesn't conform to regular identifier naming rules.
I did this. But unfortunately that return all in many table. I want to return all in one unique table. Maybe using "UNION" but I don't know the way to do.
This is my code:
EXEC sp_msforeachdb 'select ''?''AS "DataBase", s.name, t.name AS "Tables",max(si.rows) as "Rows Line"
from [?].sys.tables t inner join [?].sys.schemas s
on t.schema_id = s.schema_id
inner join [?].sys.partitions si on t.object_id = si.object_id
where t.name like "%ATTACH" group by s.name,t.name'`
You cannot do it in a single query.
You could query the sys.databases table to get a temporary table of all your databases, and then run a dynamic query on each database to store the results of the query in your question all in another temporary table.
Then at the end, you just select all rows from the last temporary table.
I have found finally a solution.i just used a Stored Procedures for having the result i was looking for.So decided to post the answer here maybe that will help someone else.
DECLARE #banco_nome nvarchar(MAX), #tabela_nome nvarchar(MAX)
DECLARE #banco_cursor CURSOR
DECLARE #sqlstatement nvarchar(MAX)
DECLARE #count_sql nvarchar(MAX)
DECLARE #total int
DECLARE #RegistrosFotograficos TABLE
(
DatabaseName nvarchar(max),
TableName nvarchar(max),
Total int
)
SET #banco_cursor = CURSOR FORWARD_ONLY FOR
SELECT name FROM sys.databases
OPEN #banco_cursor
FETCH NEXT FROM #banco_cursor INTO #banco_nome
WHILE ##FETCH_STATUS = 0
BEGIN
SET #sqlstatement = 'DECLARE tabela_cursor CURSOR FORWARD_ONLY FOR SELECT TABLE_NAME FROM ' + #banco_nome + '.INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = ''BASE TABLE'' AND TABLE_NAME LIKE ''%ATTACH'' ORDER BY TABLE_NAME'
EXEC sp_executesql #sqlstatement
OPEN tabela_cursor
FETCH NEXT FROM tabela_cursor INTO #tabela_nome
WHILE ##FETCH_STATUS = 0
BEGIN
SET #count_sql = 'USE ' + #banco_nome + '; SELECT #total=COUNT(1) FROM ' + #tabela_nome;
EXECUTE sp_executesql #count_sql, N'#total int OUTPUT', #total=#total OUTPUT
INSERT INTO #RegistrosFotograficos (DatabaseName, TableName, Total) VALUES (#banco_nome, #tabela_nome, #total);
FETCH NEXT FROM tabela_cursor INTO #tabela_nome
END
CLOSE tabela_cursor;
DEALLOCATE tabela_cursor;
FETCH NEXT FROM #banco_cursor INTO #banco_nome
END
CLOSE #banco_cursor;
DEALLOCATE #banco_cursor;
SELECT * FROM #RegistrosFotograficos
This will list all the tables in a given database and the number of rows in each. Notice the results are in a table named #results:
set nocount on
declare #curtable sysname
declare #prevtable sysname
declare #curcount int
declare #tsql varchar(500)
if object_ID('tempdb..#curtables','U') is not null
drop table #curtables
select name into #curtables
from sys.objects
where type='U'
order by 1
if object_id('tempdb..#results','U') is not null
drop table #results
create table #results(name sysname,numrows int)
select top 1 #curtable=name from #curtables order by name
while (1=1)
begin
set #tsql = 'select '''+quotename(#curtable) +''',count(*) numrows from '+quotename(#curtable)
print #tsql
insert into #results
exec (#tsql)
set #prevtable= #curtable
select top 1 #curtable = name
from #curtables
where name > #prevtable
order by name
if #curtable=#prevtable
break
end
I'm using a linked server and finding it very painful to write queries like this:
select * from [10.150.10.109].lhf.[dbo].[TABLE_NAME]
Is it possible to use a synonym for something like this:
CREATE SYNONYM [DataRelay] FOR [10.150.10.109].[lhf].[dbo]
in order to be able to query like this:
select * from DataRelay.TABLE_NAME
Without the capabilities of Intellisense, this is just painful...
No, there is no short hand for linked servers, however, you can alias tables in your queries to make it a bit easier.
select * from [10.150.10.109].lhf.[dbo].[TABLE_NAME] T
WHERE
T.FieldName=1
OR
T.FieldName=2
Now that I had a minute what I was saying in my comment is that you cannot create a synonym for just part of an object path as you desire. But you can dynamically script the drop and creation of synonyms for any object in your remote database pretty easily. here is an example of how to do if for user tables. For other objects you can use the sys.objects instead of sys.table system view.
Technique key words for more learning. Dynamic SQL, cursor, schema views.
DECLARE #ServerAndDB SYSNAME = '[10.150.10.109].[lhf]'
DECLARE #SynonymSchema SYSNAME = '[syn]'
DECLARE #ObjectPath NVARCHAR(1000)
DECLARE #SynonymName NVARCHAR(1000)
DECLARE CursorName CURSOR FOR
SELECT
#ServerAndDB + QUOTENAME(SCHEMA_NAME(t.schema_id)) + '.' + QUOTENAME(t.name) as ObjectPath
,#SynonymSchema + '.' + QUOTENAME(t.name) as SynonymName
FROM
[10.150.10.109].[lhf].sys.tables t
WHERE
t.type = 'U'
OPEN CursorName
FETCH NEXT FROM CursorName
INTO #ObjectPath, #SynonymName
WHILE ##FETCH_STATUS = 0
BEGIN
BEGIN TRY
DECLARE #SQL NVARCHAR(MAX)
IF EXISTS (SELECT * FROM sys.synonyms WHERE object_id = OBJECT_ID(#SynonymName))
BEGIN
SET #SQL = 'DROP SYNONYM ' + #SynonymName
EXECUTE sp_executesql #SQLString
SET #SQL = ''
END
SET #SQL = 'CREATE SYNONYM ' + #SynonymName + ' FOR ' + #ObjectPath
EXECUTE sp_executesql #SQLString
SET #SQL = ''
END TRY
BEGIN CATCH
--Can do error handling here
END CATCH
FETCH NEXT FROM CursorName
INTO #ObjectPath, #SynonymName
END
CLOSE CursorName
DEALLOCATE CursorName
I have tables like lg-010-a..., lg-010-ac..., and so on, I have abc database,
I have a command window:
drop table from abc where Table_Name like 'lg-010-%'
Will this drop all the tables starting with lg-010-?
Try something like this:
declare #sql varchar(max)
declare #tablenames varchar(max)
select #tablenames = coalesce(#tablenames + ', ','') + Table_Name from INFORMATION_SCHEMA.TABLES
where Table_Name like ('lg-010-%')
set #sql = 'drop table ' + #tablenames
exec (#sql)
This queries the INFORMATION_SCHEMA.TABLES table to retrieve table names that match your criteria, then concatenates them together into a comma delimited string.
This string is than added to a 'Drop table ' statement and executed.
Drop table can take multiple comma delimited table names.
(I had originally had this query sys.tables but some research revealed that while they are currently equivalent, the Information_Schema method is quaranteed to work in future versions)
Unfortunately you can't do it like that. One way is:
SELECT 'DROP TABLE ' + name FROM sysobjects WHERE name LIKE '%lg-010-a%' AND [type] IN ('P')
This will just print out the DROP TABLE statement for each table - you can then copy and paste this output and run it. You can just put an EXECUTE in the loop instead of the PRINT, but I've done it this way so you can see what's going on/check the output first.
I had an issue where the accepted answer was not doing anything. I discovered that I had to add the prefix name of the database to the code to get it to work. If your tables are not dbo.tablename try this.
declare #sql varchar(max)
declare #tablenames varchar(max)
SELECT
#tablenames = COALESCE(#tablenames + ', ','') + 'YourDatabaseName.' + Table_Name
FROM
INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
AND TABLE_NAME LIKE 'AP2%'
AND (RIGHT(TABLE_NAME, 6) < 201708)
SET #sql = 'drop table ' + #tablenames
EXEC (#sql)
GO
Unfortunately you can't do it like that.
One way is:
DECLARE #TableName NVARCHAR(128)
SELECT TOP 1 #TableName = TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE 'lg-010-%'
ORDER BY TABLE_NAME ASC
WHILE (##ROWCOUNT > 0)
BEGIN
PRINT 'DROP TABLE [' + #TableName + ']'
SELECT TOP 1 #TableName = TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE 'lg-010-%'
AND TABLE_NAME > #TableName
ORDER BY TABLE_NAME ASC
END
This will just print out the DROP TABLE statement for each table - you can then copy and paste this output and run it. You can just put an EXECUTE in the loop instead of the PRINT, but I've done it this way so you can see what's going on/check the output first.
CREATE PROCEDURE dbo.drop_MsSqlTables1 #createDate smalldatetime
AS
declare #flag int =1
declare #tname varchar(50)
declare #sql varchar(max)
select row_number() over (order by name) as num, '[dbo].[' + name +']' as table_name into #temp from sys.tables where name like ('EmpInfo_%') and create_date<#createDate
declare #count int = (select count(*) from #temp)
select * from #temp
while #flag <= #count
begin
set #tname = (select table_name from #temp where num = #flag)
set #sql = 'drop table ' + #tname
exec (#sql)
set #flag = #flag+1
end