Adding data to a SQL table through a stored procedure? - sql

I'm working on a learning project to understanding SQL. And one of the tasks I was given is:
For the "Create Order" button, create a stored procedure named [dbo].[CreateOrder] that creates a new order for the selected product and decrements the quantity of product in stock. If there is not enough product in stock to create the order the procedure should return a message stating so.
For this question I am given a DB that has several tables in it, but I'm not sure what the correct approach to solving this task is.

A pretty vague question, but I'd solve it with the following steps:
1) Creating a stored procedure that accepts parameters needed for the order.
2) Declare a varchar variable in the stored procedure to hold feedback for the user.
3) Using those parameters, check for product availability with a SELECT query in the stored procedure.
3) If the product is available, add the order to the appropriate table by adding an INSERT query to the stored procedure, and set the feedback variable to let the user know the order was inserted.
4) If the product is not available, set your feedback variable to say so.
5) Return the feedback variable to the user.
If you don't know how to perform any of those individual steps, hopefully that at least breaks the problem down into manageable bites to look up.

Related

Pre-execute a query when any Stored Procedure is called

Our enterprise's database is 20+ years old, and it's filled with junk, so we're planning to start deleting tables and Stored Procedures. The problem is that we don't exactly know which of those are unused, so we thought on doing a research to spot them.
I tried this answer's solution, but I think the number of queries returned are the ones in the system cache.
I have an idea of how to do it, but I don't know if it's possible:
- Create a system table with 3 columns: Stored Procedure name, number of executions, and date of last call
- The tricky part: everytime a Stored Procedure is executed, perform a query to insert/update that table.
To avoid having to modify ALL our Stored Procedures (those are easily 600+), I thought of adding a Database Trigger, but turns out it's only possible to link them to tables, not Stored Procedures.
My question is, is there any way to pre-execute a query when ANY Stored Procedure is called?
EDIT: Our Database is a SQL Server
I'm aware that I asked this question a while ago, but I'll post what I've found, so anyone who stumbles with it can use it.
When the question was asked, my goal was to retrieve the number of times all Stored Procedures were executed, to try to get rid of the unused ones.
While this is not perfect, as it doesn't show the date of last execution, I found this query, which retrieves all Stored Procedures on all databases, and displays the number of times it's been executed since it's creation:
SELECT
Db_name(st.dbid) [Base de Datos],
Object_schema_name(st.objectid, dbid) [Schema],
Object_name(st.objectid, dbid) [USP],
Max(cp.usecounts) [Total Ejecuciones]
FROM
sys.dm_exec_cached_plans cp
CROSS apply sys.Dm_exec_sql_text(cp.plan_handle) st
WHERE
Db_name(st.dbid) IS NOT NULL
AND cp.objtype = 'proc'
GROUP BY
cp.plan_handle,
Db_name(st.dbid),
Object_schema_name(objectid, st.dbid),
Object_name(objectid, st.dbid)
ORDER BY
Max(cp.usecounts)
I found this script on this webpage (it's on spanish). It also has 2 more useful scripts about similar topics.
I used this script (subsequently improved)
https://chocosmith.wordpress.com/2012/12/07/tsql-recompile-all-views-and-stored-proceedures-and-check-for-error/#more-571
To run through all of your objects and find the ones that are no longer valid.
If you want I will post my enhanced version which fixes a few things.
Then create a new schema (I call mine recycle) and move those invalid objects in there.
Now run it again.
You may end up moving a whole bunch on non functional objects out

T-SQL selecting values returned by a stored procedure

I am calling a stored procedure in my current one and it returns 3 SELECT statements.
I need the first SELECT only.
How can I achieve this? I'm new to T-SQL, in C# I would just get those variables but SQL doesn't work that way.
Is it possible to get the values it returns?
I have 3 possibilities:
1) Make a new stored proc without the last 2 sSELECTs.
2) Pass an optional parameter to the stored proc to indicate if the last 2 SELECTs should run or not. (If the parameter is not passed, the SELECTs will run by default.)
3) Not an elegant solution, but this might work for your purposes:
In the second stored proc, output the first SELECT into a global temp table, then SELECT * from that temp table. (This will keep everything the same for anything else using the stored proc.)
In the first stored proc, select * from the temp table after you call the 2nd stored proc. (This will give you the results that you are looking for.) At the end of your first stored proc, drop the global temp table.
Some caveats:
If you have several people hitting the stored proc at once, this won't work with a single global temp table- you'll have to figure out some sort of naming convention so that each user gets their own separate table to play with.
If you have a lot of data in the result set, your tempdb database isn't going to be happy.

Update Statement not updating when run from a stored procedure, but works perfectly when run manually

My first post here, so please be gentle with me :)
I have a stored procedure with which I take some source data, do some manipulation, run some update statements on it and then put the data into our main data table (I guess you could say its an ETL). The problem I have is some of the update statements I've written don't seem to have worked when the procedure has run, however, if I run them manually in a seperate query window they work perfectly.There are technically two parts to the update statement and one part updates and the other fails, which adds further complication to my trouble.
The snippet of code for the update is as follows:
UPDATE Prod_DDb.dbo.DataLoadTeleconnect
SET pCommissionValue = (SELECT Commission
FROM dbo.MappingiPhoneCommission
WHERE Prod_DDb.dbo.DataLoadTeleconnect.pMRC BETWEEN BaseMRC AND HighMRC),
pMRCBand = (SELECT MRCBand
FROM dbo.MappingiPhoneCommission
WHERE Prod_DDb.dbo.DataLoadTeleconnect.pMRC BETWEEN BaseMRC AND HighMRC)
WHERE pMapID = 'iPhone'
The code updates 2 columns in my source table where the MRC of the record falls between the base and high mrc. Commission is the value which is not updating, however MRCBand updates correctly.
The MappingiPhoneCommission table has the following columns:
BaseMRC
HighMRC
Commission
MRCBand
If anyone could shed any light onto why this would fail in the stored procedure but run fine in a new query window I would be most appreciative.
If you require any further information please let me know and i will try to supply what is needed.
Kind Regards
Tony
I see no reason for this code to act differently in a stored procedure, so I would assume the stored procedure makes a change in the data before the update. I would advise adding some checks to your stored procedure to see what the actual data at runtime is. You might start adding the following just before the update:
SELECT * FROM Prod_DDb.dbo.DataLoadTeleconnect WHERE pMapID = 'iPhone'
SELECT Commission FROM dbo.MappingiPhoneCommission, Prod_DDb.dbo.DataLoadTeleconnect
WHERE Prod_DDb.dbo.DataLoadTeleconnect.pMRC BETWEEN dbo.MappingiPhoneCommission.BaseMRC AND dbo.MappingiPhoneCommission.HighMRC
SELECT MRCBand FROM dbo.MappingiPhoneCommission, Prod_DDb.dbo.DataLoadTeleconnect
WHERE Prod_DDb.dbo.DataLoadTeleconnect.pMRC BETWEEN dbo.MappingiPhoneCommission.BaseMRC AND dbo.MappingiPhoneCommission.HighMRC
If the stored proc does not have a try catch block, then put one in. Likely the SP is failing just above this update which is why it doesn;t happen, without a trycatch block, you are probably not rolling back the whole transaction or bubbling up the actual error.
you can use FOR loop calling the columns in select statement and then updating the columns. this will help you out.

Creating entities from stored procedures which have dynamic sql

I have a stored procedure which uses a couple of tables and creates a cross-tab result set. For creating the cross-tab result set I am using CASE statements which are dynamically generated on basis of records in a table.
Is it possible to generate an entity from this SP using ADO.NET Entity framework? Cuz each time I try Get Column Information for the particular SP, it says that The selected stored procedure returns no columns.
Any help would be appreciated.
A member of my team recently encountered something like this, where a stored procedure was generating all kinds of dynamic SQL and returning calculated columns so the data context didn't know what to make of it. I haven't tried it myself yet, but this was the solution he claimed worked:
The solution is simply to put the line
“SET FMTONLY OFF;” into the proc.
This allows the Data Context to
actually generate the return class.
This works in this case, only because
the proc is doing nothing but querying
data.
Full details here:
http://tonesdotnetblog.wordpress.com/2010/06/02/solution-my-generated-linq-to-sql-stored-procedure-returns-an-int-when-it-should-return-a-table/
You only need the “SET FMTONLY OFF” in
the proc long enough to generate the
class. You can then comment it out.

Access to Result sets from within Stored procedures Transact-SQL SQL Server

I'm using SQL Server 2005, and I would like to know how to access different result sets from within transact-sql. The following stored procedure returns two result sets, how do I access them from, for example, another stored procedure?
CREATE PROCEDURE getOrder (#orderId as numeric) AS
BEGIN
select order_address, order_number from order_table where order_id = #orderId
select item, number_of_items, cost from order_line where order_id = #orderId
END
I need to be able to iterate through both result sets individually.
EDIT: Just to clarify the question, I want to test the stored procedures. I have a set of stored procedures which are used from a VB.NET client, which return multiple result sets. These are not going to be changed to a table valued function, I can't in fact change the procedures at all. Changing the procedure is not an option.
The result sets returned by the procedures are not the same data types or number of columns.
The short answer is: you can't do it.
From T-SQL there is no way to access multiple results of a nested stored procedure call, without changing the stored procedure as others have suggested.
To be complete, if the procedure were returning a single result, you could insert it into a temp table or table variable with the following syntax:
INSERT INTO #Table (...columns...)
EXEC MySproc ...parameters...
You can use the same syntax for a procedure that returns multiple results, but it will only process the first result, the rest will be discarded.
I was easily able to do this by creating a SQL2005 CLR stored procedure which contained an internal dataset.
You see, a new SqlDataAdapter will .Fill a multiple-result-set sproc into a multiple-table dataset by default. The data in these tables can in turn be inserted into #Temp tables in the calling sproc you wish to write. dataset.ReadXmlSchema will show you the schema of each result set.
Step 1: Begin writing the sproc which will read the data from the multi-result-set sproc
a. Create a separate table for each result set according to the schema.
CREATE PROCEDURE [dbo].[usp_SF_Read] AS
SET NOCOUNT ON;
CREATE TABLE #Table01 (Document_ID VARCHAR(100)
, Document_status_definition_uid INT
, Document_status_Code VARCHAR(100)
, Attachment_count INT
, PRIMARY KEY (Document_ID));
b. At this point you may need to declare a cursor to repetitively call the CLR sproc you will create here:
Step 2: Make the CLR Sproc
Partial Public Class StoredProcedures
<Microsoft.SqlServer.Server.SqlProcedure()> _
Public Shared Sub usp_SF_ReadSFIntoTables()
End Sub
End Class
a. Connect using New SqlConnection("context connection=true").
b. Set up a command object (cmd) to contain the multiple-result-set sproc.
c. Get all the data using the following:
Dim dataset As DataSet = New DataSet
With New SqlDataAdapter(cmd)
.Fill(dataset) ' get all the data.
End With
'you can use dataset.ReadXmlSchema at this point...
d. Iterate over each table and insert every row into the appropriate temp table (which you created in step one above).
Final note:
In my experience, you may wish to enforce some relationships between your tables so you know which batch each record came from.
That's all there was to it!
~ Shaun, Near Seattle
There is a kludge that you can do as well. Add an optional parameter N int to your sproc. Default the value of N to -1. If the value of N is -1, then do every one of your selects. Otherwise, do the Nth select and only the Nth select.
For example,
if (N = -1 or N = 0)
select ...
if (N = -1 or N = 1)
select ...
The callers of your sproc who do not specify N will get a result set with more than one tables. If you need to extract one or more of these tables from another sproc, simply call your sproc specifying a value for N. You'll have to call the sproc one time for each table you wish to extract. Inefficient if you need more than one table from the result set, but it does work in pure TSQL.
Note that there's an extra, undocumented limitation to the INSERT INTO ... EXEC statement: it cannot be nested. That is, the stored proc that the EXEC calls (or any that it calls in turn) cannot itself do an INSERT INTO ... EXEC. It appears that there's a single scratchpad per process that accumulates the result, and if they're nested you'll get an error when the caller opens this up, and then the callee tries to open it again.
Matthieu, you'd need to maintain separate temp tables for each "type" of result. Also, if you're executing the same one multiple times, you might need to add an extra column to that result to indicate which call it resulted from.
Sadly it is impossible to do this. The problem is, of course, that there is no SQL Syntax to allow it. It happens 'beneath the hood' of course, but you can't get at these other results in TSQL, only from the application via ODBC or whatever.
There is a way round it, as with most things. The trick is to use ole automation in TSQL to create an ADODB object which opens each resultset in turn and write the results to the tables you nominate (or do whatever you want with the resultsets). you can also do it in DMO if you enjoy pain.
There are two ways to do this easily. Either stick the results in a temp table and then reference the temp table from your sproc. The other alternative is to put the results into an XML variable that is used as an OUTPUT variable.
There are, however, pros and cons to both of these options. With a temporary table, you'll need to add code to the script that creates the calling procedure to create the temporary table before modifying the procedure. Also, you should clean up the temp table at the end of the procedure.
With the XML, it can be memory intensive and slow.
You could select them into temp tables or write table valued functions to return result sets. Are asking how to iterate through the result sets?