I am completely new to SQL Server and a bit lost. When I try the following, it executes the first three lines and ignores the rest, just get
'Command(s) completed successfully.'
USE [RenewalsDb]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[One]
AS
BEGIN
SET NOCOUNT ON;
DROP TABLE [dbo].NewTransTable;
SELECT * INTO [dbo].[NewTransTable] FROM [dbo].aqryTransTable;
DELETE FROM [dbo].[NewTransTable] WHERE (((NewTransTable.CURRENT_LICENSE_SKU_DESC) Like '% partner program %'));
DELETE FROM [dbo].[NewTransTable] WHERE (((NewTransTable.RENEWAL_MAINTAINANCE_SKU_DESC) Like '% partner program %'));
UPDATE NewTransTable SET NewTransTable.[Quote Number] = Null;
UPDATE dbo.TransactionTable SET Concat = dbo.qryNamedAcReseller.LATEST_DISTRIBUTOR_NAME + dbo.qryNamedAcReseller.[Sub Territory FY14 ]
FROM dbo.TransactionTable INNER JOIN
dbo.qryNamedAcReseller ON dbo.TransactionTable.LATEST_INSTANCE_NUMBER = dbo.qryNamedAcReseller.LATEST_INSTANCE_NUMBER;
UPDATE dbo.TransactionTable SET Concat = dbo.qryNamedAcReseller.[Sub Territory FY14 ]
FROM dbo.TransactionTable INNER JOIN
dbo.qryNamedAcReseller ON dbo.TransactionTable.LATEST_INSTANCE_NUMBER = dbo.qryNamedAcReseller.LATEST_INSTANCE_NUMBER
WHERE Concat IS NULL;
UPDATE dbo.NewTransTable SET [Quote Number] = dbo.Autogen.[Quote Number] FROM dbo.Autogen RIGHT OUTER JOIN
dbo.NewTransTable ON dbo.Autogen.[IB Reference Num] = dbo.NewTransTable.LATEST_INSTANCE_NUMBER AND
dbo.Autogen.[Quote Known As] = dbo.NewTransTable.[Quote Known As]
DROP TABLE [dbo].NewTransTable2;
SELECT * INTO [dbo].[NewTransTable2] FROM [dbo].aqryTransTable2;
ALTER TABLE [dbo].NewTransTable2 ADD Named_Account nvarchar(255);
END
GO
Welcome to stackoverflow.
Stored Procedure is like a template which can reused multiple times and it can be made dynamic with the help or parameters. Refer mssqltips.com - SQL Server Stored Procedure Tutorial on guide to Stored Procedures. If you want to execute some commands only once, Stored Procedure is not the right thing.
So when you execute the above script, what SQL Server is doing is creating the template structure i.e. Stored procedure named [One] and not actually running the scripts within the stored procedure.
To execute this stored procedure named [One] you have to call it using EXEC One or just simply One and Execute (F5)
Related
I'm stuck and in need of some help please. I am using SQL Server 2017.
I have written a stored procedure which is being pulled into Crystal Reports. The report is a picking list. When it has been printed I want to update column PickingSlip with 'Y'
ALTER PROCEDURE [dbo].[Picking]
AS
BEGIN
SET NOCOUNT ON;
SELECT
SorMaster.SalesOrder, SorDetail.SalesOrderLine, SorDetail.StockCode, SorDetail.OrderQty, SorDetail.ShipQty
FROM
SorMaster
INNER JOIN
SorDetail ON SorMaster.SalesOrder = SorDetail.SalesOrder
WHERE
SorDetail.OrderQty = SorDetail.ShipQty
AND (PickingSlip = '')
UPDATE SorDetail
SET PickingSlip = 'Y'
WHERE
SorDetail.OrderQty = SorDetail.ShipQty
AND PickingSlip = ''
END
The report is blank. The update is working so I'm guessing the SP completes and then generates output into Crystal Reports, which is why I'm not seeing anything.
How can I update also get an output?
Crystal doesn't know what part of the SP it should use as the result set.
Perhaps you could load the SELECT into a temporary table, do the update, and finish by returning the temp table.
Or remove the update statement and call it from another SP used in a subreport.
Or call the update statement from a Crystal formula using a UFL.
I am working on a mutation test framework for SQL Server, for this I need to be able to calculate what lines of a stored procedure, function or trigger are executed when I execute a certain stored procedure.
The difficult part is that I want to know the exact lines or statements being executed from the stored procedure I call.
With a query like this I can see what stored procedures/triggers/functions are being executed, since I know when I call the stored procedure I can use the time to see if it was executed.
SELECT d.object_id, d.database_id,
OBJECT_NAME(object_id, database_id) AS proc_name,
MAX( d.last_execution_time) as last_execution_time,
OBJECT_DEFINITION(object_id) as definition
FROM sys.dm_exec_procedure_stats AS d
WHERE d.database_id = DB_ID()
GROUP BY d.object_id, d.database_id,
OBJECT_NAME(object_id, database_id)
How would I find the lines/statements that have been executed, I also have to know inside what stored procedure/trigger/function the lines/statements exists and in which shema this is. I have to take into account that a IF/ELSE statement may be used.
With this data I can do 2 important things:
generate a code coverage report
optimize what lines to mutate, since I dont have to mutate uncovered lines.
A possible, but not a very nice, solution would be to automaticly change stored procedures to add a line that inserts the previous line into a table, but this will require splitting up the procedure into statements, which I don't know how to do.
Please note that I cannot change the code users want to test with my framework. I can search for patterns and replace but manually changing procedures is NOT a option.
EDIT:
Lets redifine this question: How to split a stored procedure definition into its different statements in a way that does not depend on code style?
and How to add a new statement in between found statements?
EDIT: in the SO post SQL Server: How to parse code into its different statements I have found a way to trace statement execution, but I can't filter it yet.
So the extended events are the solution, this is how I have done it:
IF EXISTS(SELECT * FROM sys.server_event_sessions WHERE name='testMSSQLTrace')
DROP EVENT SESSION testMSSQLTrace ON SERVER;
DECLARE #cmd VARCHAR(MAX) = '';
SELECT #cmd = 'CREATE EVENT SESSION testMSSQLTrace
ON SERVER
ADD EVENT sqlserver.sp_statement_completed
(WHERE (sqlserver.database_name = N''' + DB_NAME() + '''))
ADD TARGET package0.ring_buffer
WITH (
MAX_MEMORY = 2048 KB,
EVENT_RETENTION_MODE = NO_EVENT_LOSS,
MAX_DISPATCH_LATENCY = 3 SECONDS,
MAX_EVENT_SIZE = 0 KB,
MEMORY_PARTITION_MODE = NONE,
TRACK_CAUSALITY = OFF,
STARTUP_STATE = OFF
);'
EXEC (#cmd)
This creates an event that can be fired after every statement completion, this is done dynamicly to filter on the database
Then I have 3 procedures that make controlling this event easy
/*******************************************************************************************
Starts the statement trace
*******************************************************************************************/
CREATE OR ALTER PROC testMSSQL.Private_StartTrace
AS
BEGIN
ALTER EVENT SESSION testMSSQLTrace
ON SERVER
STATE = START;
END
GO
/*******************************************************************************************
Ends the statement trace, this also clears the trace
*******************************************************************************************/
CREATE OR ALTER PROC testMSSQL.Private_StopTrace
AS
BEGIN
ALTER EVENT SESSION testMSSQLTrace
ON SERVER
STATE = STOP;
END
GO
/*******************************************************************************************
Saves the statements trace
*******************************************************************************************/
CREATE OR ALTER PROC testMSSQL.Private_SaveTrace
AS
BEGIN
DECLARE #xml XML;
SELECT #xml = CAST(xet.target_data AS xml)
FROM sys.dm_xe_session_targets AS xet INNER JOIN sys.dm_xe_sessions AS xe ON (xe.address = xet.event_session_address)
WHERE xe.name = 'testMSSQLTrace'
INSERT INTO testMSSQL.StatementInvocations (testProcedure, procedureName, lineNumber, statement)
SELECT testMSSQL.GetCurrentTest(),
OBJECT_NAME(T.c.value('(data[#name="object_id"]/value)[1]', 'int')),
T.c.value('(data[#name="line_number"]/value)[1]', 'int'),
T.c.value('(data[#name="statement"]/value)[1]', 'VARCHAR(900)')
FROM #xml.nodes('RingBufferTarget/event') T(c)
WHERE T.c.value('(data[#name="nest_level"]/value)[1]', 'int') > 3
END
GO
These procedures respectivly start and stop the trace and the last one stores the result in a table where it filters on the nest level so my own code is not traced.
Finally I use it a bit like this:
start trace
start tran/savepoint
run SetUp (users code)
run test (users code)
save trace
save trace to variable
rollback tran (also catch errors and stuff like that)
save variable back to table so the trace is not rolled back
Special thanks to #Jeroen Mosterd for originally coming up with a proposal for this solution in this SQL Server: How to parse code into its different statements SO post
You can either:
Add a #DEBUG parameter to each stored procedure you call, or
Log everything you want, or
Only log when you want.
With the #Debug parameter, you can default it to OFF, then call it with ON when you want to trace your statements, with the following code:
IF (#Debug = 1) PRINT 'your tracing information goes here';
If you want to log everything, create a log table and insert a row into it wherever you need to know which statement was executed, such as:
DECLARE #log AS TABLE (msg VARCHAR(MAX));
and
INSERT INTO #log VALUES('your tracing information goes here');
Or you can combine them:
IF (#Debug = 1) INSERT INTO #log VALUES('your tracing information goes here');
Of course these will affect performance even when you don't output/log.
I need to pass linked server name as variable to stored procedure right now after testing and research they all suggest to using dynamic sql and open query which I am using now. however I am not comfortable using it(sql injection) plus I need to call other user defined function to the query. I am looking for a more secure and direct call. Here is my SP
ALTER PROCEDURE [dbo].[GetBackUpStatus]
-- Add the parameters for the stored procedure here
#linkedServerName AS VARCHAR(100),
#exemptDB as VARCHAR(100)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
DECLARE #Sql varchar(8000)
SET NOCOUNT ON;
set #Sql = 'select * from openquery (' + #linkedServerName + ' , ''SELECT SERVERPROPERTY(''''SERVERNAME'''') AS "SERVERNAME",
T1.NAME AS DatabaseName,
MAX(T2.backup_finish_date) AS last_db_backup_date,
CAST(COALESCE(DATEDIFF(second, MAX(T2.backup_finish_date) , CURRENT_TIMESTAMP)/ 3600.0, 9999.0) as NUMERIC(6,2)) AS [Hours Since Backup]
FROM master.sys.databases T1
LEFT OUTER JOIN msdb.dbo.backupset T2 ON T2.database_name = T1.NAME
WHERE T1.NAME NOT IN (''''tempdb'''')
GROUP BY T1.NAME
ORDER BY T1.NAME'')'
Exec (#Sql)
END
the purpose of this query is to get the server status and its database, I don't like this because of that confusing single quotes, this query will eventually grow as I develop and add function calls.
I tried this and something like this is what I wanted, since it is direct query and cleaner without those quotes. That's how I typically use linked server.
Select * from [' + #linkedservername + '].[schema].table
thanks
Solution for a large scale data model with hundreds of tables / objects.
Dynamic modification and cloning of a stored procedure for every linked-server.
It is kinda hiding any dynamic SQL under the hood.
How to
Create a stored procedure which interacts with an existing linked-server.
During a database deployment process:
Obtain the source code of the stored procedure.
Replace the name of the linked-server in the code.
If you want to create a new stored procedure (cloned), replace the name of the initial stored procedure in the code.
Create a cloned stored procedure or modify the current.
Repeat all steps for each required linked-server.
There are another variations for it.
Now, any external logic may decide which procedure to use.
You can check the existence of a linked-server or its related stored procedure.
For modifications and cloning, it is possible to use SQL Server or external tools, such as C#, CMD, etc.
For creation under SQL Server.
I'm currently facing a strange situation.
I'm collecting code of existing stored procedures from a query to a TMP table.
TABLE:
##SPListAndCode
(
Code nVarchar(MAX)
)
Query:
INSERT INTO ##SPListAndCode
SELECT OBJECT_DEFINITION (OBJECT_ID('SPname')))
After that I am trying to replace values to get from Create query, Alter query
REPLACE(CODE, 'CREATE PROCEDURE', 'ALTER PROCEDURE')
But problem is this: REPLACE function is not replacing values.
But, when I am trying to use
REPLACE(CODE, 'CREATE', 'ALTER')
function works as expected.
But this scenario are not acceptable for me, because inside the stored procedure there can be things like
CREATE TABLE
Example data inside "Code" column:
/****** Object: StoredProcedure dbo.spName Script Date: 6/20/2016 9:10:18 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE dbo.spName
AS
DECLARE #pStartDate date, #x int
SET #pStartDate = (SELECT max(CT_ACTIVITY_DATE) FROM Table)
...
Thanks a lot in advance for any kind of support!
Your stored procedure has two spaces between CREATE and PROCEDURE, while your replace is looking for the string with a single space between the words.
To gain access to the actual code contained inside of the stored procedures, you can use something like this:
SELECT
so.name [ObjectName], so.type,
OBJECT_NAME(sc.id), sc.id, sc.colid , sc.[text]
FROM
sys.syscomments sc
INNER JOIN
sys.sysobjects so ON so.id = sc.id
WHERE
so.type = 'P'
ORDER BY
sc.id, sc.colid
Note there can be multiple entries for each object, and the colid is used to order those entries.
This is probably a simple question, but I need the act of running a report to have a "pre-event" of triggering a stored procedure. I am NOT returning data from the procedure, it is updating 2 tables in a data warehouse by doing a BULK INSERT from .csv files that have been exported from an ISAM database. The report itself uses a separate query to pull from the SQL Server tables, but the imported data is ultimately used by multiple reports so the tables need to be actually updated.
The stored procedure will run nightly as part of a regular routine, but the data affecting this particular report will be updated by users and a new .csv extract created immediately before running the report, so the report needs to fire the stored procedure to update the tables before it queries those tables itself.
I've tried searching but all the references I find seem to focus on using a stored procedure as the report query, and that's not what I'm trying to accomplish. I have a separate query for pulling data, I need to run the stored procedure in-addition-to and preceding the report query, if that makes sense.
Does anybody know how to trigger a stored procedure as the opening line(s) of my report query?
Thanks in advance for any ideas. I'm not a SQL programmer (or any kind of programmer, really) so please be fairly specific with your advice... high-level concepts that assume any existing base of knowledge on my part will probably be lost on me.
This is the stored procedure (dbo.KCSI.DataUpdate) I wrote if that helps...
--To run as a script (query) the following 2 lines should be un-commented (there are 3 of these 'run-as-a-script' comments to find)
--USE KCSI
--Go
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- To run as a script (query) the following 3 lines should all be commented out
CREATE PROCEDURE DataUpdate
AS
BEGIN
SET NOCOUNT ON
-- Declare all the needed variables.
DECLARE #CustFile varchar(255)
DECLARE #CustFile_Exists int
DECLARE #HistFile varchar(255)
DECLARE #HistFile_Exists int
DECLARE #dt varchar(30)
DECLARE #NewCustName varchar(250)
DECLARE #NewHistName varchar(250)
-- Sets Boolean value for whether or not each file exists, using T-SQL extended (i.e. DOS Shell) command
SELECT #CustFile='C:\transfer\ecallcust.csv'
EXEC Master.dbo.xp_fileexist #CustFile, #CustFile_Exists OUT
SELECT #HistFile='C:\transfer\ecallhist.csv'
EXEC Master.dbo.xp_fileexist #HistFile, #HistFile_Exists OUT
-- Sets a date variable to append to the final file name
SELECT #dt = REPLACE(Convert(varchar(30),getdate(),120),':','_')
-- Sets a variable to hold the final name. Variable use required because of the hybrid nature of the name (dos shell command + SQL variable)
SET #NewCustName = 'RENAME C:\transfer\history\ecallcust2.csv "ecallcust_'+#dt+'.csv"'
SET #NewHistName = 'RENAME C:\transfer\history\ecallhist2.csv "ecallhist_'+#dt+'.csv"'
-- Subroutine runs only if ecallcust.csv is present
IF #CustFile_Exists = 1
BEGIN
--Zaps the table
TRUNCATE TABLE custextract
-- Initially renames the file, using T-SQL extended (i.e. DOS Shell) command
EXEC master.dbo.xp_cmdshell 'RENAME C:\transfer\ecallcust.csv ecallcust2.csv'
-- Update table from CSV file
BULK INSERT custextract
FROM 'c:\transfer\ecallcust2.csv'
WITH (
ROWTERMINATOR='\n'
)
-- Move file to the history directory and rename it to include the date-time stamp using T-SQL extended (i.e. DOS Shell) command
EXEC master.dbo.xp_cmdshell 'MOVE C:\transfer\ecallcust2.csv C:\transfer\history\'
EXEC master.dbo.xp_cmdshell #NewCustName
END
-- Subroutine runs only if ecallhist.csv is present
IF #HistFile_Exists = 1
BEGIN
--Zaps the table
TRUNCATE TABLE histextract
-- Initially renames the file, using T-SQL extended (i.e. DOS Shell) command
EXEC master.dbo.xp_cmdshell 'RENAME C:\transfer\ecallhist.csv ecallhist2.csv'
-- Update table from CSV file
BULK INSERT histextract
FROM 'c:\transfer\ecallhist2.csv'
WITH (
ROWTERMINATOR='\n'
)
-- Move file to the history directory and rename it to include the date-time stamp using T-SQL extended (i.e. DOS Shell) command
EXEC master.dbo.xp_cmdshell 'MOVE C:\transfer\ecallhist2.csv C:\transfer\history\'
EXEC master.dbo.xp_cmdshell #NewHistName
END
-- To run as a script (query) the following line should be commented out
END
GO
and the report query...
WITH OrderedYTD AS
(
SELECT custextract.*, histextract.*,
ROW_NUMBER () OVER (PARTITION BY custextract.custcustno ORDER BY histextract.salesytd desc) AS RowNumber
FROM custextract
INNER JOIN histextract
ON custextract.custcustno = histextract.histcustno
WHERE (custextract.ecall = 'Y')
)
SELECT OrderedYTD.*
FROM OrderedYTD
WHERE RowNumber <= 10;
Create one stored procedure, that first updates the data and then returns the refreshed data to be loaded by the report...
CREATE PROCEDURE DataSelect
AS
BEGIN
-- Refresh Data Here
EXEC DataUpdate
-- Select Data for Report
WITH OrderedYTD AS
(
SELECT custextract.*, histextract.*,
ROW_NUMBER () OVER (PARTITION BY custextract.custcustno ORDER BY histextract.salesytd desc) AS RowNumber
FROM custextract
INNER JOIN histextract
ON custextract.custcustno = histextract.histcustno
WHERE (custextract.ecall = 'Y')
)
SELECT OrderedYTD.*
FROM OrderedYTD
WHERE RowNumber <= 10;
END