SQL with clause in stored procedure - sql

Is it possible to define a with clause in a stored procedure and use it in if else statements because I always get an error?
BEGIN
WITH Test (F, A) AS
(
SELECT FM.ID, FM.Name
FROM [Test.Abc] FM
INNER JOIN [Organization] O on O.ABCID = FM.ID
)
IF(#var = 'case1')
BEGIN
SELECT *
FROM Test F
WHERE NOT F.ID = 'someID'
END
I always get an "Incorrect syntax" error before the if statement
If I move the with clause into the if statement it works fine. But I need the with statement outside to reuse it in different if else statements.

Here's another version of the same answers you're getting:
Your with common table expresson has to be in the same statement as the query that calls it, and it has to be referenced by a query (or other cte) or it is a syntax error.
Reference the documentation Guidelines for Creating and Using Common Table Expressions.
BEGIN -- doing stuff
-- .... doing stuff over here
IF(#var = 'case1')
BEGIN
with Test (F, A) as (
select FM.ID, FM.Name from [Test.Abc] FM
inner join [Organization] O on O.ABCID = FM.ID
)
select * from Test F
where not F.ID = 'someID'
END
-- .... and doing some other stuff over here too
END -- done with this stuff

Just use a temporary table or table variable. The scoping rules of SQL Server ensure that such a table is dropped at the end of the procedure:
BEGIN
select FM.ID, FM.Name
into #test
from [Test.Abc] FM inner join
[Organization] O
on O.ABCID = FM.ID;
IF(#var = 'case1')
BEGIN
select *
from #Test F
where not F.ID = 'someID'
END;
This has the advantage that you can add indexes to the table, and these might improve performance.

WITH is not a standalone, it always a part of a whole statement and only one statement.
It is not recognizable outside the scope ofits statement.
BEGIN
with my_cte (n) as (select 1+1)
select * from my_cte
-- The following statement yields the error "Invalid object name 'my_cte'."
-- select * from my_cte
END

Related

Select query, insert into table, and return initial query in postgres

I have a rather complex plpgsql stored procedure and I need to select from multiple tables and insert as well.
This is part of what I currently have.
BEGIN
RETURN query
SELECT domains.id, webpages.id as page_id ...
FROM domains
LEFT JOIN domain_settings
ON domain_settings.domain_id = domains.id
RIGHT JOIN webpages
ON webpages.domain_id = domains.id
LEFT JOIN subscriptions
ON webpages.id = subscriptions.page_id
AND subscriptions.user_id = query_user_id
AND subscriptions.comment_id IS NULL
WHERE domains.domain_address = query_domain_url
IF NOT FOUND THEN ...
END;
$$ language plpgsql;
Now, I would like add an insert query into another table using certain values from the return query before the 'if not found then' statement:
INSERT INTO page_visits (domain_id, page_id)
SELECT id, page_id FROM ?? (return query statement)
And after the insert, I want to return the initial return query values. How do I go about doing this? I tried using WITH AS statements, but I can't seem to get it to work
A set-returning PL/pgSQL function builds the return stack while processing the function body. There is no way to access that return stack from within the same function. You could nest the function. Or use a temporary table.
But using a CTE is probably the simplest way for the cas at hand. Going out on a limb, you may be looking for something like this:
CREATE OR REPLACE FUNCTION demo(query_user_id int, query_domain_url text)
RETURNS TABLE (c1 int, c2 int)
LANGUAGE plpgsql AS
$func$
BEGIN
RETURN QUERY
WITH sel AS (
SELECT d.id, w.id as page_id ...
FROM webpages w
JOIN domains d ON d.id = w.domain_id
LEFT JOIN domain_settings ds ON ds.domain_id = d.id
LEFT JOIN subscriptions s ON s.page_id = w.id
AND s.user_id = query_user_id -- origin?
AND s.comment_id IS NULL
WHERE d.domain_address = query_domain_url -- origin?
)
, ins AS (
INSERT INTO tbl (col1, col2)
SELECT main.id, sel.page_id
FROM (SELECT 'foo') AS main(id)
LEFT JOIN sel USING (id) -- LEFT JOIN ?
)
TABLE sel;
IF NOT FOUND THEN
-- do something
END IF;
END
$func$;
Remember, if the transaction does not commit successfully, the INSERT is also rolled back.
The final TABLE sel is just short syntax for SELECT * FROM sel. See:
Is there a shortcut for SELECT * FROM?

MSSQL Check if a SELECT statement will have rows, if yes, then execute the same SELECT statement

I would like to execute a SELECT statement in a stored procedure, but before executing, I have to know if it will have rows. If not, I have to jump to a specified Label, and set an output.
My current method works just fine, but I will need more of these in several procedures, and I was wondering if I could do this without code repetition (and without Ctrl+C, Ctrl+V)
(It's just a sample code, not my real code)
IF EXISTS (
SELECT *
FROM sample s
INNER JOIN sample2 s2 ON s.Id = s2.sId
WHERE s2.number = #input
)
BEGIN
INSERT INTO #Temp
SELECT *
FROM sample s
INNER JOIN sample2 s2 ON s.Id = s2.sId
WHERE s2.number = #input
END
ELSE
BEGIN
SET #noresult = 1;
GOTO label;
END
Thank you for helping!
Why not just load the table and check afterwards?
INSERT INTO #Temp
SELECT *
FROM sample s JOIN
sample2 s2 ON s.Id = s2.sId
WHERE s2.number = #input;
IF NOT EXISTS (SELECT 1 FROM #temp)
BEGIN
SET #noresult = 1;
GOTO label;
END;
If #noresult is the same for all the tables, you can have just one if after loading a bunch of temp tables.

Error when creating procedure with existing query

I have a query that I am trying to use within a procedure. The query works exactly as it should but once I place it inside of the BEGIN and END of the procedure, it tells me "name is already used by an existing object". Not sure what this means, any help would be great.
Here is the orignal query:
SELECT
course.course_no,
course.description,
section.section_no,
enrcount.countofenrollment
FROM
course
INNER JOIN section ON course.course_no = section.course_no
INNER JOIN (
SELECT
section_id,
COUNT(*) countofenrollment
FROM
enrollment
GROUP BY
section_id
) enrcount ON section.section_id = enrcount.section_id
WHERE
enrcount.countofenrollment < 6;
Here is the procedure:
CREATE PROCEDURE PRC_Enrollment
AS
BEGIN
SELECT
course.course_no,
course.description,
section.section_no,
enrcount.countofenrollment
FROM
course
INNER JOIN section ON course.course_no = section.course_no
INNER JOIN (
SELECT
section_id,
COUNT(*) countofenrollment
FROM
enrollment
GROUP BY
section_id
) enrcount ON section.section_id = enrcount.section_id
WHERE
enrcount.countofenrollment < 6;
END;
Use create or replace procedure.. instead of just create procedure.. in order to resolve the error youve mentioned above. That means already the procedure name has been used.
First of all INTO clause should be added to return the values of the columns
CREATE OR REPLACE PROCEDURE PRC_Enrollment AS
v_course_no course.course_no%type;
v_description course.description%type;
v_section_no section.section_no%type;
v_count_enrl int;
BEGIN
SELECT c.course_no, c.description, s.section_no, e.countofenrollment
INTO v_course_no, v_description, v_section_no , v_count_enrl
FROM course c
JOIN section s
ON c.course_no = s.course_no
JOIN (SELECT section_id, COUNT(*) countofenrollment
FROM enrollment
GROUP BY section_id) e
ON s.section_id = e.section_id
WHERE e.countofenrollment < 6;
EXCEPTION WHEN NO_DATA_FOUND THEN NULL;
END;
/
Alternatively you can return those values as out parameters by using
CREATE OR REPLACE PROCEDURE PRC_Enrollment(
v_course_no out course.course_no%type,
v_description out course.description%type,
v_section_no out section.section_no%type,
v_count_enrl out int
) AS
instead of returning them as local variables as in the first case.
alias your tables with a letter, usually preferred the first letter
of the tables
add exception handling, at least against the case no data found in
order not to get error
Btw, you get such an error, if OR REPLACE has not been added after CREATE keyword for the second and subsequent compilations.

Avoiding creating the same query twice in SQL

I have a pretty much simple and self explanatory SQL statement:
ALTER PROCEDURE [dbo].[sp_getAllDebatesForAlias](#SubjectAlias nchar(30))
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
SELECT *
FROM tblDebates
WHERE (SubjectID1 in (SELECT SubjectID FROM tblSubjectAlias WHERE SubjectAlias = #SubjectAlias))
OR (SubjectID2 in (SELECT SubjectID FROM tblSubjectAlias WHERE SubjectAlias = #SubjectAlias)) ;
END
I am certain that there is a way to make this statement more efficient, at least get rid of that multiple creation of the same table in the in section, i.e., the
SELECT SubjectID FROM tblSubjectAlias WHERE SubjectAlias = #SubjectAlias
part.
Any ideas?
Try:
select d.* from tblDebates d
where exists
(select 1
from tblSubjectAlias s
where s.SubjectID in (d.SubjectID1, d.SubjectID2) and
s.SubjectAlias = #SubjectAlias)
SELECT d.*
FROM tblDebates d
inner join tblSubjectAlias s on s.SubjectID in (d.SubjectID1, d.SubjectID2)
where s.SubjectAlias = #SubjectAlias

DB2 set default when null on join / Open table after FETCH

This is kind of a double question, just thinking of ways to accomplish my problem.
Also, I'm pretty new to DB2 and stored procedures, so bear with me.
I'm creating a stored procedure that gets a value from two tables using a Left Join statement. This will result in some of the values in the second table returning a null value (since they don't exist in tableB).
DECLARE CURSOR C1 WITH RETURN FOR
select a.name, a.title, b.order from tableA a
left outer join tableB b on a.name = b.name;
Now, I need some way to set these null values to a default value of 0.
The program I'm working with can do it ( CAST-IRON ) but if the result set is too large, it slows down the orchestrations and truncates the job log. So I'm trying to figure it out using the stored procedure.
My first thought was to use the FETCH INTO statement and a WHILE loop.
WHILE AT_END = 0 DO
FETCH C1 INTO CHNAME, CHTITLE, CHORDER;
IF CHORDER IS NULL
THEN SET CHORDER = 0;
END IF;
IF SQLCODE = 100
THEN SET AT_END = 1;
END IF;
END WHILE;
But it seems like that would require a temporary table being created, and declaring another cursor with that table, using an insert command after the 'FETCH INTO'. So I was wondering if there were another way to do this, or to automatically set a default in the select statement?
Set a default in the select statement using COALESCE.
DECLARE CURSOR C1 WITH RETURN FOR
select a.name, a.title, COALESCE(b.order,0) as order
from tableA a
left outer join tableB b on a.name = b.name;