Query Blocks with SELECT INTO - sql

QUERY is self explanatory.
DECLARE
ID NUMBER (10);
ISFIRST NUMBER (1);
BEGIN
SELECT M.ID, M.ISFIRST
INTO ID, ISFIRST
FROM MERCHANT M
WHERE M.PHONE = :1;
IF (ISFIRST=1) THEN
SELECT * FROM CUSTOMER C WHERE C.ISFIRST=1 AND C.MERCHANTID = ID;
ELSE
SELECT * FROM CUSTOMER C WHERE C.ISFIRST=0 AND C.MERCHANTID = ID;
END IF;
END;
This query gives me "PLS-00428: an INTO clause is expected in this SELECT statement".
I need to select data from CUSTOMER table depending on MERCHANT.ISFIRST and MERCHANT.ID.
Any workaround or little explanation what went wrong would be appreciated.
PS: The problem is solved with UNION ALL statement. This question needs to be closed.

The SELECT statements have nothing wrong, except that you are not doing anything with them. I mean the last two. What do you want them to do? Produce a result that is going to be discarded? PL/SQL does not allow it.
Just to try if this is correct, you can pick a single field and do SELECT {aField} INTO {aVariable} instead of SELECT *.
IF( ISFIRST = 1 ) THEN
SELECT {aField} INTO {aVariable} FROM CUSTOMER C WHERE C.ISFIRST=1 AND C.MERCHANTID = ID;
ELSE
SELECT {aField} INTO {aVariable} FROM CUSTOMER C WHERE C.ISFIRST=0 AND C.MERCHANTID = ID;
END IF;
Don't forget to declare {aVariable}!!!

I think this query will do the same thing :
SELECT C.*
FROM CUSTOMER C
INNER JOIN MERCHANT M ON C.MERCHANTID = M.ID AND
C.ISFIRST = M.ISFIRST AND
M.PHONE = :1;

Related

Oracle Trigger PLS-00103. Query with multiple rows in temporal variable

I'm trying to write a trigger that raises error when someone attempts to rate a product which has not been bought. I have come up with a query to get the purchase history of a client :
SELECT nref
FROM CartClient a
INNER JOIN PaidCart b
ON a.idpurchase = b.idpurchase
INNER JOIN CartDetails c
ON b.idpurchase = c.idpurchase
WHERE a.Id = '12345672X'
which works fine.
So the next trigger should check if the product of a new rating (:new.NRef) has not been bought, namely is not part of the result of the last query (NOT IN).
CREATE OR REPLACE TRIGGER cant_rate
BEFORE INSERT ON Rating
FOR EACH ROW
BEGIN
IF (:new.NRef NOT IN (SELECT nref FROM CartClient a
INNER JOIN PaidCart b
ON a.idpurchase = b.idpurchase
INNER JOIN CartDetails c
ON b.idpurchase = c.idpurchase
WHERE a.Id =:new.Id)) THEN
RAISE_APPLICATION_ERROR(-20603,'Cant rate a not bought product');
END IF;
END;
I get error:
"PLS-00103:Encountered the symbol “INNER” when expecting one of".
I have tried to store the result of the query in a temporal variable using SELECT INTO. But, it's a multiple row result. What could I do?
How about such an approach?
CREATE OR REPLACE TRIGGER cant_rate
BEFORE INSERT ON Rating
FOR EACH ROW
DECLARE
l_exists NUMBER(1) := 0;
BEGIN
SELECT MAX(1)
INTO l_exists
FROM dual
WHERE EXISTS (SELECT nref FROM CartClient A
INNER JOIN PaidCart b
ON A.idpurchase = b.idpurchase
INNER JOIN CartDetails C
ON b.idpurchase = C.idpurchase
WHERE A.ID = :NEW.ID
AND a.nref = :NEW.nref --> is it "a.nref"?
);
IF l_exists = 0 THEN
RAISE_APPLICATION_ERROR(-20603,'Cant rate a not bought product');
END IF;
END;
Note remark "is it a.nref?" - you never said which table owns that nref column so I presumed it is cartclient; modify it, if necessary.
As of your attempt: if you executed it in SQL*Plus or SQL Developer, you'd see a message regarding subquery in IF; something like this:
LINE/COL ERROR
--------- -------------------------------------------------------------
2/3 PL/SQL: Statement ignored
2/21 PLS-00405: subquery not allowed in this context
So, no - you can't do it that way.
You probably don't get the actual error: PLS-00405 subquery not allowed in this context.
Simple stupid test:
BEGIN
IF 1 NOT IN ( SELECT 2 FROM DUAL )
THEN
NULL;
END IF;
END;
/
You can adjust your trigger in this way or similar:
CREATE OR REPLACE TRIGGER cant_rate
BEFORE INSERT ON Rating
FOR EACH ROW
DECLARE
l_test PLS_INTEGER;
BEGIN
SELECT CASE
WHEN :new.NRef NOT IN ( SELECT nref
FROM CartClient a
INNER JOIN PaidCart b
ON a.idpurchase = b.idpurchase
INNER JOIN CartDetails c
ON b.idpurchase = c.idpurchase
WHERE a.Id = :new.Id
)
THEN 1
ELSE 0
END
INTO l_test;
FROM DUAL;
IF l_test = 1
THEN
...
END IF;
END;
/

postgres: query results into variables to be used later

I have what will end up being a complex query where certain parts will often be repeated. I would therefore like to store the results of some sub queries into variables which can then be used in the main query.
For example I would like to set the variable 'variable_id' to be equal to a SELECT query and variable_school_id to be equal to another SELECT query:
variable_id integer := (SELECT id FROM account WHERE email = 'test#test.com');
variable_school_id integer := (SELECT school FROM account WHERE email = 'test#test.com');
Then I would like to make use of those variables in a query that would look like:
select * from doctor where account_id = variable_id AND school = variable_school_id ;
How do I go about doing this?
Can't you just use CTEs?
with params as (
SELECT id, school
FROM account
WHERE email = 'test#test.com'
)
select d.*
from params cross join
doctor d
on d.account_id = params.id and d.school = params.school;

How to declare and assign value to a variable before query?

I have a complicated query that has to use a number called SubUnitRate. This variable comes from another table with special condition. in short we have:
DECLARE
SUBUNITRATE NUMBER;
BEGIN
SELECT NVL (NULLIF (CU.SUBUNITRATE, 0), 1)
INTO SUBUNITRATE
FROM CURRENCYS CU
JOIN ACCOUNTS ACC ON CU.ID = ACC.CURRENCY
WHERE ACC.ID = :ACCOUNTID;
END;
SELECT SUBUNITRATE * 100 FROM DUAL;
My goal is to acquire the result of(in simple case):
SELECT SUBUNITRATE * 100 FROM DUAL;
But how is that possible?
Assuming you want to use the value of SUBUNITRATE multiple times in the same query you could use the WITH clause:
with cte as (
select case
when CU.SUBUNITRATE = 0 then 1
else CU.SUBUNITRATE
end as SUBUNITRATE
FROM CURRENCYS CU
JOIN ACCOUNTS ACC ON CU.ID = ACC.CURRENCY
WHERE ACC.ID = :ACCOUNTID
)
select cte.SUBUNITRATE * 100
from cte;
A PL/SQL block cannot return the results of a query as a query. Instead, you can print the results out.
So, does this do what you want?
DECLARE
SUBUNITRATE NUMBER;
BEGIN
SELECT NVL(NULLIF(CU.SUBUNITRATE, 0), 1)
INTO SUBUNITRATE
FROM CURRENCYS CU JOIN
ACC
ON CU.ID = ACC.CURRENCY
WHERE ACC.ID = :ACCOUNTID;
DBMS_OUTPUT.PUT_LINE(SUBUNITRATE * 100)
END;
No need for PL. APC' solution, simplified and in a form you can use directly in your query (wherever you would say ... = subunitrate, say ... = (select sur from cte) instead - including the parentheses):
with cte_prelim as (select subunitrate from ... etc.),
cte (sur) as select case when subunit rate is null or subunitrate = 0 then 100
else subunitrate * 100 end from cte_prelim)
select... (your query where you need to use the value)

Assigning a numeric score to a group of SQL statements

I was hoping someone could help me with the best way to do this in SQL.
If I have about 5 select statements
e.g.,
1) select name from payment a
join address b on a.id = b.id (if this statement score = 4)
2) select name from payment x
join address y on x.id = y.id (if this statement score = 7)
What is the best logic to use to know which select the person belongs to and how do I assign a numeric value to that name
If am not wrong you are looking for something like this
SELECT CASE
WHEN statement_score = 4 THEN 'statement_score_4'
WHEN statement_score = 7 THEN 'statement_score_7'
.....
END AS identifier,
name
FROM payment a
JOIN address b
ON a.id = b.id
AND statement_score IN( 4, 7,.. )
I don't know if I totally understand your question, but maybe you can select a value in each SELECT statement that indicates which query it came from. In other words,
select name, 4 AS score from payment a join address b on a.id = b.id (if this statement score = 4)
select name, 7 AS score from payment x join address y on x.id = y.id (if this statement score = 7)

SQL Query Help, Need some expert opinions

I have this query and it works well, the question is if there is a way to have the query NULL the column value if it doesn't exist in the table?
UPDATE PRD_WOCNT
SET c1 = (
SELECT WO_CNT.RATE FROM WO_CNT
WHERE WO_CNT.CNT = PRD_WOCNT.c1
)
WHERE EXISTS (
SELECT WO_CNT.CNT FROM WO_CNT
WHERE WO_CNT.CNT = PRD_WOCNT.c1
)
Right it uses a second table to update the main table values of sales codes into their commission rates. but sometimes a sales code is entered that doesn't exist in the table so it adds the sales code as a dollar value and makes the added total wrong.
I don't know too much PHP and trying not to bother with it if I can simply alter the query... it's a stab in the dark, have a feeling I'll need to do this on the PHP side but have no idea how I can have my query tell the php it doesn't exist.
UPDATE a
SET c1 = WO_CNT.RATE
FROM PRD_WOCNT a
LEFT JOIN WO_CNT b
ON b.CNT = a.c1
I havn't executed. I think it will work. Try this query:
UPDATE PRD_WOCNT SET c1 = CASE
WHEN EXISTS (
SELECT WO_CNT.CNT FROM WO_CNT
WHERE WO_CNT.CNT = PRD_WOCNT.c1
)
THEN (
SELECT WO_CNT.RATE FROM WO_CNT
WHERE WO_CNT.CNT = PRD_WOCNT.c1
)
ELSE NULL
END