I have many different application databases with a [Log] table. I have one central database with a similar log table, but with one extra column called TenantId. There is also a Tenant table with a TenantId and a DatabaseName column. These DatabaseName contain the names of the application databases.
Now I want to loop all the application databases and copy the log entries to the central log table, with the TenantId that belongs to the application database name.
Would it be possible to write one procedure in the central database instead of creating many procedures in the application databases? All databases are on the same SQL Server instance.
Just some quick Dynamic SQL. In the example below, CHINRUS is my central database and would therefore be excluded from consolidation.
I should add, that the WHERE should be tailored to exclude any misc database on the server. Yet another option would be to maintain a table which has the proper definitions.
Declare #LogTable varchar(100)='[Chinrus].[dbo].[TransactionLog]'
Declare #CentralDB varchar(100)='Chinrus'
Declare #SQL varchar(max) = ''
Select #SQL = #SQL + SQL
From (
Select Name,SQL=';Insert Into '+#LogTable+' Select *,TenantId='''+Name+''' From ['+Name+'].[dbo].[TransactionLog] '
From master.dbo.sysdatabases
Where Name<>#CentralDB
) A
Select #SQL
--Exec(#SQL)
You can get list of all databases with following query:
SELECT name
FROM master.dbo.sysdatabases
and then you can use a cursor to get each database data and insert in one table in current database.
Related
I want to create 50 databases for 50 states dynamically and insert records of table factinternetsales from adventureworksdw database to related state database, how can I write sql script or built ssis pacakge
Have a look at "dynamic sql". Start with the database like so:
declare #stateName varchar(50) = 'MyState';
declare #cmd varchar(max) = 'create database ' + #stateName + ';';
execute (#cmd);
If you have your states in a table, you can loop over them by using a cursor and this kind of dynamic sql. After creating the databases you can create tables and do INSERTs in the same way.
I need to run a SELECT query on a SQL Server and return info pulled from multiple databases on the same server. I have the following, which could work:
SELECT [Name], [Nationality]
FROM [dbtest].[dbo].[Staff]
WHERE Nationality = 'Canadian'
Union all
SELECT [Name], [Nationality]
FROM [dbtest2].[dbo].[Staff]
WHERE Nationality = 'Canadian'
etc..
The problem is I have 2000 databases to query and it will almost certainly be added to in future, meaning the query will need editing.
What I really need is a wildcard for the database name.
ie:
*.[dbo].[Staff]
but this gives me an error. Even if it worked, not all databases have the same tables, so is likely to error anyway.
Any way I can do this without typing out the above example 2000 times ?
You can build the statement dynamically
DECLARE #Query varchar(max) = ''
SELECT #Query = COALESCE(#Query + ' UNION ALL ', '') + 'SELECT [Name], [Nationality] FROM [' + TABLE_CATALOG+'].dbo.[Staff] WHERE Nationality = ''Canadian'''
FROM information_schema.tables
WHERE table_name = 'Staff'
SET #Query = STUFF(#Query, CHARINDEX('UNION ALL', #Query), 10, '')
PRINT #Query
EXEC(#Query)
One way of doing that is to generate query on the fly.
Either by querying information_schema DMV as in #Yosi answer or by using your own metadata table (in case tables can have different names in different databases or there are any other significant differences in table's schema) :
Create some master database and create table here which will contain list of all other databases - mainly DB name but you can include any other information describing differences (and use this data during query generation). You can add more (or delete) database "definitions" here.
Create stored procedure which will iterate master table and generate query on the fly
Execute query using sp_exec
i have a demo database, which would be used by many users concurrently. Users can query and modify the data, and query those modified data. but other users should see the changes only made by themselves. when user logs out, i would clear all those changes made by that user.
i know i can just copy the database, and connect to different databases when user log in. but if there 're too many users, i would end up getting a lot of databses in one single server.
i wonder if there's any convinient way to do that.
What about creating Temp tables in SQL
and as soon as the user logout just drop them off.
to create a temp table from your original table
Declare #usera varchar(10)
set #usera = 'Ham'
Declare #sql varchar(70)
set #sql = 'use NorthTemp select * into ##temptable_' + #usera + ' from originaltable'
exec (#sql)
and allow users to work with the TempTables
am using ## so that the table is global
Given a multi-tenant setup with one database that holds the tenant data, and one database for each tenant, how can you construct a query to look up the same piece of data in each tenant database?
eg The tenant master database has a table called Tenants:
[TenantMaster].[dbo].[Tenants]
Id, Name, DatabaseName
1, Bob, bobs_db_name
2, Kate, kates_db_name
And each individual tenant has a table called Widgets:
[bobs_db_name].[dbo].[Widgets]
Id, Name
1, Red widget
Is it possible to write a select query to get the count of widgets in each tenant DB? Or does it require a cursor or a store procedure? eg the output would be:
Tenant, WidgetCount
Bob, 10
Kate, 12
In a multi-tenancy setup, I'd recommend considering caching these "across-the-board" stats in a central database and updating it periodically
e.g. a table in the master with following columns:
TenantId
WidgetCount
AsOfDate
That way, you can query the stats very quickly without hitting each database (but obviously the data may be out of date depending on the frequency of the update).
For scaling in a multi-tenancy system, I recommend this approach. But it does depend (as always) on exact requirements/whether you can live with slightly out of date stats etc.
create table #TenatsWidjetCount
(
TenantID int,
TenantName nvarchar(100),
Count int
)
Insert into #TenatsWidjetCount(TenantID,TenantName)
select ID,Name from Tenants
Decalre #Dbname navarchar(100)
Declare #Min Int;
Declare #Max Int;
set #Min=(Select min(TenantID ) from #TenatsWidjetCount )
set #Max=(Select max(TenantID ) from #TenatsWidjetCount )
while(#Min<=#Max)
Begin
print #min
set #dbName=(Select DatabaseName From Tenant Where ID=#Min)
Decalre #Dbname navarchar(100)
Declare #Selectstring nvarchar(max);
set #Selectstring='Update #TenatsWidjetCount
set Count=(select count(*) from '+#DBname+'.dbo.Widjets)'
print #Selectstring
execute sp_executesql #query=#Selectstring
print #Selectstring
set #min=#min+1
print #min
end
select * from #TenatsWidjetCount
we first load the data to a temp table..using the temptable i run a loop so i get count from each widjet table in the list of databases listed in the Tenant table..
You would need to use dynamic SQL if you have a list of tenants which will grow / shrink over time. Alternatively you could, when tenants are added or deleted, use dynamic SQL to generate views which reference each of the databases in question.
If you want to look in a specific database, but you don't know where to target that database yet, then you can use a synonym to achieve a similar result, as synonym targets are bound at execute time, and not create time.
I have two databases, lets say Database A and B, with different datastructures.
In Database A there is a table contacts.
In Database B there is a table Accounts.
I want to transfer data from Database A table contacts to Database B table Accounts.
I am use SQL Server 2005 and want to write sql scripts to do this.
Can someone tell me what's the easiest and most efficient way to achieve this:
a) If they are on the same SQL server
b) If they are on different SQL servers.
The easiest method isn't necessarily the most efficient. SSIS is likely the most efficient, as Mitch already indicated.
The easiest (if you don't know SSIS already) is to just set up a linked server to the remote DB, and SELECT the data across using four-part naming. You set up a linked server using sp_addlinkedserver and sp_addlinkedsrvlogin (check BOL for the syntax), and query as follows:
INSERT INTO MyLocalTable (ColumnList)
SELECT <Columns> FROM RemoteServer.RemoteDB.RemoteSchema.RemoteTable
Use SSIS. It will work for both local and remote cases, and will enable you to set up a transform between the tables, to map columns to lother columns etc.
Is it a one off transfer? If it's a simple transfer I write a SELECT statement to create the INSERT statements, i.e.
SELECT 'INSERT INTO Accounts (ID, Name) VALUES (' + CAST(ID as VARCHAR) + ', ''' + Name + ''')'
FROM Contacts
Run this on Database A - and it will spit out the all INSERT statements, which you copy and paste so you can run them on Database B.
Or, on the same database:
INSERT INTO DatabaseA.dbo.Accounts (ID, Name)
SELECT Id, Name
FROM DatabaseB.dbo.Contacts
Still not happy - try setting up linked servers: http://msdn.microsoft.com/en-us/library/aa213778(SQL.80).aspx