I have got a script of stored procedure from my senior, like :
BEGIN
EXEC dbo.sp_executesql #statement = N'create procedure [dbo].[up_transfer_data_from_isfoc_to_unicode_sp]
as
begin
declare #errx as int
begin try
truncate table u_lrc..dir
truncate table u_lrc..k_2
truncate table u_lrc..k_name
truncate table u_lrc..k_gata
truncate table u_lrc..order1
truncate table u_lrc..remark
insert into u_lrc..dir
select code,[lrc].name
from lrc..dir
Where dir, K_2, k_name and others are Table names whereas lrc and u_lrc are databases. u_lrc is a copy of lrc database.
What is (..) is doing here and examples of its usage ?
SQL Server uses three (really four) part naming for objects stored in the database -- tables, functions, stored procedures, and so on. This is explained in the documentation.
The three part names are ...
Typing the schema name gets cumbersome and many people just use the default schema of dbo.
So, the .. is a reference to the table in the u_lrc database using the default schema.
I should point out that the fourth part is optional (as are the second and third parts). It is for the server name.
Related
I have a database creation script that sets up tables, stored procedures, views, etc. When I change the type of a column in a create table statement, I want this change to be reflected in the create stored procedures / views / etc statements that reference that table without having to go through and manually change each one.
In other words I want my stored procedures to automatically determine the column type based on another column's type on creation. I don't need this to work on a live database with data, just while I'm iterating over the design and prototyping.
Something like a TYPE_OF() in this (fictional) example:
create table Logs
(
id int identity(1, 1) primary key,
userName varchar(32),
logType int foreign key references LogType(id),
description varchar(128),
datestamp datetime
);
go
create procedure WriteLog
(
#userName TYPE_OF(Logs.userName), -- should be varchar(32),
#logType int,
#description TYPE_OF(Logs.description) -- should be varchar(128)
)
as
begin
insert into Logs
values(#userName, #logType, #description, SYSDATETIME());
end
go;
I think I remember something similar from Oracle / SQL Plus / PLSQL but I am having trouble finding it.
I'm using SQL Server Management Studio v18.4
Not sure if the TYPEOF feature you're looking for exitsts, but you could try and use a DDL Trigger to keep your procedure in sync with the column type changes.
This trigger would get fired every time a table is altered and you'd just have to parse the EVENTDATA() to see if the column types in the Logs table have changed. The body of your trigger would look something like this:
CREATE TRIGGER OnLogsChanged
ON DATABASE
FOR ALTER_TABLE
AS
BEGIN
-- 1. Parse EVENTDATA() to see if the Logs table was altered
-- 2. If it has, store the definition of the WriteLog procedure into a variable by reading it from sys.procedures
-- 3. Read the new types for the columns of the Logs table from sys.all_columns
-- 4. replace the parameter declarations in the procedure definition to match the new types in the Logs table
-- 5. alter the procedure with the new definition by building up the ALTER PROCEDURE statement as a string and executing it with sp_executesql
END
As long as the trigger stays enabled your procedure should stay in sync with the table column types.
I have inherited a database that contains a lot of stored procedures that create a local temporary table, calls a procedure that uses the temp table, and then deletes the temp table. Like this:
CREATE PROCEDURE procSelectFromTable
AS
BEGIN
SELECT *
FROM #myTable
END;
GO
CREATE PROCEDURE procMakeTable
AS
BEGIN
SELECT 1 AS [ID]
,'NestedProcedure' AS [Message]
INTO #myTable;
EXEC procSelectFromTable
DROP TABLE #myTable;
END;
GO
EXEC procMakeTable;
GO
--Clean up
IF OBJECT_ID('tempdb..#myTable') IS NOT NULL
DROP TABLE #myTable;
DROP PROCEDURE procMakeTable;
DROP PROCEDURE procSelectFromTable
I have not seen procedures written in this manner before. Is it safe for me to assume this is ok because the nested procedure will always be called in the same spid and will always be able to access the temp table?
Yes, the nested procedure will have access to the local temp table. This was common use before the introduction of table-valued parameters or when the procedures exist in different databases in the same instance. The procedures are tightly coupled and might be a problem to test the 'child' procedure, but it has the advantage that it can be called from multiple procedures.
According to books online (https://technet.microsoft.com/en-us/library/ms189915(v=sql.105).aspx) we have:
In SQL Server, if the current schema contains a procedure with the specified name, that procedure is returned. If a nonqualified stored procedure is specified, the Database Engine searches for the procedure in the following order:
• The sys schema of the current database.
• The caller's default schema if executed in a batch or in dynamic SQL; or, if the non-qualified procedure name appears inside the body of another procedure definition, the schema containing this other procedure is searched next.
• The dbo schema in the current database.
I tried testing the case with a stored procedure Proc1 which calls proc2. I define them in the same schema, but call proc2 without the schema name. It doesn't work, so what does the second part of item two on the list above mean?
Use AdventureWorks
GO
CREATE SCHEMA MySchema
GO
CREATE PROCEDURE MySchema.PROC2
AS
BEGIN
SELECT 1
END
GO
CREATE PROCEDURE MySchema.PROC1
AS
BEGIN
SELECT 2
-- calling proc2 without schema name
-- expecting it will work, since proc1 and proc2 are in same schema
EXEC PROC2
END
GO
--calling proc1 (my default schema is dbo)
--Could not find stored procedure 'PROC2'.
EXEC MySchema.PROC1
I know best practice is to always use the schema name - I'm just curious what they mean by the second item. I've tested this on version 2016.
The page you have linked to is the documentation for a specific system stored procedure. Its meaning is limited to what this stored procedure does.
CREATE PROCEDURE MySchema.PROC1
AS
BEGIN
SELECT 2
-- calling proc2 without schema name
-- expecting it will work, since proc1 and proc2 are in same schema
EXEC sp_stored_procedures 'PROC2'
END
Produces 2 result sets - the first contains 2, the second contains information about the MySchema.PROC2 stored procedure.
I'm using SQL Server 2008.
How can I pass Table Valued parameter to a Stored procedure across different Databases, but same server?
Should I create the same table type in both databases?
Please, give an example or a link according to the problem.
Thanks for any kind of help.
In response to this comment (if I'm correct and that using TVPs between databases isn't possible):
What choice do I have in this situation? Using XML type?
The purist approach would be to say that if both databases are working with the same data, they ought to be merged into a single database. The pragmatist realizes that this isn't always possible - but since you can obviously change both the caller and callee, maybe just use a temp table that both stored procs know about.
I don't believe it's possible - you can't reference a table type from another database, and even with identical type definitions in both DBs, a value of one type isn't assignable to the other.
You don't pass the temp table between databases. A temp table is always stored in tempdb, and is accessible to your connection, so long as the connection is open and the temp table isn't dropped.
So, you create the temp table in the caller:
CREATE TABLE #Values (ID int not null,ColA varchar(10) not null)
INSERT INTO #Values (ID,ColA)
/* Whatever you do to populate the table */
EXEC OtherDB..OtherProc
And then in the callee:
CREATE PROCEDURE OtherProc
/* No parameter passed */
AS
SELECT * from #Values
Table UDTs are only valid for stored procs within the same database.
So yes you would have to create the type on each server and reference it in the stored procs - e.g. just run the first part of this example in both DBs http://msdn.microsoft.com/en-us/library/bb510489.aspx.
If you don't need the efficency you can always use other methods - i.e. pass an xml document parameter or have the s.p. expect a temp table with the input data.
Edit: added example
create database Test1
create database Test2
go
use Test1
create type PersonalMessage as TABLE
(Message varchar(50))
go
create proc InsertPersonalMessage #Message PersonalMessage READONLY AS
select * from #Message
go
use Test2
create type PersonalMessage as TABLE
(Message varchar(50))
go
create proc InsertPersonalMessage #Message PersonalMessage READONLY AS
select * from #Message
go
use Test1
declare #mymsg PersonalMessage
insert #mymsg select 'oh noes'
exec InsertPersonalMessage #mymsg
go
use Test2
declare #mymsg2 PersonalMessage
insert #mymsg2 select 'oh noes'
exec InsertPersonalMessage #mymsg2
Disadvantage is that there are two copies of the data.
But you would be able to run the batch against each database simultaneously.
Whether this is any better than using a table table is really down to what processing/data sizes you have - btw to use a temp table from an s.p. you just access it from the s.p. code (and it fails if it doesn't exist).
Another way to solve this (though not necessarily the correct way) is to only utilize the UDT as a part of a dynamic SQL call.
USE [db1]
CREATE PROCEDURE [dbo].[sp_Db2Data_Sync]
AS
BEGIN
/*
*
* Presumably, you have some other logic here that requires this sproc to live in db1.
* Maybe it's how you get your identifier?
*
*/
DECLARE #SQL VARCHAR(MAX) = '
USE [db2]
DECLARE #db2tvp tableType
INSERT INTO #db2tvp
SELECT dataColumn1
FROM db2.dbo.tblData td
WHERE td.Id = ' + CAST(#YourIdentifierHere AS VARCHAR) '
EXEC db2.dbo.sp_BulkData_Sync #db2tvp
'
EXEC(#SQL)
END
It's definitely not a purist approach, and it doesn't work for every use case, but it is technically an option.
in my SQL Server 2008 database I have a number of different tables with the same structure. I query them in different stored procedures. My first try was to pass the table name to the stored procedure, like:
CREATE PROCEDURE MyTest
#tableName nvarchar(255)
AS
BEGIN
SELECT * FROM #tableName
END
But we can't use parameters for table names in SQL. So I asked you and tried the solution with using Synonyms instead of a parameter for the table name:
CREATE PROCEDURE MyTest
#tableName nvarchar(255)
AS
BEGIN
EXEC SetSimilarityTableNameSynonym #tbl = #tableName;
SELECT * FROM dbo.CurrentSimilarityTable
END
SetSimilarityTableNameSynonym is a SP to set the Synonym dbo.CurrentSimilarityTable to the passed value (the specific table name). It looks like:
CREATE PROCEDURE [dbo].[SetSimilarityTableNameSynonym]
#tbl nvarchar(255)
AS
BEGIN
IF object_id('dbo.CurrentSimilarityTable', 'SN') IS NOT NULL
DROP SYNONYM CurrentSimilarityTable;
-- Set the synonym for each existing table
IF #tbl = 'byArticle'
CREATE SYNONYM dbo.CurrentSimilarityTable FOR dbo.similarity_byArticle;
...
END
Now, as you probably see, the problem is with concurrent access to the SPs which will "destroy" each others assigned synonym. So I tried to create dynamic synonyms for each single SP-call with a GUID via NewID()
DECLARE #theGUID uniqueidentifier;
SET #theGUID=NEWID()
SET #theSynonym = 'dbo.SimTabSyn_' + CONVERT(nvarchar(255), #theGUID);
BUT ... I can't use the dynamical created name to create a synonym:
CREATE SYNONYM #theSynonym FOR dbo.similarity_byArticle;
doesn't work.
Has anybody an idea, how to get dynamical synonyms running? Is this even possible?
Thanks in advance,
Frank
All I can suggest is to run the CREATE SYNONYM in dynamic SQL. And this also means your code is running at quite high rights (db_owner or ddl_admin). You may need EXECUTE AS OWNER to allow it when you secure the code.
And how many synonyms will you end up with for the same table? If you have to do it this way, I'd use OBJECT_ID not NEWID and test first so you have one synonym per table.
But if you have one synonym per table then why not use the table name...?
What is the point is there creating 1 or more synonyms for the same table, given the table names are already unique...
I'd fix the database design.
Why would you want multiple concurrent users to overwrite the single resource (synonym)?
If your MyTest procedure is taking a the table name as a parameter, why not simply do dynamic SQL? You can validate the #tableName against against a hardcoded list of tables that this procedure is allowed to select from, or against sys.tables