Use result of selection statement into another selection in stored procedure - sql-server

How can I use the result of a select statement into another statement in a stored procedure in SQL Server? I am try to write this code
CREATE procedure [dbo].[ShowRequest] (#Id int)
AS
SELECT
Request.RequestId,
Request.UserId
INTO
reqTable
FROM
[User],[Request]
WHERE
Request.UserId = [User].UserId
AND
Request.RequestId = Id
/*another selection*/
SELECT
RequestProduct.ProductName
FROM
RequestProduct
/*ERROR:The multi-part identifier "ReqTable.id" could not be bound*/
WHERE
RequestProduct.RequestId = ReqTable.[id]

Try this:
CREATE procedure [dbo].[ShowRequest] (#Id int)
AS
SELECT
Request.RequestId,
Request.UserId
INTO
reqTable
FROM
[User],[Request]
WHERE
Request.UserId = [User].UserId
AND
Request.RequestId = Id
/*another selection*/
SELECT
ProductName
FROM
RequestProduct
WHERE
RequestId in
(
select id
from reqtable
)

It sounds like you actually just need to do a single selection:
SELECT
u.RequestId,
r.UserId,
rp.ProductName
FROM
[User] u
inner join
[Request] r
on
r.UserId = u.UserId
inner join
RequestProduct rp
on
rp.RequestId = r.RequestId
WHERE
r.RequestId = #Id
Generally, with SQL, you should decide what overall result you're trying to achieve, and then try to express it as a single statement - SQL Server's job (or any SQL product's) is to work out how best to construct the results. You shouldn't have to break down the problem into separate parts.

I don't know the etiquette here - this is a comment not a proposed answer but I want to make it easier for people to comment on my comment... downvote as appropriate... I don't want to just start a new question since I want the OP to see this.
You've got some alternatives but no one talked about why the first query didn't work or answered how to use the results of one query into another.
Why it didn't work: If the table "reqTable" existed and had a column named "id" at the time that your query was evaluated, SQL Server could have bound the name. You can use "eval" to put in sql that will be valid when it runs. For this problem that would be unjustifiably complex, but things like this must come up, I don't know if it's a regular tool in the toolbox of people who write a lot of stored procedures.
SQL Server 2005 and 2008 both have a feature called "CTE" you should read about that addresses the general question of "How do I use the results of one query in another query". They don't do anything subqueries absolutely can't do, but most of the time they are easier to write.

I have solved it. declare a table contains the result of first selection and use it in the second selection.
CREATE procedure [dbo].[ShowRequest] (#Id int)
AS
DECLARE #reqTable TABLE
(
ReqID int,
UserID int
)
INSERT INTO
#reqTable
SELECT
Request.RequestId AS 'ReqID',
Request.UserId
FROM
[User],[Request]
WHERE
Request.UserId = [User].UserId
AND
Request.RequestId = Id
/*another selection*/
SELECT
RequestProduct.ProductName
FROM
RequestProduct,#reqTable
WHERE
RequestProduct.RequestId = ReqID
Thanks for everyone who care about my question and spend his time to solve my problem

Related

SQL Server views and stored procedures

I am creating a web app using SQL Server on a private framework. This web app has an orderLines table that should only show the ordersLines of the specific order that is currently opened.
My framework allows to pass views as data objects to tables. So basically I can pass a orderlines view to my table and it shows all the orderlines that are in the db, but the problem is I need only the orderlines of my specific order. I have created a stored procedure that receives orderID as a parameter, but I don't know how to use it instead of a view.
The stored procedure code is below and the view is pretty much the same just without the checking of orderID.
CREATE PROCEDURE [dbo].[astp_Sales_OrdersLinesProductsByID]
(#OrderId INT)
AS
SELECT
ol.OrderID, ol.Created, ol.CreatedBy, ol.Updated, ol.UpdatedBy,
ol.CUT, ol.CDL, ol.Domain, ol.ProductID, ol.Amount,
p.ProductName, p.Supplier, p.Quantity AS TotalQuantity, p.Price,
ol.PrimKey
FROM
dbo.atbl_Sales_OrdersLines AS ol
INNER JOIN
dbo.atbl_Sales_Products AS p ON ol.ProductID = p.ProductID
WHERE
ol.OrderID = #OrderId
I was thinking that maybe there is a way to add the stored procedure to my view? Because from what I see it's not possible to pass parameters to a view.
Could anyone help me with this?
Thank you
A stored procedure can be called by using EXEC:
EXEC <sp_NameHere> #Parameter = <ParameterValueHere>
In your case:
EXEC [dbo].[astp_Sales_OrdersLinesProductsByID] #OrderId = 1
You cannot SELECT from a stored procedure like you would SELECT from a view or table.
However, I completely agree with SMor (as in: the term "View" means something completely different in SQL). You should reconsider your solution as I assume that the framework you are using will provide a method for building the query and/or filtering the results in a more efficient way.

Is it possible to create a generic SP to determine Median?

I am using SQL Server 2012. I guess what I am asking is should I continue on the path of researching the ability to create a SP (or UDF, but with #Temp tables probably involved, I was thinking SP) in order to have a reusable object to determine the median?
I hope this isn't too generic of a question, and is hosed, but I have spent some time researching the ability to determine a median value. Some possible hurdles include the need to pass in a string representation of the query that will return the data that I wish to perform the median on.
Anyone attempt this in the past?
Here is a stored proc I use to generate some quick stats.
Simply pass a Source, Measure and/or Filter.
CREATE PROCEDURE [dbo].[prc-Dynamic-Stats](#Table varchar(150),#Fld varchar(50), #Filter varchar(500))
-- Syntax: Exec [dbo].[prc-Dynamic-Stats] '[Chinrus-Series].[dbo].[DS_Treasury_Rates]','TR_Y10','Year(TR_Date)>2001'
As
Begin
Set NoCount On;
Declare #SQL varchar(max) =
'
;with cteBase as (
Select RowNr=Row_Number() over (Order By ['+#Fld+'])
,Measure = ['+#Fld+']
From '+#Table+'
Where '+case when #Filter='' then '1=1' else #Filter end+'
)
Select RecordCount = Count(*)
,DistinctCount = Count(Distinct A.Measure)
,SumTotal = Sum(A.Measure)
,Minimum = Min(A.Measure)
,Maximum = Max(A.Measure)
,Mean = Avg(A.Measure)
,Median = Max(B.Measure)
,Mode = Max(C.Measure)
,StdDev = STDEV(A.Measure)
From cteBase A
Join (Select Measure From cteBase where RowNr=(Select Cnt=count(*) from cteBase)/2) B on 1=1
Join (Select Top 1 Measure,Hits=count(*) From cteBase Group By Measure Order by 2 desc ) C on 1=1
'
Exec(#SQL)
End
Returns
RecordCount DistinctCount SumTotal Minimum Maximum Mean Median Mode StdDev
3615 391 12311.81 0.00 5.44 3.4057 3.57 4.38 1.06400795277565
You may want to take a look at a response that I had to this post. In short, if you're comfortable with C# or VB .NET, you could create a user defined CLR aggregate. We use CLR implementations for quite a few things, especially statistical methods that you may see in other platforms like SAS, R, etc.
This is easily accomplished by creating a User-Defined Aggregate (UDA) via SQLCLR. If you want to see how to do it, or even just download the UDA, check out the article I wrote about it on SQL Server Central: Getting The Most Out of SQL Server 2005 UDTs and UDAs (please note that the site requires free registration in order to read their content).
Or, it is also available in the Free version of the SQL# SQLCLR library (which I created, but again, it is free) available at http://SQLsharp.com/. It is called Agg_Median.
If using SQL Server 2008 or newer (which you are), you can write a function that accepts a table-valued parameter as input.
Create Type MedianData As Table ( DataPoint Int )
Create Function CalculateMedian ( #MedianData MedianData ReadOnly )
Returns Int
As
Begin
-- do something with #MedianData which is a table
End

Creating a new row in SSRS dataset SQL query to use in a report parameter

I am going round in circles with a bit of SQL and would appreciate some help.
I've looked up creating temp tables, nested Select statements (where advice seems to be to avoid these like the plague) and various uses of Case statements but I can't seem to find a solution that works. I'd say I'm beginner level for SQL.
I have a table with 10 relevant records. The query that works to return all the relevant entries in the table is:
SELECT
TblServAct.ServActId
,TblServAct.ServActName
FROM TblServAct
WHERE TblServAct.ServActExclude IS NULL
ORDER BY TblServAct.ServActName
Here is where I run into problems:
When the parameter (#YESNOActivity) = Yes, I want all the rows in the table to be returned. I have managed to do this with a CASE statement
...however when the parameter (#YESNOActivity) = No, I want ONLY ONE row to be returned which doesn't actually exist in the table (and should not be inserted into the actual table). The values that I need to insert are: ServActId = 101 and ServActName = 'Select YES in Parameter2 to filter by Service Activity'
For background, the reason I am doing this is because I have found SSRS report parameters to be especially difficult to conditionally format. I want to use the dataset above to return a message in a parameter (lets call it parameter2) that the user needs to select yes in (#YESNOActivity) in order to see the full selection list in parameter2.
If I can get this to work I can see lots of potential for re-use so all advice appreciated
Thanks
Eileen
I believe this should do the job, just include your parameter in the WHERE clause and UNION it with your own row of data.
SELECT
TblServAct.ServActId
,TblServAct.ServActName
FROM TblServAct
WHERE TblServAct.ServActExclude IS NULL
AND #YESNOActivity = 'Yes'
UNION ALL
SELECT
ServActId = 101
,ServActName = 'Select YES in Parameter2 to filter by Service Activity'
WHERE #YESNOActivity = 'No'
ORDER BY TblServAct.ServActName
One way is to use this query:
SELECT
TblServAct.ServActId
,TblServAct.ServActName
FROM TblServAct
WHERE TblServAct.ServActExclude IS NULL
AND 'Yes' = #YESNOActivity
UNION ALL
SELECT
101 AS ServActId
,'Select YES in Parameter2 to filter by Service Activity' AS ServActName
WHERE 'No' = #YESNOActivity
ORDER BY TblServAct.ServActName
Another way would be to create two data flows and use your variable in a constraint to send the processing to one or the other.
A third way would be to put an expression on the SQL command and use your variable to switch between two SQL statements.

Pro*C returning Not a number in the IN clause

I am trying to run an SQL from my C code using Pro*c. This is my SQL
EXEC SQL select count(1) from MY_TABLE where id IN ( :format );
id is a NUMBER(10) and format is a char array containing value 1,2,3,4,5
This is returning error with "Not a Number"
However if the format array is just a single number, its running fine.
Please let me know if someone find the error.
Thx!
IN clause accept bind variables only as (:1,:2,:3) , so you have yo know the number of bind variables before hand. Which is not likely.
Simplest way is to form a dynamic query string with hard coded values in Pro*C.
There are alternative solutions from AsKTom and My SO answer
for(i=0;i<5;i++)
{
EXEC SQL select count(1) from MY_TABLE where id IN ( :format[i] );
}
I am telling to use above code as it is too lousy, just explaining how arrays works in Pro*C. You have to give the index of the array.
Edit: I learned a new thing for this problem:- We can also use
EXEC SQL FOR 5
SELECT COUNT(1) FROM MY_TABLE WHERE id IN (:format);
EXEC SQL SELECT COUNT(1) FROM MY_TABLE WHERE id IN
(:format[0],:format[1],:format[2],:format[3],:format[4])

Trouble translating a SQL Server query to Firebird

I'm new to Firebird, and I'm having particular difficulty translating this T-SQL to Firebird SQL. This code is stored outside of the database, not in a stored procedure.
DECLARE #NumTotal int
DECLARE #NumUsed int
SELECT #NumTotal = COUNT(*)
FROM "some_Table"
WHERE "CreatedOn"=#CreatedOn
SELECT #NumUsed = COUNT(*)
FROM "some_Table"
WHERE "CreatedOn"=#CreatedOn AND "UserID" IS NOT NULL
SELECT #NumUsed AS "NumUsed", #NumTotal AS "NumTotal"
I guess from the errors and my experimentation that I'm basically forced to put this into a stored procedure somehow. Is there a way I can do this while still keeping the code out of the database?
Your code can be simplified to a single query:
SELECT COUNT(*) AS numTotal,
(SELECT COUNT(*)
FROM YOUR_TABLE
WHERE userid IS NOT NULL
AND createdon = #createdon) AS numUsed
FROM YOUR_TABLE
WHERE createdon = #createdon
Using double quotes is ANSI for escaping unusual characters, none of which I see in the example.

Resources