I am trying to re-create a stored procedure for testing a specific application scenario, but I don't have enough access to view the original stored procedure. I can see the application runs a query like:
exec dbo.SP_GET_WORKSTATIONS #WORKSTATION_FID=N'%',#VALID_IND=N'%',#WORKSTATION_DOMAIN=N'%',#WORKSTATION_PID=N'%'
Based on the input data type results of the original stored procedure, and results it returned I built a stored procedure like this:
CREATE PROCEDURE [dbo].[SP_GET_WORKSTATIONS]
#WORKSTATION_FID varchar(32),
#VALID_IND char(1),
#WORKSTATION_DOMAIN char(20),
#WORKSTATION_PID varchar(10)
AS
SELECT
WORKSTATION_FID as Code,
VALID_IND as ValidInd,
WORKSTATION_DOMAIN As Name,
WORKSTATION_PID as PId
FROM
[dbo].[L_WORKSTATIONS]
WHERE
WORKSTATION_FID LIKE #WORKSTATION_FID AND
VALID_IND LIKE #VALID_IND AND
WORKSTATION_DOMAIN LIKE #WORKSTATION_DOMAIN AND
WORKSTATION_PID LIKE #WORKSTATION_PID;
GO
However this doesn't return any data, however if I run
SELECT
WORKSTATION_FID as Code,
VALID_IND as ValidInd,
WORKSTATION_DOMAIN As Name,
WORKSTATION_PID as PId
FROM
[dbo].[L_WORKSTATIONS]
WHERE
WORKSTATION_FID LIKE '%' AND
VALID_IND LIKE '%' AND
WORKSTATION_DOMAIN LIKE '%' AND
WORKSTATION_PID LIKE '%'
I get results. If I change the LIKE in stored procedure to = and specify exact parameters, the stored procedure works.
Your #WORKSTATION_DOMAIN parameter should be varchar not char.
Trailing space is significant in the like pattern and % followed by 19 spaces (padded out to 20 characters) will try and match content ending with 19 spaces.
Trailing space is ignored in equality comparisons.
Be aware that there may be the need to pass in different parameters that like % and depending on the datatypes your proc might not work. More than likely the original was created using dynamic SQL so it could handle a list of values and different datatypes.
Related
In SQL Server, I have an existing Document_Add stored procedure that works and returns a good DocID value (in Visual Studio vb code) and cannot change. Calling it like this in SQL:
EXEC #DocID = PADS2.dbo.Document_Add #SystemCode...
This runs the stored procedure, but #DocID is always 0 (whether declared as INT or varchar).
Expecting #DocID to be 2594631 or similar.
Any ideas?
I always say RTFM - read the fine manual provided by microsoft.
https://learn.microsoft.com/en-us/sql/t-sql/statements/create-procedure-transact-sql?view=sql-server-ver16
1 - Example D shows how to use input parameters.
2 - Example F show how to use output parameters.
Just remember, input and output parameters are scalar, not tables.
If you do need to input of a table look at Example G.
3 - Example G - how to pass a table value parameter
4 - Example B - return multiple result sets.
If you execute two SELECT statements in the procedure, you will have MARS (multiple active result sets).
By default, a procedure returns a value of zero. It is typical used to indicate if the procedure was a success. You can code a non zero value to indicate an error.
Always read the docs!
<If this is not the place to follow up, please advise.>
Credit to rjs123431:
SQL SP that ends like this:
...
SELECT #Rslt = CONVERT(VARCHAR(2000),#NewId)
select #Rslt;
END
Returns a string '2680914' in vb:
sDocid = DA.ExecScalarString(EXEC PADS2.DBO.[Document_Add] 'C', ...)
But returns 0 when called from SQL like this:
EXEC #DocID = PADS2.dbo.Document_Add #SystemCode...
This returns correct DocID (2680914) when using a Temp Table like this:
INSERT INTO #TempTable EXEC PADS2.dbo.Document_Add #SystemCode...
set #sDocID = (SELECT DocID FROM #TempTable)
How to stop showing messages from procedure?
Currently, the problem is I have created a stored procedure Procedure A. It executes another procedure B from its code, and the B procedure executes yet other procedures C,D,E from its code.
The problem is when the A procedure executes, it shows 4 result sets like 0,1 or another values. But I want to show only the result from procedure A. How can I achieve this? I can't change the other procedures B,C,D,E because they also perform their individual tasks.
If you need clarification please ask.
You can try the followings:
if any of the sub procedures is returning only one row set and it is static (same columns with the same type are always returned), you can materialized the result set in temporary tables (or table variables)
For example, let's say that procedure X returns a table with two int columns. You
materialized the result like this:
CREATE TABLE #X
(
A INT
,B INT
);
INSERT INTO #X
EXEC usp_X;
Add additional parameter to the sub procedures or use any of the existing ones to not return the row set(s) if certain option is passed.
For example, add #MiscSettings parameter to your existing procedure X:
ALTER PROCEDURE usp_X AS
(
#Param01 INT
,#Parame02 VARCHAR(12)
,...
,#MiscSettings NVARCHAR(MAX) = NULL
)
The parameter is not mandatory, so you are not going to break any existing reference. Then in the procedure you can check if [DoNotReturnResultSet] string is passed in the #MiscSettings to not return the result sets. Existing references will continue to work because by default the row sets are returned.
IF Option Is Not Passed
BEGIN;
SELECT ...
END;
In both ways you can suffer if someone change the code of the sub routines. For example, if a type of returned column is changed, or someone add additional row set without checking if your special option is passed.
Note, in the second technique, if you do not like to add additional parameter, you can use some of the existing strings (for example). Just check if the string contains your option and then replace it.
I'm trying to create a wrapper in T-SQL for a procedure where I'm not sure what the data types are. I can run the wrapper without an INSERT INTO statement and I get the data just fine, but I need to have it in a table.
Whenever I use the INSERT INTO I get an error:
Column name or number of supplied values does not match table definition
I've parsed back through my code and can't see where any column names don't match up, so I'm thinking that it has to be a data type. I've looked through the procedure I'm wrapping to see if I can find what the data types are, but some aren't defined there; I've referenced the tables they pull some data from to find the definitions; I've run SQL_VARIANT_PROPERTY on all of the data to see what data type it is (although some of them come up null).
Is there some better way for me to track down exactly where the error is?
I think you can find out your stored procedure result schema, using sp_describe_first_result_set (available from SQL2012) and FMTONLY. Something like this:
EXEC sp_describe_first_result_set
#tsql = N'SET FMTONLY OFF; EXEC yourProcedure <params are embedded here>'
More details can be found here.
However, if I remember correctly, this works only if your procedure used deterministic schemas (no SELECT INTO #tempTable or similar things).
One trick to find out the schema of your result is to actually materialize the result into ad-hoc created table. However, this is not easy since SELECT INTO does not work with EXEC procedure. One work-around is this:
1) Define a linked-server to the instance itself. E.g. loopback
2) Execute your procedure like this (for SQL 2008R2):
SELECT * INTO tempTableToHoldDataAndStructure
FROM OPENQUERY(' + #LoopBackServerName + ', ''set fmtonly off exec ' + #ProcedureFullName + ' ' + #ParamsStr
where
#LoopBackServerName = 'loopback'
#ProcedureFullName = loopback.database.schema.procedure_name
#ParamsStr = embedded parameters
For SQL2012 I think the execution might fail if RESULT SETS are not provided (i.e. schema definition of the expected result, which is kind of a chicken-egg problem in this case):
' WITH RESULT SETS (( ' + #ResultSetStr + '))'');
Okay, I have a solution to my problem. It's tedious, but tedious I can do. Randomly guessing is what drives me crazy. The procedure I'm wrapping dumps 51 columns. I already know I can get it to work without putting anything into a table. So I decided to comment out part of the select statement in the procedure I'm wrapping so it's only selecting 1 column. (First I made a copy of that procedure so I don't screw up the original; then I referenced the copy from my wrapper). Saved both, ran it, and it worked. So far so good. I could have done it line by line, but I'm more of a binary kind of guy, so I went about halfway down--now I'm including about 25 columns in both the select statement and my table--and it's still working. Repeat procedure until it doesn't work any more, then backtrack until it does again. My error was in identifying one of the data types followed by "IDENTITY". I'm not sure what will happen when I leave that out, but at least my wrapper works.
I am trying to input a tuple of room here is my code for insert
create proc spInsertToRoom
#room_name varchar(50),
#room_status varchar(50)='Available',
#room_rate float
AS
BEGIN
INSERT INTO tblRoom(room_name,room_status,room_rate)
SELECT #room_name,#room_status,#room_rate
END
I want the status to be automaticly available. Then when I input a value
it just keeps on saying
exec [spInsertToRoom]'A102',3500
Procedure or function 'spInsertToRoom' expects parameter '#room_rate',
which was not supplied.
But when I try this
exec [spInsertToRoom]'A103',#room_rate=4000
It worked!
I'm Just wondering why is it needed to to input the #room_rate=4000 whereas what I saw on youtube is a person just input a variable just like my former code?
In this case you need to name the parameters in your call. With your code what is happening is it will implicitly convert 3500 to varchar(50) and then not find a value for room_rate.
exec [spInsertToRoom] #room_name = 'A102', #room_rate = 3500
I would make a couple recommendations. First is not to use float when you want the number to be precise. Float is an approximate datatype. Something like NUMERIC(9, 2) would be a better choice.
My second recommendation is to drop the prefix from your names. It is just noise when looking for a procedure name and it isn't likely to get confused with something else. If that were my system the name for this proc would be Room_Insert. That way the procs will sort by the object they are dealing with and the verb is at the end. Room_Update, Room_Delete etc will all be next to other in the list of procedures when sorted alphabetically (like in SSMS).
I have a TELEPHONE_NUMBER as a varchar like this:
Value : "1112223344"
And I need to add "-" to the value like this:
111-222-33-44
So how can I add - to my telephone number value in my SQL Server stored procedure?
CREATE PROCEDURE SP_TELEPHONE_NUMBER
(#TELEPHONE_NUMBER VARCHAR(4000))
AS
BEGIN
INSERT INTO DOSYA_ARSIV(TELEPHONE_NUMBER)
VALUES(#TELEPHONE_NUMBER)
END
Just an alternative:
select SUBSTRING('1112223344',1,3)+'-'+
SUBSTRING('1112223344',4,3)+'-'+
SUBSTRING('1112223344',7,2)+'-'+
SUBSTRING('1112223344',9,2)
In your case:
CREATE PROCEDURE SP_TELEPHONE_NUMBER
(#TELEPHONE_NUMBER VARCHAR(4000))
AS
BEGIN
INSERT INTO DOSYA_ARSIV(TELEPHONE_NUMBER)
VALUES
(
SUBSTRING(#TELEPHONE_NUMBER,1,3)+'-'+
SUBSTRING(#TELEPHONE_NUMBER,4,3)+'-'+
SUBSTRING(#TELEPHONE_NUMBER,7,2)+'-'+
SUBSTRING(#TELEPHONE_NUMBER,9,2)
)
END
As noobob has mentioned in his comment, you may have this as an INT type (INT,BIGINT or something similar) and just handle the way it is displayed in the front end. For instance in C# you would have it as:
TELEPHONE_NUMBER.ToString("###-###-##-##");
Another comment would be that defining the expected argument as VARCHAR(4000) is way too much. Though it might not be very bad, it is a good point to define arguments or variables as close to expected input as you can. In your case i would say that something like VARCHAR(30) would be enough.
Use STUFF function in the MS SQL server
SET #TELEPHONE_NUMBER=STUFF(STUFF(STUFF(#TELEPHONE_NUMBER,4,0,'-'),8,0,'-'),11,0,'-')