I have the following SP
CREATE PROCEDURE Studentrocedure
#Type varchar(50)
AS
BEGIN
If #Type = 'Student'
Select * from tblStudent
Else If #Type = 'Fee'
Select * from tblFee
End
END
The problem I'm having is that when I add a DataSet for a SSRS report, it pulls no fields/columns in the Fields section.
How can I resolve that?
Syntax error near the ELSE part, it should be ELSE IF.
Also no need of the extra End in the query
Instead of * explicitly mention the column names
CREATE PROCEDURE Studentrocedure
#Type varchar(50)
AS
BEGIN
IF #Type = 'Student'
Select * from tblStudent
ELSE IF #Type = 'Fee'
Select * from tblFee
END
You really can't resolve this assuming that your select * queries return different result sets. A dataset requires a deterministic set of fields. You can not dynamically determine the fields that will be included in a dataset.
If you are confident that your dynamically selected results will always and forever return the same set of columns regardless of the input given then you can explore using FMTONLY option.
Check out this link
Related
Edit: The below question was framed incorrectly by attempting to utilize the CASE WHEN expression in place of an IF statement. Please see the answer provided by schmiel. Hopefully this helps others.
I'm making a tool/report in Report Builder. The main logic is dictated by a parameter that is manually selected with a dropdown called CheckOrUpdate.
What I'm trying to accomplish is if the CheckOrUpdate parameter is set to CHECK I want the report to run a simple Query. If set to UPDATE I want the report to run an update statement.
Here is the Query:
DECLARE #SITE AS NVARCHAR(30)
DECLARE #Password AS NVARCHAR (30)
DECLARE #CheckOrUpdate AS NVARCHAR(30)
--SET #Password = 'Resend'
--SET #SITE = 'SRVCS'
--SET #CASE = '123456'
--SET #CheckOrUpdate = 'CHECK'
SELECT
CASE
WHEN #CheckOrUpdate = 'CHECK' --Just check to verify that records have been updated
THEN
(SELECT
order_num
,is_extracted
,interface_batch
,trans.item_num
,item.desc_1
,item.desc_2
FROM trans
INNER JOIN item on item.item_num=trans.item_num
WHERE order_num=#CASE AND site_code = #SITE AND is_extracted = 1 AND #Password='Resend')
WHEN #CheckOrUpdate = 'UPDATE' --Run the update
THEN
(UPDATE trans
SET is_extracted = 0 , interface_batch = NULL
WHERE order_num=#CASE AND site_code = #SITE AND is_extracted = 1 AND #Password='Resend')
--ELSE NOTHING
END
I understand that the syntax should go SET > Select > CASE WHEN. Just trying to understand how to go about running a query or running an update.
There is only one dataset in the report I'm making and the dataset is using the query above.
The commented out portion is where I was testing the logic in SQL Server.
Any ideas or references someone can point me too? Should I create another dataset and split the two? I couldn't find much in the way of what I'm looking to do.
Background: Application didn't interface info for this record due to interface outage or error and queueing stuff to be resent. Now this is being done manually just creating a tool to speed the process up for end users.
As suggested in the comments by Dan Guzman and droebi you should use a if statement like:
if #CheckOrUpdate = 'CHECK' --Just check to verify that records have been updated
begin
(SELECT
order_num
,is_extracted
,interface_batch
,trans.item_num
,item.desc_1
,item.desc_2
FROM trans t
INNER JOIN item i
on i.item_num=t.item_num
WHERE order_num=#CASE
AND site_code = #SITE
AND is_extracted = 1
AND #Password='Resend')
end
else if #CheckOrUpdate = 'UPDATE'
begin
(UPDATE trans
SET is_extracted = 0 , interface_batch = NULL
WHERE order_num=#CASE AND site_code = #SITE AND is_extracted = 1 AND #Password='Resend')
end
Or you can use else instead of else if if you only have two options.
And maybe you don't need the begin and end statement but that's the way I'm writing if statements :)
I have a table, which has columns, say
Week1,Week2, Week3 and so on.
I have a stored procedure, and based on the number input, i want to select that column.
Example, if input is 4 then I want to make the query,
select *
from table_name
where Week4=<something>
Is there any way to do this other than using dynamic query? Because this dynamic thing will be just a small part of a huge query.
The comments about normalization are right, but if you have no choice, you can use "or" clauses:
declare #inputvalue int;
set #int = 1;
select *
from <table>
where (week1 = <something> and #inputvalue = 1)
or (week2 = <something> and #inputvalue = 2)
or (week3 = <something> and #inputvalue = 3)
or (week4 = <something> and #inputvalue = 4)
This will be very slow if the tables are of any size, as you won't be using any indexes. I wouldn't suggest doing this unless you're absolutely unable to change the table structure.
I realize this isn't what you asked for, but I figured I'd point out to some people who find this what you mean by doing this as a dynamic query.
You'd just write a procedure and hold the field name in there. Assuming that the naming standard is the same, so the input value would be the week# (1,2,7,27, 123, etc.) and the field name would directly correspond (Week1, Week2, Week7, Week27, Week123, etc.)
create or replace procedure myweek(week_in varchar2)
is
dyn_sql varchar2(1000);
begin
dyn_sql := 'select * from table_name where week'||week_in||' = ''something;'' '
execute immediate dyn_sql;
end;
/
Then to call it you'd just do something like :
exec myweek(27); and it would generate the sql:
select * from table_name where week27 = 'something';
I have a Stored Procedure to get the details of Invoices
Some occasions I get the list of invoices by sending only the InvoiceID
But in some other occasions I need to get the list of invoices as per the search fields supplied by the user. To do this I send all the fields to the Stored Procedure and use those parameters as below. I included only 2 columns but there are more.
SELECT * FROM INVOICES I
WHERE
(#InvoiceNumber is null or I.InvoiceNumber = #InvoiceNumber)
and
(#PONo is null or I.PONo = #PONo)
Is there a way to send the condition for the WHERE clause as one parameter?
Yes, it is possible with Dynamic SQL, but I highly discourage to do that.
SELECT * FROM tbl WHERE #condition:
If you are considering to write the procedure
CREATE PROCEDURE search_sp #condition varchar(8000) AS
SELECT * FROM tbl WHERE #condition
Just forget it. If you are doing this, you have not completed the transition to use stored procedure and you are still assembling your
SQL code in the client.
It will also open your application to SQL Injection attacks.
You can use custom type to pass table as parameter https://msdn.microsoft.com/pl-pl/library/bb510489(v=sql.110).aspx or you can use default parameters
If you're using SQL Server 2016 or similar (check by calling select compatibility_level, name from sys.databases and seeing that your DB is 130 or higher) then you can use the string_split builtin function.
I found it works best like this (spread out for clarity)
CREATE PROCEDURE [dbo].[GetInvoices]
#InvoiceNumber int = NULL
#PONo nvarchar(1024) = NULL
AS
SELECT * from [Invoices] AS [i]
WHERE
i.InvoiceNumber = ISNULL(#InvoiceNunber, i.InvoiceNunber)
AND CASE
WHEN #PONo is null
THEN 1
ELSE (CASE
WHEN i.PONo IN (select value from string_split(#PONo, ','))
THEN 1
ELSE 0
END)
END
= 1
So if you pass in a null to either parameter it gets translated as where x = x which is always true, and if you pass in a CSV value, it selects it from a split table of values that, if present, results in the where clause being where 1=1, which is true or 0=1 if the value is not present in the input list.
So here you can pass in an invoice number, or PO number, or both, or neither and it should return what you expect.
I'm new here, and relatively new to stored procedures, so please bear with me! I've checked related questions on here and can't find anything that works in this instance.
I am trying to build a stored procedure (MS SQL Server 2005) that takes a number of passed in values and in effect dynamically builds up the SQL as you would with inline SQL.
This is where I've come unstuck.
We have (somewhat simplified for clarity):
#searchf1 varchar(100), -- search filter 1
#searchr1 varchar(100), -- search result 1
#searchf2 varchar(100), -- search filter 2
#searchr2 varchar(100), -- search result 2
#direction char(1), -- direction to order results in
AS
set nocount on
set dateformat dmy
SELECT *
FROM database.dbo.table T
WHERE T.deleted = 'n'
ORDER BY CASE #direction
WHEN 'A' THEN T.id
WHEN 'D' THEN T.id DESC
END
END
set nocount off
I have also tried the lines from ORDER BY as:
IF #direction = 'N' THEN
ORDER BY
T.id
ELSE
ORDER BY
T.id DESC
Both approaches give me an error along the lines:
"Incorrect syntax near the keyword 'DESC'." (which references the line id DESC following the final ORDER BY
As part of this stored procedure I also want to try to feed in matched pairs of values which reference a field to look up and a field to match it to, these could either be present or ''. To do that I need to add into the SELECT section code similar to:
WHERE
deleted = 'n'
IF #searchf1 <> '' THEN
AND fieldf1 = #searchf1 AND fieldr1 = #searchr1
This however generates errors like:
Incorrect syntax near the keyword 'IF'.
I know dynamic SQL of this type isn't the most elegant. And I know that I could do it with glocal IF ELSE statements, but if I did the SP would be thousands of lines long; there are going to up to 15 pairs of these search fields, together with the direction and field to order that direction on.
(the current version of this SP uses a passed in list of IDs to return generated by some inline dynamic SQL, through doing this I'm trying to reduce it to one hit to generate the recordset)
Any help greatly appreciated. I've hugely simplified the code in the above example for clarity, since it's the general concept of a nested IF statement with SELECT and ORDER BY that I'm inquiring about.
For this I would try to go with a more formal Dynamic SQL solution, something like the following, given your defined input parameters
DECLARE #SQL VARCHAR(MAX)
SET #SQL = '
SELECT
FROM
database.dbo.table T
WHERE
T.deleted = ''n'' '
--Do your conditional stuff here
IF #searchf1 <> '' THEN
SET #SQL = #SQL + ' AND fieldf1 = ' + #searchf1 + ' AND fieldr1 = ' + #searchr1 + ''' '
--Finish the query
SET #SQL = #SQL + ' ORDER BY xxx'
EXEC(#SQL)
DISCLAIMER: The use of Dynamic SQL is NOT something that should be taken lightly, and proper consideration should be taken in ALL circumstances to ensure that you are not open to SQL injection attacks, however, for some dynamic search type operations it is one of the most elegant route.
Try it this way:
SELECT * FROM database.dbo.table T WHERE T.deleted = 'n'
ORDER BY
CASE WHEN #direction='A' THEN T.id END ASC,
CASE WHEN #direction='D' THEN T.id END DESC
Source Article:
http://blog.sqlauthority.com/2007/07/17/sql-server-case-statement-in-order-by-clause-order-by-using-variable/
Another option that you might have, depending on the data type of your field, if nulls are NOT allowed, would be to do something like this.
SELECT *
FROM database.dbo.table T
WHERE T.deleted = 'n'
AND fieldf1 = COALESCE(#searchf1, fieldf1)
AND fieldr1 = COALESCE(#searchr1, fieldr1)
--ETC
ORDER BY fieldf1
This way you are not using dynamic SQL and it is fairly readable, just have the variable be null when you are looking to omit the data.
NOTE: As I mentioned this route will NOT work if any of the COALESCE columns contain null values.
I want to create a stored procedure. If the parameter is -1 then there should not be a where clause on that column else there should be a WHERE clause. What's the best way to do it without a lot of IF branching?
I checked the archive. There are a few similar questions but not exactly the same.
CREATE PROCEDURE report
(
#site int,
#promo int,
#type int
)
AS
SET NOCOUNT ON
-- I want to avoid this:
IF #site = -1 AND #promo = -1 and #type = -1
BEGIN
SELECT * from table
END
IF #site > -1 AND #promo = -1 and #type = -1
BEGIN
SELECT * from table WHERE site = #site;
END
... -- other cases
ELSE -- all parameters are > -1
BEGIN
SELECT * from table
WHERE site = #site AND promo = #promo AND type = #type
END
This works in many cases, (despite what the comments will say without trying it) because the optimiser will ignore the ISNULL bit. Only works for non-null columns
SELECT #site = NULLIF(#site, -1) ...
SELECT * from table
WHERE site = ISNULL(#site, site) ..
Otherwise, conditional WHERE which is usually bad because OR can not be optimised
SELECT * from table
WHERE (#site = -1 OR site = #site) AND (...
Or separate stored procedures (don't think you want that either)
Or use sp_executesql (avoids dynamic SQL)
How about:
SELECT * FROM table WHERE
((site = #site) OR (#site = -1)) AND
((promo = #promo) OR (#promo = -1)) AND
((type = #type) OR (#type = -1))
One caveat, though, you may find that SQL is not very intelligent in optimizing this sort of query.
why fight against the obvious, simplest solution?
seriously, the branching solution make the intent clear, and can easily be understood by others.