I restored a database after a server failure and now I'm running into a problem where the table names show as database_user_name.table_name. So when I query something like:
select * from contacts
it doesn't work because it expects it be fully qualified, as in:
select * from user1000.contacts
The problem with this is that I have hundreds of stored procedures that reference the tables with their name, so none of the queries work.
Is there a way to tell SQL Server 2005 to drop the username from the table without changing the user as the owner?
try this advice from the manual:
To change the schema of a table or view by using SQL Server Management Studio, in Object Explorer, right-click the table or view and then click Design. Press F4 to open the Properties window. In the Schema box, select a new schema.
If you are sure none of the tables exist in the dbo schema as well, then you can say:
ALTER SCHEMA dbo TRANSFER user1000.contacts;
To generate a set of scripts for all of the tables in that schema, you can say:
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'';
SELECT #sql = #sql + N'
ALTER SCHEMA dbo TRANSFER user1000.' + QUOTENAME(name) + ';'
FROM sys.tables
WHERE SCHEMA_NAME([schema_id]) = N'user1000';
PRINT #sql;
--EXEC sp_executesql #sql;
(Once you're happy with the PRINT output - acknowledging that it will be truncated at 8K even though the variable really contains the whole script - uncomment the EXEC and run it again. This does not check for potential conflicts.)
But the real fix is to fix your code. You should never say select * from contacts - both the * and the missing schema prefix can be problematic for various reasons.
Related
I have multiple databases to change mode from Single-User to Multi-User.
I can use this to change one database.
USE master;
GO
ALTER DATABASE CDN_Ceramika
SET MULTI_USER;
GO
Is it possible to change mode for few bases or any query, when mode will be change for Multi-User just when a mode is Single-User?
If you are new to database management I'd advise against using sys.sp_MSforeachdb. Despite being undocumented it's a very popular function among DBAs that know and quadruple-check what they're doing. This article explains some of its pitfalls.
It's generally safer to generate the command strings you want to execute with SQL, inspect them, fix any problems and execute the resulting script. Probably inside a transaction if appropriate.
As the article shows sp_MSforeachdb itself queries the sys.databases table. You can do the same, eg with :
select 'ALTER DATABASE [' + name + '] SET MULTI_USER;'
from sys.databases
where name not in ('master','tempdb','model','msdb')
To generate ALTER DATABASE for all the databases you want, whose names match the WHERE clause. You could also write :
select 'ALTER DATABASE [' + name + '] SET MULTI_USER;'
from sys.databases
where name not in ('master','tempdb','model','msdb')
and [user_access_desc] != 'MULTI_USER'
to exclude databases that are already in multi-user mode
You could use the undocumented system procedure sp_msforeachdb:
USE master;
EXEC sys.sp_MSforeachdb 'IF ''?'' NOT IN (''master'',''msdb'',''tempdb'',''model'') BEGIN
ALTER DATABASE ? SET MULTI_USER;
END;';
Right click on the database you wish to change, then click on Properties.
Click on Options and scroll down to the bottom, then set it as can be seen below:
Click OK and it will be set.
I often run into MSSQL databases that have many more tables than are listed in information_schema or systables.
For example, I'm querying a database right now but only getting the tables spt_fallback_db, spt_fallback_dev, spt_fallback_usg, spt_monitor, spt_values. (1)
How does this happen?
And - can it be fixed easily?
(1) I should clarify that this isn't a permissions issue, as I am sysadmin on the database ; there are around 200 tables and I have full permission on all of them.
#DeadZone was right on the money, the query had some issues.
I was using:
DECLARE #command varchar(1000)
SELECT #command = 'SELECT * FROM sysobjects WHERE xtype=''U'' '
EXEC sp_MSforeachdb #command
But it would only show system tables. So then I switched to a more direct query to see what was going on and was able to view the tables:
use MYDATABASENAME;
SELECT * FROM sysobjects WHERE xtype='U'
I Edited my question so it can be clearer,
In sys.server there is a row that called server_id,
I wanted to know if there is any name to get the database name from this server id,
I am working with replication and linked server so i wanted to make a query that takes all the server and get database names,
I dont need all the database that on the server.
Thank you for your help.
Taking your edit into consideration and removing my previous answer, I don't have an exact answer, but some additional metadata that might help: sys.linked_logins, sp_linkedservers.
Perhaps you could just get each linked server name and use OPENQUERY to query the sys.databases catalog on the remote server?
-- this would be done in some kind of loop:
DECLARE #linkedSvrName sysname = (SELECT TOP 1 name FROM sys.servers WHERE server_id > 0);
DECLARE #sql nvarchar(4000) = 'SELECT * FROM OPENQUERY(' + #linkedSvrName + ', ''SELECT name FROM sys.databases'')';
EXEC sys.sp_executesql #sql
(I didn't have any linked server entries to test against to see if this would actually work as expected.)
For decades i've used VIEWs as a synonym:
CREATE VIEW dbo.Banks AS
SELECT *
FROM OtherDatabase.dbo.Banks
i do this so i can abstract where the "real" table is. And when it changes, it's as simple as altering the view:
And this works well. It's doesn't cause the optimizer any issues, and i have been able to edit the view as required.
Synonyms
Starting with SQL Server 2005, Microsoft introduced synonyms:
CREATE SYNONYM dbo.Banks FOR OtherDatabase.dbo.Banks
It seems to work identically to the VIEW approach. Every execution plan i've looked at behaves identically.
Unfortunately it seems that synonyms are unable to provide one of their basic functions, functionality i need:
Provides a layer of abstraction that protects a client application from changes made to the name or location of the base object
You are not able to change where a synonym points. Because there is no ALTER SYNONYM statement, you first have to drop the synonym and then re-create the synonym with the same name, but point the synonym to the new location.
Do they have any redeeming quality?
Practically speaking, this isn't going to happen. i will just never do it. i won't use a mechanism that requires me to drop objects from a database in order to change a setting. i'm certainly not going to delete all the easily alterable VIEWs, replacing them with SYNONYMs, and have to explain to everyone why making everything harder is "better".
So my question is, is there anything i am losing by using views?
every execution plan looks identical to synonyms
i can easily change the "view synonym" at any time
Is there a virtue to a table or view synonym that i'm missing?
Aside from having to call RefreshAllViews in case i forgot that i made a table change somewhere
Even stored procedures
i don't even use synonyms for stored procedures:
CREATE PROCEDURE dbo.GetUSDNoonRateAsOf #tradeDate datetime AS
EXECUTE OtherDatabase.dbo.GetUSDNoonRateAsOf #tradeDate
Is there a value in synonyms that i am missing?
Update: RefreshAllViews procedure
We have a standard procedure in every database. Reordering, or inserting, columns wreaks havoc on views; so they have to be "refreshed".
CREATE PROCEDURE [dbo].[RefreshAllViews] AS
-- This sp will refresh all views in the catalog.
-- It enumerates all views, and runs sp_refreshview for each of them
SET NOCOUNT ON
DECLARE abc CURSOR FOR
SELECT TABLE_NAME AS ViewName
FROM INFORMATION_SCHEMA.VIEWS
ORDER BY newid()
OPEN abc
DECLARE #ViewName varchar(128)
--DECLARE #ParmDefinition NVARCHAR(500)
-- Build select string once
DECLARE #SQLString nvarchar(2048)
--SET #SQLString = N'EXECUTE sp_RefreshView #View'
--SET #ParmDefinition = N'#View nvarchar(128)'
FETCH NEXT FROM abc
INTO #ViewName
WHILE ##FETCH_STATUS = 0
BEGIN
IF #ViewName <> 'IndexServerNodes'
BEGIN
SET #SQLString = 'EXECUTE sp_RefreshView '+#ViewName
PRINT #SQLString
EXECUTE sp_ExecuteSQL #SQLString--, #ParmDefinition, #View = #ViewName
END
FETCH NEXT FROM abc
INTO #ViewName
END
CLOSE abc
DEALLOCATE abc
God knows why SQL Server doesn't do it for me.
A synonym is a much more transparent redirect. I prefer them over views because views need to be maintained. When you use SELECT * especially.
I'm not sure I buy that the lack of ALTER SYNONYM is a real blocker. The drop/create of a synonym is a very simple metadata operation, and will be very fast. Omitting error handling for brevity:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
DROP SYNONYM ...
CREATE SYNONYM ...
COMMIT TRANSACTION;
Similarly, for stored procedures, if your base stored procedure interface changes (say, you add a parameter), you have to also change the wrapper procedure - not so with a synonym.
One downside is that you can create, say, an instead of trigger on a view, but you can't on a synonym. There are other operations you can't perform via a synonym (mostly DDL). And of course IntelliSense may not function correctly, depending on version.
Not being able to memorize the syntax seems like a made-up excuse to me. There are no fancy options or with clauses; just a 2-part name for the synonym, and a 2-, 3- or 4-part name for the object it refers to:
CREATE SYNONYM dbo.Something FOR Server.Database.dbo.SomethingElse;
If you can't memorize that, how did you create the synonym in the first place?
I also have a suggestion to thoroughly simplify your stored procedure (and prevent it from failing when any view is not in the dbo schema, or the procedure is executed by someone whose default schema is not the same as the view's schema, or the view has an ' or space in its name, or otherwise breaks any of the rules for identifiers (you can find them on this page)):
CREATE PROCEDURE [dbo].[RefreshAllViews]
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sql NVARCHAR(MAX) = N'';
SELECT #sql += '
EXEC sp_refreshview ' + CHAR(39)
+ QUOTENAME(REPLACE(s.name,'''',''''''))
+ '.' + QUOTENAME(REPLACE(v.name,'''','''''')) + CHAR(39) + ';'
FROM sys.views AS v
INNER JOIN sys.schemas AS s
ON v.[schema_id] = s.[schema_id];
PRINT #sql;
EXEC sp_executesql #sql;
END
GO
At the very least, if you're going to keep the cursor, stop using the terrible default options (declare the cursor as LOCAL FAST_FORWARD), and use sys.views instead of INFORMATION_SCHEMA.
God knows why SQL Server doesn't do it for me.
Because SQL Server is software, and it isn't perfect - especially when it comes to dependencies. The main problem is that you are violating a best practice by using SELECT * in your views in the first place. shrug If you would accept your hang-ups about synonyms, you won't have to worry about that.
If a view references a table, and you subsequently add columns to that table, you must modify the view in order to “pick up” the new column—even if you use SELECT *. Synonyms will “pick up” those columns automatically. Here’s a sample script:
-- Set things up
CREATE TABLE Foo
(
Id int not null
,data varchar(10) not null
)
GO
INSERT Foo values (1,'one'),(2,'Two')
GO
CREATE SYNONYM synFoo for Foo
GO
CREATE VIEW vFooDelim as select Id, Data from Foo
GO
CREATE VIEW vFooStar as select * from Foo
GO
select * from Foo
select * from synFoo
select * from vFooDelim
select * from vFooStar
then,
-- Add a column
ALTER TABLE Foo
add MoreData datetime default getdate()
GO
select * from Foo
select * from synFoo
select * from vFooDelim
select * from vFooStar
GO
(don’t forget to)
-- Clean things up
DROP Synonym synFoo
DROP VIEW vFooDelim
DROP VIEW vFooStar
DROP TABLE Foo
A significantly more obscure situation (that we do all the time here), if you have to set up a reference in a database to an object in another database, you don’t necessarily know what columns are in that table (dynamic denormalized) are or will be, and you don’t know the name of the database at the time you write your code (one database per client, but only once they sign the contract) (usually), using synonyms can be a godsend. At the time of database creation, just dynamicaly build and run CREATE SYNONYM myTable FOR <DatabaseName>.<schema>.MyTable, and you are done—no matter what columns get added for which client in the future.
Synonyms are useful for situations where you're working with lots of disparate data sources/multiple databases etc, or doing data migrations.
I've never really found cause to use them in new, greenfield developments.
I'm looking to query all databases mapped to a user, similar to Security > Logins > Properties > User Mapping.
This may be done in SQL 2005 if possible
For example, something similar to:
SELECT name
FROM sys.databases
WHERE HAS_DBACCESS(name) = 1
But perform the query from an administrative user, as opposed to running the above query as the user itself.
How would something like this be performed?
Thank you.
Well this might be a start, probably not the nice output you'd hope for (and it produces two resultsets):
EXEC sp_helplogins N'floob';
But it does work on SQL Server 2000. If you want to try and replicate some of the functionality in the procedure, you can see how it's checking for permissions, basically a cursor through every database. On SQL Server 2000:
EXEC sp_helptext N'sp_helplogins';
On 2005+ I much prefer the output of OBJECT_DEFINITION():
SELECT OBJECT_DEFINITION(OBJECT_ID(N'sys.sp_helplogins'));
So you could write your own cursor based on similar logic, and make the output prettier...
Here is a quick (and not complete) example, doesn't cover much but an idea to get started if the above is not sufficient:
DECLARE #login NVARCHAR(255);
SET #login = N'foobarblat';
-- above would be an input parameter to a procedure, I presume
CREATE TABLE #dbs(name SYSNAME);
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'';
SELECT #sql = #sql + N'INSERT #dbs SELECT ''' + name + ''' FROM '
+ QUOTENAME(name) + '.sys.database_principals AS u
INNER JOIN sys.server_principals AS l
ON u.sid = l.sid
WHERE l.name = #login;'
FROM sys.databases
WHERE state_desc = 'ONLINE'
AND user_access_desc = 'MULTI_USER';
EXEC sp_executesql #sql, N'#login SYSNAME', #login;
SELECT name FROM #dbs;
DROP TABLE #dbs;
As I said, this is not complete. Won't know if the user has been denied connect, is member of deny reader/writer roles, won't show the alias if the user name in the db doesn't match the login, etc. You can dig into more details from sp_helplogins depending on what you want to show.
The EXECUTE AS functionality was added in the 2005 release, so I don't think you can run that in 2000. You could probably mimick it by putting the relevant code in a job and setting the job owner to an admin user, but it would process with the job not inline.