Let's say there is a stored procedure:
------
/****** This is my procedure
Dev
author
build date
last modified date
**********/
-- procedure starts
create procedure [temp_my_proc]
begin
declare var1, var2, .. var N
-- 1st select
select a, b, c, d
from mytable_1;
-- delete record
delete from mytable_2;
-- insert record select
insert into mytable_4
select x, y, z
from mytable_3;
end
Now I want to extract the SQL used in this stored procedure by using some SQL command. I tried using these commands:
create table #tmp
(
id int identity(1, 1),
sqlsyntax varchar(max)
);
insert into #tmp (sqlsyntax)
exec sp_helptext temp_my_proc;
select *
from #tmp;
But select * from #tmp is spitting out entire definition of the stored procedure in separate rows. How I can extract just the 3 SQL statements from the stored procedure by omitting all multiple line or single line comment present in the stored procedure?
Expected results is
select a, b, c, d
from mytable_1;
delete from mytable_2;
insert into mytable_4
select x, y, z
from mytable_3;
For modern versions of SQL Server STRING_SPLIT() is the one you need. You need to cross apply your text output against string split, splitting on the enter character i.e.
SELECT #tmp.id, lines.value
FROM #tmp
CROSS APPLY STRING_SPLIT(#tql.sqlsyntax,'
') AS lines
That will split your results into one row per line. Unfortunately you would not be able to distinguish multi-line statements from single ones.
Then you can filter by out the comments by checking
WHERE lines.value NOT LIKE '%--%' AND lines.value<> ''
However, some of your comments are enclosed by /* signs, which go across lines. Unfortunately, there is nothing you can do directly. But if you manually replaced the contents of those comments with -- or used a regex to do so you would be able to handle it.
Related
How can I find the specific value from all stored procedures in my SQL Server database?
To be more specific, I want to know the value that is inserted into the specified column on the specified table.
For example:
A database has 3 stored procedures; dbo.sp_1, dbo.sp_2, dbo.sp_3
And that database also has a [Log] table which has a [number] column
dbo.sp_1
INSERT INTO [dbo].[Log] ([number])
VALUES (1);
dbo.sp_2
INSERT INTO [dbo].[Log] ([number])
VALUES (2);
dbo.sp_3
INSERT INTO [dbo].[Log] ([number])
VALUES (4);
So, the query results I expect are as follows:
I found a snippet that was used for a somewhat-similar task, however, I did not have to parse values. This may get you close if you really have to parse the sql. Sorry, the rest of the parsing will be left up to you
DECLARE #NonEscapeTextToFindLike NVARCHAR(MAX) = 'INSERTINTO\[dbo\].\[LOG\](\[number\])VALUES('
DECLARE #NonEscapeTextToFind NVARCHAR(MAX) = 'INSERTINTO[dbo].[LOG]([number])VALUES('
;WITH Procs AS
(
SELECT
StoredProcedure = name,
StoredProcedureText = OBJECT_DEFINITION(object_id),
NoBlankText = REPLACE(REPLACE(REPLACE(REPLACE(OBJECT_DEFINITION(object_id),' ',''),CHAR(9),''),CHAR(10),''),CHAR(13),'')
FROM
sys.procedures
)
SELECT
*,
StartOfPossibleInt = CHARINDEX(#NonEscapeTextToFind, Procs.NoBlankText) + LEN(#NonEscapeTextToFind)
FROM
Procs
WHERE
Procs.NoBlankText LIKE '%'+#NonEscapeTextToFindLike+'%' ESCAPE '\'
I am using visual FoxPro and SQL. I am creating reports in visual Foxpro using SQL data. All connections are set.
here is one store procedure and I want to give parameter like
#A=''AA','BB','CC''
but because of comma it acts like separate parameters to procedure
that is used for IN operator
eg. where V_TYPE in (#A)
Parameter value come from Visual FoxPro.''AA','BB','CC'' by the VFP program.
this is single parameter for Stored procedure.
eg. EXEC testProc ''AA','BB','CC'' .
but because of comma its act like three para .
Is there problem with quotes ??seeting of quoted identifier
please tell me how should I give parameter like this.
thanks in Advance!
Unfortunately you have been given advices that you shouldn't use at all and wide open to SQL injection attacks. Instead there are multiple safe ways to do that.
One of them is to create a temp table in SQL server, insert values there and use inner join instead of an IN query.
One another way is to use a procedure to parse comma separated values to a table server side and use it in a join.
Yet another way is to pass an XML data string, create table at server side and do a join. Below is a sample using XML (for the other 2 samples look here - samples):
LOCAL lnHandle, cXML, myInQuery
TEXT TO myInQuery noshow
DECLARE #hDoc int
exec sp_xml_preparedocument #hDoc OUTPUT, ?m.cXML
SELECT * FROM [Northwind]..[Products]
WHERE ProductID IN
(
SELECT myID FROM OPENXML(#hDoc, ?m.cNodename, 1) WITH (myid int)
)
EXEC sp_xml_removedocument #hDoc
ENDTEXT
** Local cursor
CREATE CURSOR test (myID i)
INSERT INTO test VALUES (1)
INSERT INTO test VALUES (3)
INSERT INTO test VALUES (5)
** Local cursor
CURSORTOXML('test','cXML',2)
cNodeName = '/VFPData/test' && CursorToXML by default use VFPData as root, and tablename in lowercase for rows
lnHandle = SQLSTRINGCONNECT('Driver={SQL Native Client};server=.\SQLExpress;Trusted_Connection=yes')
SQLEXEC(m.lnHandle, m.myInQuery, 'result')
SQLDISCONNECT(m.lnHandle)
SELECT result
BROWSE
Note: With these types of approaches your values could be any type without the worry of having quotes or other characters in it (int, char, datetime ...).
I am trying to pass a multiple value string parameter to a table type parameter in a SQL Server 2012 stored procedure. I paste this code in the dataset of SSRS:
DECLARE #mylist clinic_list_tbltype
INSERT #mylist(n) VALUES (#pm_ChooseClinics)
EXEC sp_Skillset_Summary_With_Callbacks_Report #mylist, #pm_ChooseInterval, #pm_StartDateTime, #pm_EndDateTime
clinic_list_tbltype is a table type I created with one varchar(50) field named "n". I can call this stored procedure from SSMS o.k. like this (and it comes back very fast):
DECLARE #mylist clinic_list_tbltype
INSERT #mylist(n) VALUES ('clinicA'), ('clinicB')
EXEC sp_Skillset_Summary_With_Callbacks_Report #mylist, 'Daily', '6/3/2014', '6/9/2014'
I can run in SSRS for only one clinic (but very slow), but if I try more than one it gives an error saying that
there are fewer columns in the INSERT statement than values specified
in the Values clause
. Even running for one clnic it works, but it takes a very very long time compared to running the query in SSMS. Like 2 minutes vs. 1 second. Must be because I'm passing ('clinicA', 'clinicB') instead of ('clinicA'), ('clinicB').
How to do?
Right I need to give you some back ground 1st.
When you allow SSRS parameter to select multiple values, The selection of multiple values creates a comma deliminated string of value as one string
'value1,value2,value3'
To check values in a string using IN operator we need strings concatenated with commas something like this ....
'value1','value2','value3'
Your Proc
Now in your proc when you insert values explicitly it inserts multiple values into your table.
INSERT INTO Table_Value_Param
VALUES ('value1'), --<-- 1st value/Row
('value2'), --<-- 2nd Value/Row
('value3') --<-- 3rd Value/Row
and this gives you back the expected results as when inside your procedure you execute a statement like
SELECT *
FROM Table_Name
WHERE ColumnName IN (SELECT ColumnName
FROM Table_Value_Param)
On the other hand when you try to insert into table using SSRS report Parameter you table inserts value like
INSERT INTO Table_Value_Param
VALUES ('value1,value2,value3') --<-- One Row/Value containing all the values comma separated
Solution
Creating TVP in this situation doesnt really help, What I do is make use of dbo.Split() function inside my procedure.
You can find many definitions for split function online, for a some cool ones have a look here Split Function equivalent in tsql?
Once you have created this split function just use this function inside your procedure definition you dont even need the Table valued parameters then.
Something like this...
SELECT *
FROM Table_Name
WHERE ColumnName IN (
SELECT Value
FROM dbo.Split(#Report_Param, ',')
)
declare #Vendors_Filter nvarchar(max) = 'a,b,c'
declare #Vendors nvarchar(max)
set #Vendors =''''+replace(#Vendors_Filter,',',''',''')+''''
select #Vendors
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
I have a stored procedure which is returning a result in an xml #Data output parameter
To assign data in xml code is
SELECT #data= (
SELECT DISTINCT
CONVERT(varchar(2),u.USER_SOURCE ) + '~' +
CONVERT(varchar(20), u.[USER_ID]) + '-' +
CONVERT(varchar(10), u.DEALER_ID) as USER_DEALER_ID
FROM #users u FOR XML RAW('users'))
When I exec the procedure in SQL Server Mgmt Studio, I can see the result OK.
This procedure is been called from another procedure, and that parent procedure is used in SSRS.
In SSRS I am getting error
Query execution failed for dataset 'DataSet1'. Invalid column name
'USER_SOURCE'. Invalid column name 'USER_ID'. Invalid column name
'DEALER_ID'.
Could you please help?
Thanks,
Chetan
Here's a script which I think reproduces a problem identical to yours:
CREATE PROCEDURE TestTmpTable
#value varchar(20)
AS
BEGIN
CREATE TABLE #test (id int IDENTITY, value varchar(20));
INSERT INTO #test (value) VALUES (#value)
SELECT * FROM #test;
DROP TABLE #test;
END
GO
CREATE TABLE #test (id int IDENTITY, value2 varchar(20));
EXEC TestTmpTable 'some text';
SELECT * FROM #test;
DROP TABLE #test;
GO
DROP PROCEDURE TestTmpTable
As you can see, there are two #test tables here, one is created in the stored procedure, the other one in the batch that invokes the stored procedure. They have different structures: one has a column named value, the other a column named value2. If you run the script, you'll see this error:
Msg 207, Level 16, State 1, Procedure TestTmpTable, Line 6
Invalid column name 'value'.
I can't point you to a relevant documentation article at the moment, but to me it is evident enough that some preliminary name checking is taking place immediately before the execution of the SP. At that stage, a discrepancy between the column names referenced in the stored procedure and those actually present in the already existing table is revealed, which renders the execution impossible.
If you change value2 to value, the script will work without any problem, and there will be two row sets in the output, one with the 'some text' value, the other empty. And of course the script will work if you remove all parts related to the external #test table.
So, check the places where your procedure is called to see if any other #users table can be existing by that moment, and if so, amend the issue according to your situation.