How can I fix a subquery in a plsql conditional? - sql

Currently, inside a loop, I have:
IF(R1.CURRENT_STATE_CODE not in (select stvstat_code from stvstat))
THEN
v_cur_state := 'FR';
ELSE
v_cur_state := R1.CURRENT_STATE_CODE;
END IF;
This fails because you cannot perform a subquery in a plsql conditional. "subquery not allowed in this context"
How could I accomplish this instead

Why not just set the value in a select?
select coalesce(max(s.stvstat_code, 'FR'))
into v_cur_state
from stvstat s
where R1.CURRENT_STATE_CODE = s.stvstat_code;
This is an aggregation query with no group by, so it always returns exactly one row. If the where filters out all rows, then the MAX() returns NULL. The COALESCE() then fills in a value in that case.

Related

Function is SQL

I want to create a function with a trigger on a relation. The trigger is supposed to not let more than 3 datasets inside of a relation. Somehow the function I created gives an exception regardless of how many datasets are inside of the Relation.
Here is my Code for the Function. so it gives back Null which apparently is enough to raise the exception. How do I make it so that when there are less than 3 it does not raise the exception?
create function myFunction() returns trigger as $$
Begin
if exists(
select case when count(*)>3 then count(*) end
from person
)
then raise exception 'Just 3 Datasets allowed';
End if;
return null;
End;
$$ language plpgsql
This construct:
if exists (select case when count(*)>3 then count(*) end
from person
)
always evaluates to true. Why? exists counts the number of rows returned by a subquery. A query that is an aggregation query with no group by always returns one row. If there are no rows in the underlying table, then the returned values would typically be NULL.
Note that exists doesn't care about the column values on the returned row. So a row with NULL values "exists" just as much as a row with other values. In fact, Postgres let's you return no columns at all! (Although I personally find that syntax a bit awkward.)
I suspect that you intend:
if (select count(*)
from person
) > 3

SQL NOT IN function not returning expected result

Total number of records in table i1450:
Total number with condition where i.BROJ is equal to field REFERENCA in other table:
Shouldn't it return difference between last two results (which is 64) when I use NOT IN in WHERE clause?
Both of columns are of varchar type.
If you have any NULL values in the REFERENCA column from the FpsPmtOrderRQ table then the NOT IN clause will not work as expected - (the reason why)
A solution is to remove NULL values from the result returned by the subselect.
SELECT COUNT(*)
FROM i1450 j
WHERE i.BROJ NOT IN (SELECT REFERENCA FROM FpsPmtOrderRQ WHERE REFERENCA IS NOT NULL)
If the sub-query returns a null value, the IN will not be true. Do NOT EXISTS instead.
select count(*)
from i1450 i
where not exists (select 1 from FpsPmtOrderRQ f
where i.broj = f.REFERENCA)
I think you need to coalesce your field to handle nulls. That is probably why you get 0.
By doing:
where coalesce(I.BROJ,'n/a') not in (select coalesce(REFERENCA,'')
or something similar, you would exclude nulls, and return a proper count.

Oracle - Error at line 4: PL/SQL: SQL Statement

I am trying to build a trigger for my database and I am getting an error and I suspect it is because of my into clause but I am not getting the reason. I was reading the documentation of it (https://docs.oracle.com/cd/B19306_01/appdev.102/b14261/selectinto_statement.htm) and there is saying:
By default, a SELECT INTO statement must return only one row.
Otherwise, PL/SQL raises the predefined exception TOO_MANY_ROWS and
the values of the variables in the INTO clause are undefined. Make
sure your WHERE clause is specific enough to only match one row
Well, at least I am trying to be sure that my where clause is returning one and just one row. Can you give me some advice about it?
CREATE OR REPLACE TRIGGER t_ticket
INSTEAD OF INSERT ON V_buyTicket FOR EACH ROW
declare ticketID number; busy number; seatRoom number;
BEGIN
select count(a.id_ticket) into busy , s.freeSeats into seatRoom
from assigned a
inner join show e on (a.id_movie= e.id_movie)
inner join rooms s on (e.id_room = s.id_room)
where a.id_session = 1 AND a.id_movie = 1
group by s.freeSeats;
if(busy < seatRoom ) then
ticketID := seq_ticket.NEXTVAL;
insert into tickets(id_ticket, type, number, cc, store) values(ticketID, :new.type, :new.number, :new.cc, :new.store);
insert into assigned (id_ticket, id_movie, id_session) values(ticketID, :new.id_movie, :new.id_session);
else
DBMS_OUTPUT.PUT_LINE('No available seats');
end if;
END;
Don't use group by if you want exactly one row returned:
select count(a.id_ticket), sum(s.freeSeats)
into busy, seatRoom
from assigned a inner join
show e
on a.id_movie = e.id_movie inner join
rooms s
on e.id_room = s.id_room
where a.id_session = 1 and a.id_movie = 1;
An aggregation query without a group by always returns exactly one row. The alternative would be to include an explicit rownum = 1 in the WHERE clause.
My guess is that you conditions are not choosing exactly one room. You might want to check on the logic.

Update columns in same table

I want to update BRCD_NEW column in table branches with the condition applied on another column BRCD in the same table, here is my code, but it returns error
single-row subquery returns more than one row
update branches set brcd_new=(
select
case
when BRCD between '5000' and '5999' then CONCAT('PK001',BRCD)
else CONCAT('PK002',BRCD)
end
from branches);
You don't need the subquery to achieve what you are doing. Use CASE statement to get the value you need and assign in to your column in SET statement:
update branches
set brcd_new =
case
when BRCD between '5000' and '5999' then CONCAT('PK001',BRCD)
else CONCAT('PK002',BRCD)
end
-- WHERE <your filters (if needed)>

ORACLE - return record by comparing foreign key to each of the returned key

I have a SQL statement which returns the "single-row subquery returns more than one row" error in Oracle:
SELECT * FROM lds_placement
WHERE fk1_account_id =
(SELECT lds_account.account_id
FROM lds_account
WHERE lds_account.fk1_consultant_id =
(SELECT consultant_id
FROM lds_consultant
WHERE UPPER(cst_name) LIKE UPPER(:app_user) || ' %' ));
How can I compare and display all records from lds_placement where the fk1_account_id is equal to either one of the returned account_id from lds_account table?
If a sub-query can return a set (of values) as opposed to a single (scalar) value, you cannot use =. Have you tried using IN instead?
(To elaborate: what would something = (1,2,3) mean... one or all of them? It seems you want something is one of (1,2,3), which in SQL is something IN (1,2,3) -- to wit, replace = with IN in your query and you should be good to go.)