I use sp_start_job to start a job.
The job (test2) has only one step:
select getdate()
waitfor delay '00:00:10'
The TRY/CATCH code:
begin try
EXEC msdb.dbo.sp_start_job #job_name = 'test2'
end try
begin catch
print 'error'
end catch
First run of the code:
Job 'test2' started successfully.
Second run of the code (within 10 seconds):
Msg 22022, Level 16, State 1, Line 0SQLServerAgent Error: Request to run job test2 (from User sa) refused because the job is already running from a request by User sa.
Why does TRY/CATCH not work in this scenario?
UPDATE:
I should added at first that I am working on a sql server 2005 which has linked servers (sql server 2000). I was trying to write a proc on the sql server 2005 server to see a job on all the linked servers. If the job is not running, run it. Initially, I used try - catch and hoped to catch any error when run the already running job but failed (this thread).
I finally used following code: (it won't compile, you need to substitute some variables, just gives an idea)
CREATE TABLE [dbo].[#jobInfo](
[job_id] [uniqueidentifier] NULL,
[originating_server] [nvarchar](30) ,
[name] [nvarchar](128) ,
[enabled] [tinyint] NULL,
[description] [nvarchar](512) ,
[start_step_id] [int] NULL,
[category] [nvarchar](128) ,
[owner] [nvarchar](128) ,
[notify_level_eventlog] [int] NULL,
[notify_level_email] [int] NULL,
[notify_level_netsend] [int] NULL,
[notify_level_page] [int] NULL,
[notify_email_operator] [nvarchar](128) ,
[notify_netsend_operator] [nvarchar](128) ,
[notify_page_operator] [nvarchar](128) ,
[delete_level] [int] NULL,
[date_created] [datetime] NULL,
[date_modified] [datetime] NULL,
[version_number] [int] NULL,
[last_run_date] [int] NOT NULL,
[last_run_time] [int] NOT NULL,
[last_run_outcome] [int] NOT NULL,
[next_run_date] [int] NOT NULL,
[next_run_time] [int] NOT NULL,
[next_run_schedule_id] [int] NOT NULL,
[current_execution_status] [int] NOT NULL,
[current_execution_step] [nvarchar](128) ,
[current_retry_attempt] [int] NOT NULL,
[has_step] [int] NULL,
[has_schedule] [int] NULL,
[has_target] [int] NULL,
[type] [int] NOT NULL
)
SET #sql =
'INSERT INTO #jobInfo
SELECT * FROM OPENQUERY( [' + #srvName + '],''set fmtonly off exec msdb.dbo.sp_help_job'')'
EXEC(#sql)
IF EXISTS (select * from #jobInfo WHERE [name] = #jobName AND current_execution_status IN (4,5)) -- 4: idle, 5: suspended
BEGIN
SET #sql = 'EXEC [' + #srvName + '].msdb.dbo.sp_start_job #job_name = ''' + #jobName + ''''
--print #sql
EXEC (#sql)
INSERT INTO #result (srvName ,status ) VALUES (#srvName, 'Job started.')
END ELSE BEGIN
INSERT INTO #result (srvName ,status ) VALUES (#srvName, 'Job is running already. No action taken.')
END
Not all errors can be caught by TRY/CATCH. In this case, sp_start_job actually calls external procedures, and these are outside the bounds of SQL Server's error handling. Or at least that's the story that they're sticking to:
http://connect.microsoft.com/SQLServer/feedback/details/362112/sp-start-job-error-handling
Also note that this is still a problem in SQL Server 2012 SP1 CU3. Please vote and comment if you want this bug fixed.
A tedious but viable workaround, which requires certain permissions and in this case assumes the job owner is sa:
DECLARE #x TABLE
(
a VARBINARY(32),b INT,c INT,d INT,e INT,f INT,g INT,h INT,i NVARCHAR(64),
Running BIT, -- the only important column
k INT,l INT,m INT
);
DECLARE #job_id UNIQUEIDENTIFIER;
SELECT #job_id = job_id FROM msdb.dbo.sysjobs WHERE name = N'test2';
INSERT #x EXEC master.dbo.xp_sqlagent_enum_jobs 1, N'sa', #job_id;
IF EXISTS (SELECT 1 FROM #x WHERE Running = 0)
BEGIN
EXEC msdb.dbo.sp_start_job #job_name = N'test2';
END
ELSE
BEGIN
PRINT 'error';
END
Even better might be:
DECLARE #job_id UNIQUEIDENTIFIER, #d DATETIME;
SELECT #job_id = job_id FROM msdb.dbo.sysjobs WHERE name = N'test2';
SELECT #d = stop_execution_date
FROM msdb.dbo.sysjobactivity WHERE job_id = #job_id;
IF #d IS NOT NULL
BEGIN
EXEC msdb.dbo.sp_start_job #job_name = N'test2';
END
ELSE
BEGIN
PRINT 'error';
END
In either case, it is still possible that the job has started between the check for its status and the call to start it, so this doesn't eliminate errors from sp_start_job altogether, but it makes them far less likely to occur.
You can use alerts to execute SQL Agent jobs. And you can use alerts' options to configure required response.
(this will help you to totally avoid error 22022 but you will have additional records in the errorlog)
To make an evergreen solution, we should also consider a job that has never run before.
This my be useful in a scenario where the SQL server is rebuilt and the jobs recreated.
To capture that scenario look at the last run requested date:
DECLARE #jobEnd DATETIME, #jobRun DATETIME
SELECT #jobEnd = sja.stop_execution_date , #jobRun = sja.run_requested_date
FROM msdb.dbo.sysjobactivity AS sja
INNER JOIN msdb.dbo.sysjobs AS sj
ON sja.job_id = sj.job_id
WHERE sj.name = 'PhoneListSyncMember'
IF (#jobEnd IS NOT NULL AND #jobRun IS NOT NULL)
OR (#jobEnd IS NULL AND #jobRun IS NULL) -- job is New and never run before
EXEC #iRet =msdb.dbo.sp_start_job #job_name='PhoneListSyncMember'
Here is how you can capture Job trigger failures.
Declare #returnstatus int
Exec #returnstatus msdb.dbo.sp_start_job 'Jobname'
if(#returnstaus = 1)
Print 'Success'
else
Print 'Failure'
Related
I'm trying to script sp_WhoIsActive into a table. The goal is feed the table with an Agent Job every 10 seconds.
I followed this guide and I tried to feed the table this way:
--Log activity into table.
DECLARE #destination_table VARCHAR(4000) =
'[Monitoring].[dbo].[WhoIsActive] '
EXEC sp_WhoIsActive
#get_plans = 1,
#get_transaction_info = 1,
#destination_table = #destination_table;
But as result I receive the error:
Warning: The join order has been enforced because a local join hint is used.
Msg 50000, Level 16, State 1, Procedure sp_WhoIsActive, Line 1111 [Batch Start Line 0]
Destination table not properly formatted.
On Google I found many guides talking about a solution that could help me execute a Stored Procedure into a temp table and from there I could create a table:
sp_configure 'Show Advanced Options', 1
GO
RECONFIGURE
GO
sp_configure 'Ad Hoc Distributed Queries', 1
GO
RECONFIGURE
GO
SELECT * INTO #MyTempTable FROM OPENROWSET('SQLNCLI', 'Server=localhost;Trusted_Connection=yes;',
'EXEC sp_WhoIsActive')
SELECT * FROM #MyTempTable
But this process too is failing with error:
Msg 11526, Level 16, State 1, Procedure sys.sp_describe_first_result_set, Line 1 [Batch Start Line 12]
The metadata could not be determined because statement 'INSERT #sessions
(
recursion,
session_id,
request_id' in procedure 'sp_WhoIsActive' uses a temp table.
I tried following Kendra Little blog but that too is not working.
In the end I scripted out the table manually:
CREATE TABLE [dbo].[WhoIsActive](
[dd_hh_mm_ss_mss] [nvarchar](50) NOT NULL,
[session_id] [tinyint] NOT NULL,
[sql_text] [nvarchar](max) NOT NULL,
[sql_command] [nvarchar](400) NOT NULL,
[login_name] [nvarchar](50) NOT NULL,
[wait_info] [nvarchar](50) NOT NULL,
[tran_log_writes] [nvarchar](50) NOT NULL,
[CPU] [smallint] NOT NULL,
[tempdb_allocations] [smallint] NOT NULL,
[tempdb_current] [smallint] NOT NULL,
[blocking_session_id] [nvarchar](50) NOT NULL,
[reads] [int] NOT NULL,
[writes] [float] NOT NULL,
[physical_reads] [tinyint] NOT NULL,
[query_plan] [nvarchar](50) NOT NULL,
[used_memory] [tinyint] NOT NULL,
[status] [nvarchar](50) NOT NULL,
[tran_start_time] [datetime2](7) NOT NULL,
[implicit_tran] [nvarchar](50) NOT NULL,
[open_tran_count] [tinyint] NOT NULL,
[percent_complete] [nvarchar](50) NOT NULL,
[host_name] [nvarchar](50) NOT NULL,
[database_name] [nvarchar](50) NOT NULL,
[program_name] [nvarchar](100) NOT NULL,
[start_time] [datetime2](7) NOT NULL,
[login_tine] [datetime2](7) NOT NULL,
[request_id] [tinyint] NOT NULL,
[collection_time] [datetime2](7) NOT NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
But that too is failing and I cannot feed the table with a job.
sp_WhoIsActive is so popular, I cannot believe I'm the only one trying to insert the results into a table.
You need to create a table suitable to use with the output of the procedure, the schema of which can vary depending on the options you use.
SP_WhoIsActive will actually give you the create script, so to capture the default options just do
declare #definition varchar(max)
exec sp_WhoIsActive #return_schema = 1, #schema = #definition output
print #definition
This returns the appropriate T-SQL:
CREATE TABLE < table_name > (
[dd hh:mm:ss.mss] VARCHAR(8000) NULL
,[session_id] SMALLINT NOT NULL
,[sql_text] XML NULL
,[login_name] NVARCHAR(128) NOT NULL
,[wait_info] NVARCHAR(4000) NULL
,[CPU] VARCHAR(30) NULL
,[tempdb_allocations] VARCHAR(30) NULL
,[tempdb_current] VARCHAR(30) NULL
,[blocking_session_id] SMALLINT NULL
,[reads] VARCHAR(30) NULL
,[writes] VARCHAR(30) NULL
,[physical_reads] VARCHAR(30) NULL
,[used_memory] VARCHAR(30) NULL
,[status] VARCHAR(30) NOT NULL
,[open_tran_count] VARCHAR(30) NULL
,[percent_complete] VARCHAR(30) NULL
,[host_name] NVARCHAR(128) NULL
,[database_name] NVARCHAR(128) NULL
,[program_name] NVARCHAR(128) NULL
,[start_time] DATETIME NOT NULL
,[login_time] DATETIME NULL
,[request_id] INT NULL
,[collection_time] DATETIME NOT NULL
)
Edit and run with the required target table name, then you can run sp_whoisactive with the destination table option
exec sp_WhoIsActive #destination_table='Monitoring.dbo.WhoIsActive'
See the docs
I am unable to EXEC a stored procedure that upserts a table that has an encrypted column using Always Encrypted. However, I am able to copy the SQL from the sproc and run that as regular SQL with the parameters set, Just cannot get the sproc to fire when executing the sproc via the EXEC function in SSMS which is also causing problems in the application
The table has a trigger on it that inserts into another audit table of similar structure that is also encrypted using the same encryption. I have done the usual thing:
Checking the Enable Parameterizaion for Always Encrypted in Query Options Setting column encryption setting=enabled on the Connection Settings.
Refreshing the encyrption metadata for the sproc:
EXEC sp_refresh_parameter_encryption 'organization.uspOrganizationAddressUpsert'
Tables:
CREATE TABLE [organization].[OrganizationAddress](
[OrganizationAddressId] [int] IDENTITY(1,1) NOT NULL,
[CreatedUser] [int] NOT NULL,
[CreatedDate] [datetime2](7) NOT NULL,
[LastUpdateUser] [int] NOT NULL,
[LastUpdateDate] [datetime2](7) NOT NULL,
[RemovedDate] [datetime2](7) NULL,
[Address1] [varchar](60) NOT NULL,
[Address2] [varchar](60) NULL,
[City] [varchar](60) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [CEK_Auto1], ENCRYPTION_TYPE = Deterministic, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256') NOT NULL,
[State] [varchar](60) NOT NULL,
[ZipCode] [varchar](60) NOT NULL,
[ClientNumberId] [int] NOT NULL
CREATE TABLE [audit].[OrganizationAddressAudit](
[OrganizationAddressId] [int] NOT NULL,
[CreatedUser] [int] NOT NULL,
[CreatedDate] [datetime2](7) NOT NULL,
[LastUpdateUser] [int] NOT NULL,
[LastUpdateDate] [datetime2](7) NOT NULL,
[RemovedDate] [datetime2](7) NULL,
[Address1] [varchar](60) NOT NULL,
[Address2] [varchar](60) NULL,
[City] [varchar](60) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [CEK_Auto1], ENCRYPTION_TYPE = Deterministic, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256') NOT NULL,
[State] [varchar](60) NOT NULL,
[ZipCode] [varchar](60) NOT NULL,
[ClientNumberId] [int] NOT NULL,
[OperationDate] [datetime] NOT NULL,
[Operation] [varchar](50) NOT NULL,
[OperationBy] [varchar](100) NOT NULL
Stored Procedure:
ALTER PROCEDURE [organization].[uspOrganizationAddressUpsert]
#OrganizationId INT,
#ExecutingUserId INT,
#Address1 VARCHAR(60),
#Address2 VARCHAR(60),
#City VARCHAR(60),
#State VARCHAR(60),
#ZipCode VARCHAR(60),
#ClientNumberId INT
AS
BEGIN
SET NOCOUNT ON
DECLARE #RightNow AS DATETIME2 = SYSDATETIME()
If EXISTS (Select 1 From [organization].[OrganizationAddress] Where ClientNumberId = #ClientNumberId)
BEGIN
UPDATE [organization].[OrganizationAddress] SET
LastUpdateUser = #ExecutingUserId,
LastUpdateDate = #RightNow,
Address1 = #Address1,
Address2 = #Address2,
City = #City,
[State] = #State,
ZipCode = #ZipCode,
RemovedDate = Null
Where ClientNumberId = #ClientNumberId
END
ELSE
BEGIN -- INSERT part of the UPSERT
INSERT INTO [organization].[OrganizationAddress]
(CreatedUser
,CreatedDate
,LastUpdateUser
,LastUpdateDate
,Address1
,Address2
,City
,[State]
,ZipCode
,ClientNumberId)
VALUES
(#ExecutingUserId
,#RightNow
,#ExecutingUserId
,#RightNow
,#Address1
,#Address2
,#City
,#State
,#ZipCode
,#ClientNumberId)
END
END
Running the stored procedure code with the paramteers set is fine, but I am unable to EXEC the sproc:
declare #orgId INT = 1;
declare #client int = 888;
declare #user int = 1;
declare #Add1 varchar(60)= 'Test Address1';
declare #Add2 varchar(60)= 'Test Address2';
declare #city varchar(60) = 'City';
declare #state varchar(60) = 'St';
declare #zip varchar(60) = '12345';
EXEC organization.uspOrganizationAddressUpsert
#OrganizationID=#orgID,
#ExecutingUserId = #user, -- int
#Address1 = #Add1, -- varchar(60)
#Address2 = #Add2, -- varchar(60)
#City = #city, -- varchar(60)
#State = #state, -- varchar(60)
#ZipCode = #zip, -- varchar(60)
#ClientNumberId = #client; -- int
Msg 206, Level 16, State 2, Procedure uspOrganizationAddressUpsert, Line 0 [Batch Start Line 1]
Operand type clash: varchar is incompatible with varchar(60) encrypted with (encryption_type = 'DETERMINISTIC', encryption_algorithm_name = 'AEAD_AES_256_CBC_HMAC_SHA_256', column_encryption_key_name = 'CEK_Auto1', column_encryption_key_database_name = 'BankruptcyApp') collation_name = 'SQL_Latin1_General_CP1_CI_AS'
I created a similar table in a test DB with VARCHAR(60) for the enrcrypted columns, a trigger, and an audit table and its working fine there and I cant find any differences in the table/sproc/trigger that would allow it to work there and not here. I've pretty much exhausted the other posts and blogs I can find.
Fixed! Needed to update the app code to specify the data type and length:
parameters.Add("#City", organizationAddress.City, System.Data.DbType.AnsiString, System.Data.ParameterDirection.Input, 60);
where it was previously just:
parameters.Add("#City", organizationAddress.City)
This at least get the app to run the sproc but still cant run it from SSMS via EXEC
I am trying to utilize Dynamic SQL that will parse in the file directory into an OpenRowSet(#Database). Right now I have a hard coded directory for the Excel File. The end result will be me creating an application that will take the user's file and import into the SQL table. From there I'll be merging and Match/Not Matching (Which is working properly). This is the last piece of the puzzle. I don't know why the error message is looking for my file in "C:\WINDOWS\system32\ "
My current error messages are:
OLE DB provider "Microsoft.ACE.OLEDB.12.0" for linked server "(null)" returned message "The Microsoft Access database engine could not find the object 'C:\WINDOWS\system32\ C:\Users\GrimRieber\Desktop\isi test.xlsx'. Make sure the object exists and that you spell its name and the path name correctly. If 'C:\WINDOWS\system32\ C:\Users\GrimRieber\Desktop\isi test.xlsx' is not a local object, check your network connection or contact the server administrator.".
Msg 7303, Level 16, State 1, Line 1
Cannot initialize the data source object of OLE DB provider "Microsoft.ACE.OLEDB.12.0" for linked server "(null)".
Code:
declare #Database varchar(max)
select #Database = 'C:\Users\GrimRieber\Desktop\isi test.xlsx'
declare #sql varchar(Max)
select #sql = 'SELECT * FROM OPENROWSET(
''Microsoft.ACE.OLEDB.12.0'',
''Excel 12.0; Database= ' + #Database + '; HDR=YES; IMEX=1'',
''SELECT [Vendor],[VendorName],[Material],[MaterialName],[Supplier Stock Num],[01],[02],[03],[04],[05],[06],[07],[08],[09],[10],[11],[12],[Year]FROM [Data$]''
)'
IF OBJECT_ID('tempdb.dbo.#TempScorecardInventorySold', 'U') IS NOT NULL
DROP TABLE #TempScorecardInventorySold;
CREATE TABLE #TempScorecardInventorySold
(
[Vendor] [varchar](50) NULL,
[VendorName] [varchar](50) NULL,
[Material] [varchar](50) NULL,
[MaterialName] [varchar](50) NULL,
[Supplier Stock Num] [varchar](50) NULL,
[01] [nVarchar](50) NULL,
[02] [nVarchar](50) NULL,
[03] [nVarchar](50) NULL,
[04] [nVarchar](50) NULL,
[05] [nVarchar](50) NULL,
[06] [nVarchar](50) NULL,
[07] [nVarchar](50) NULL,
[08] [nVarchar](50) NULL,
[09] [nVarchar](50) NULL,
[10] [nVarchar](50) NULL,
[11] [nVarchar](50) NULL,
[12] [nVarchar](50) NULL,
[Year] [Int] Null
) ON [PRIMARY];
INSERT INTO [dbo].#TempScorecardInventorySold ([Vendor],[VendorName],[Material],[MaterialName],[Supplier Stock Num],[01],[02],[03],[04],[05],[06],[07],[08],[09],[10],[11],[12],[Year])
EXECUTE(#sql)
While I cannot recreate your file path issue (be sure to carefully check if file exists at the path and file extension), the OPENROWSET() in that setup should define fields in the SELECT clause at beginning. The last argument should be unquoted, pointing to worksheet range:
select #sql = 'SELECT [Vendor],[VendorName],[Material],[MaterialName],[Supplier Stock Num],
[01],[02],[03],[04],[05],[06],
[07],[08],[09],[10],[11],[12],[Year]
FROM OPENROWSET(''Microsoft.ACE.OLEDB.12.0'',
''Excel 12.0; Database= ' + #Database + '; HDR=YES; IMEX=1'', [Data$])';
Alternatively, consider OPENDATASOURCE:
select #sql = 'SELECT [Vendor],[VendorName],[Material],[MaterialName],[Supplier Stock Num],
[01],[02],[03],[04],[05],[06],
[07],[08],[09],[10],[11],[12],[Year]
FROM OPENDATASOURCE(''Microsoft.ACE.OLEDB.12.0'',
''Data Source=' + #Database + ';Extended Properties=Excel 12.0'')...Data$'
Or even a Driver version (fields can be in either of two SELECT clauses)
select #sql = 'SELECT [Vendor],[VendorName],[Material],[MaterialName],[Supplier Stock Num],
[01],[02],[03],[04],[05],[06],
[07],[08],[09],[10],[11],[12],[Year]
FROM OPENROWSET(''MSDASQL'',
''Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};
DBQ=' + #Database + ''', ''SELECT * FROM [DATA$]'');
Have 2 databases: MAIN and IP2LOCATION
in MAIN, I have the following stored procedure:
CREATE PROCEDURE dbo.Update_IP2Location_DB11_from_CSV
AS
BEGIN
IF NOT EXISTS (SELECT * FROM sys.objects
WHERE object_id = OBJECT_ID(N'[ip2location].[dbo].[db11_new]') AND type in (N'U'))
BEGIN
CREATE TABLE [ip2location].[dbo].[db11_new]
(
[ip_from] bigint NOT NULL,
[ip_to] bigint NOT NULL,
[country_code] nvarchar(2) NOT NULL,
[country_name] nvarchar(64) NOT NULL,
[region_name] nvarchar(128) NOT NULL,
[city_name] nvarchar(128) NOT NULL,
[latitude] float NOT NULL,
[longitude] float NOT NULL,
[zip_code] nvarchar(30) NOT NULL,
[time_zone] nvarchar(8) NOT NULL,
) ON [PRIMARY]
CREATE INDEX [ip_from] ON [ip2location].[dbo].[db11_new]([ip_from])
END
ELSE
BEGIN
DELETE FROM [ip2location].[dbo].[db11_new]
END
BULK INSERT [ip2location].[dbo].[db11_new]
FROM 'D:\IP2LOCATION-LITE-DB11.CSV'
WITH
( FORMATFILE = 'C:\inetpub\wwwroot\ws\DB11_ip4.FMT')
EXEC sp_rename N'dbo.db11', N'db11_old', 'OBJECT'
EXEC sp_rename N'ip2location.dbo.db11_new', N'db11', 'OBJECT'
END
that does not work properly:
if db11_new does not exists, it (correctly) creates it, but if it exists.. I get
There is already an object named 'db11_new' in the database.
therefore it seems there is something wrong in
IF NOT EXISTS (SELECT * FROM sys.objects
WHERE object_id = OBJECT_ID(N'[ip2location].[dbo].[db11_new]') AND type in (N'U'))
and also at the end of procedure with the 2 Rename I get (always) the following answer
Msg 15248, Level 11, State 1, Procedure sp_rename, Line 359
Either the parameter #objname is ambiguous or the claimed #objtype (OBJECT) is wrong.
it seems problem is because the sproc is not stored into ip2location DB but in another database..
can suggest a solution, considering that I would prefer to keep all sprocs in MAIN DB, since have all other there?
Thanks
therefore it seems there is something wrong in
IF NOT EXISTS (SELECT * FROM sys.objects
WHERE object_id = OBJECT_ID(N'[ip2location].[dbo].[db11_new]') AND type in (N'U'))
Your analysis is correct. The sys.objects catalog view will return objects in the current database context (MAIN). Although you could just use a 3-part name (ip2location.sys.objects), I suggest you simply check for a NULL OBJECT_ID function result:
IF OBJECT_ID(N'[ip2location].[dbo].[db11_new]', 'U') IS NULL
BEGIN
CREATE TABLE [ip2location].[dbo].[db11_new]
(
[ip_from] bigint NOT NULL,
[ip_to] bigint NOT NULL,
[country_code] nvarchar(2) NOT NULL,
[country_name] nvarchar(64) NOT NULL,
[region_name] nvarchar(128) NOT NULL,
[city_name] nvarchar(128) NOT NULL,
[latitude] float NOT NULL,
[longitude] float NOT NULL,
[zip_code] nvarchar(30) NOT NULL,
[time_zone] nvarchar(8) NOT NULL,
) ON [PRIMARY];
CREATE INDEX [ip_from] ON [ip2location].[dbo].[db11_new]([ip_from]);
END;
ELSE
BEGIN
DELETE FROM [ip2location].[dbo].[db11_new];
END;
sys.objects and sp_rename are local objects.
Try to use this:
IF NOT EXISTS (SELECT * FROM ip2location.sys.objects
WHERE object_id = OBJECT_ID(N'[dbo].[db11_new]') AND type in (N'U'))
and
EXEC ip2location.sp_rename N'dbo.db11_new', N'db11', 'OBJECT'
Maybe it helps...
Alternatively, when you wanna do things in another database than the current one, you can write you code in dynamic sql and then execute it directly in the other database.
https://msdn.microsoft.com/en-us/library/ms188001.aspx
I have tested this query (without csv upload)
At first I remove every reference to ip2location:
CREATE PROCEDURE dbo.Update_IP2Location_DB11_from_CSV
AS
BEGIN
IF NOT EXISTS (SELECT * FROM sys.objects
WHERE object_id = OBJECT_ID(N'dbo.db11_new') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[db11_new]
(
[ip_from] bigint NOT NULL,
[ip_to] bigint NOT NULL,
[country_code] nvarchar(2) NOT NULL,
[country_name] nvarchar(64) NOT NULL,
[region_name] nvarchar(128) NOT NULL,
[city_name] nvarchar(128) NOT NULL,
[latitude] float NOT NULL,
[longitude] float NOT NULL,
[zip_code] nvarchar(30) NOT NULL,
[time_zone] nvarchar(8) NOT NULL,
) ON [PRIMARY]
CREATE INDEX [ip_from] ON [dbo].[db11_new]([ip_from])
END
ELSE
BEGIN
DELETE FROM [dbo].[db11_new]
END
BULK INSERT [dbo].[db11_new]
FROM 'D:\IP2LOCATION-LITE-DB11.CSV'
WITH
( FORMATFILE = 'C:\inetpub\wwwroot\ws\DB11_ip4.FMT')
EXEC sp_rename N'dbo.db11', N'db11_old', 'OBJECT'
EXEC sp_rename N'dbo.db11_new', N'db11', 'OBJECT'
END
GO
First run:
I have no db11* tables. Execution brings me:
Msg 15248, Level 11, State 1, Procedure sp_rename, Line 401 [Batch
Start Line 2] Either the parameter #objname is ambiguous or the
claimed #objtype (OBJECT) is wrong. Caution: Changing any part of an
object name could break scripts and stored procedures.
That means that db11_new was created, and than renamed in db11, but db11_old wasn't found, so I got this error. I get db11 table in my DB.
Second run:
Caution: Changing any part of an object name could break scripts and
stored procedures. Caution: Changing any part of an object name could
break scripts and stored procedures.
That means all was created and renamed.
Third run:
Msg 15335, Level 11, State 1, Procedure sp_rename, Line 509 [Batch
Start Line 2] Error: The new name 'db11_old' is already in use as a
OBJECT name and would cause a duplicate that is not permitted. Msg
15335, Level 11, State 1, Procedure sp_rename, Line 509 [Batch Start
Line 2] Error: The new name 'db11' is already in use as a OBJECT name
and would cause a duplicate that is not permitted.
So every next re-run You will get this same errors.
My suggestion is to do something about db11_old.
Thanks to Reboon and Dan Guzman here the solution, little improved:
CREATE PROCEDURE dbo.spA_Update_IP2Location_DB11_from_CSV
AS
BEGIN
IF OBJECT_ID(N'[ip2location].[dbo].[db11_new]', 'U') IS NULL
BEGIN
CREATE TABLE [ip2location].[dbo].[db11_new](
[ip_from] bigint NOT NULL,
[ip_to] bigint NOT NULL,
[country_code] nvarchar(2) NOT NULL,
[country_name] nvarchar(64) NOT NULL,
[region_name] nvarchar(128) NOT NULL,
[city_name] nvarchar(128) NOT NULL,
[latitude] float NOT NULL,
[longitude] float NOT NULL,
[zip_code] nvarchar(30) NOT NULL,
[time_zone] nvarchar(8) NOT NULL,
) ON [PRIMARY]
CREATE INDEX [ip_from] ON [ip2location].[dbo].[db11_new]([ip_from]) ON [PRIMARY]
END
ELSE
BEGIN
delete from [ip2location].[dbo].[db11_new]
END
BULK INSERT [ip2location].[dbo].[db11_new]
FROM 'D:\IP2LOCATION-LITE-DB11.CSV'
WITH
( FORMATFILE = 'C:\inetpub\wwwroot\ws\DB11_ip4.FMT' )
BEGIN TRANSACTION
EXEC ip2location.dbo.sp_rename N'dbo.db11', N'db11_old'
EXEC ip2location.dbo.sp_rename N'dbo.db11_new', N'db11'
IF OBJECT_ID(N'[ip2location].[dbo].[db11_old]', 'U') IS NOT NULL
BEGIN
DROP TABLE ip2location.dbo.db11_old
END
COMMIT TRANSACTION
END
I have 5 meta tables that have the same format but depend on 5 other tables. Each Meta table looks like this:
CREATE TABLE [dbo].[SiteMetas]
(
[SiteMetaId] [bigint] IDENTITY(1,1) NOT NULL,
[SiteId] [bigint] NOT NULL,
FOREIGN KEY([SiteId]) REFERENCES [dbo].[Sites] ([SiteId]),
[MetaGroup] [nvarchar] (64) NOT NULL,
[MetaName] [nvarchar] (128) NOT NULL,
[MetaType] [char] NOT NULL DEFAULT 0, -- t, i, r, d, s, b
[MetaBool] [bit] DEFAULT NULL, -- t
[MetaInteger] [bigint] DEFAULT NULL, -- i
[MetaReal] [real] DEFAULT NULL, -- r
[MetaDateTime] [datetime] DEFAULT NULL, -- d
[MetaString] [nvarchar] (MAX) DEFAULT NULL, -- s
[MetaBinary] [varbinary] (MAX) DEFAULT NULL, -- b
[MetaCreated] [datetime] NOT NULL DEFAULT (GETUTCDATE()),
[MetaExpires] [datetime] DEFAULT NULL,
[MetaUpdated] [datetime] DEFAULT NULL,
PRIMARY KEY CLUSTERED ([SiteMetaId] ASC) WITH (IGNORE_DUP_KEY = ON),
UNIQUE NONCLUSTERED ([SiteId] ASC, [MetaGroup] ASC, [MetaName] ASC) WITH (IGNORE_DUP_KEY = ON)
);
This is for Site but there's 4 more. Like Users, ...
And I want to read the Binary meta value from Site. So wrote this stored procedure:
CREATE PROCEDURE [dbo].[GetSiteMetaBinary]
#SiteId AS bigint,
#Group AS nvarchar(64),
#Name AS nvarchar(128)
AS
BEGIN
SELECT TOP 1 [MetaBinary]
FROM [dbo].[SiteMetas]
WHERE [SiteId] = #SiteId
AND [MetaGroup] = #Group
AND [MetaName] = #Name
AND [MetaType] = 'b';
END;
This stored procedure has duplicates for User too... and the rest of the tables. That just replaces Site with User in its body.
But thinking that I have too many of these I wrote this one:
CREATE PROCEDURE [dbo].[GetMeta]
#Set AS nvarchar(64),
#Id AS bigint,
#Group AS nvarchar(64),
#Name AS nvarchar(128),
#Type AS nvarchar(16)
AS
BEGIN
DECLARE #Flag nchar(1);
DECLARE #Sql nvarchar(MAX);
SET #Flag = CASE #Type
WHEN 'Bool' THEN 't'
WHEN 'Integer' THEN 'i'
WHEN 'Real' THEN 'r'
WHEN 'DateTime' THEN 'd'
WHEN 'String' THEN 's'
WHEN 'Binary' THEN 'b'
ELSE NULL
END;
SET #Sql = N'SELECT TOP 1 [Meta' + #Type + N'] FROM [dbo].[' + #Set + N'Metas]' +
N'WHERE [' + #Set + N'Id] = #Id AND [MetaGroup] = #Group AND [MetaName] = #Name AND [MetaType] = #Flag;';
-- SELECT #Sql; -- DEBUG
EXEC sp_executesql #Sql,
N' #Id AS bigint, #Group AS nvarchar(64), #Name AS nvarchar(128), #Flag AS nchar(1)',
#Id, #Group, #Name, #Flag
;
END;
which is a general use stored procedure to read any data typed stored in a column based on input arguments. I use it like this [dbo].[GetMeta] 'Site', 1, 'group', 'name', 'Binary' the difference being that the actual query is dynamically generated so it's not known before hand by SQL Server like the first specialized variant.
Which of the two choices is better from a performance point of view and friendlier to SQL Server's internals? A dedicated one for each table and column data type of a general one that internally builds a query based on fed arguments.
I can use either. I like the last as it does not pollute my stored procedure space. :) The first one is more clear and SQL Server might be able to optimize it better. Not sure...
PS: I'm quite new to SQL Server
Static procedures are usually faster because the SQL engine can cache the compiled SP's execution plan.
However, unless this SP will be called a lot or is time-critical, it probably isn't worth worrying about it because the time savings of only having to maintain one SP will make up for the very small amount of time difference spent waiting for the SP to finish.