Oracle sql:How to pass outer block value to inner block - oracle-sqldeveloper

Below is my query. I want to pass outer block value to inner block. outer block phase_name value should be passed to inner block. But that's not happening
select phase_name,
(select count(*) from projects,PHASES WHERE UPPER(projects.status) LIKE
'%'||phase_name||'%') count_pr
from PHASES

Try the INSTR function
for example:
INSTR('Corporate Floor','or')
would return the location where the first occurrence of the string 'or' took place in the sting 'Corporate Floor'.
https://docs.oracle.com/cd/B28359_01/olap.111/b28126/dml_functions_1103.htm#OLADM564

This issue is resolved by using alias name for the table in the outer block.
select phase_name,
(select count(*) from projects,PHASES WHERE UPPER(projects.status) LIKE
'%'||ph.phase_name||'%') count_pr
from PHASES ph

Related

Subquery with `WHERE` on function calls with outer query grouped by the function calls gives "subquery uses ungrouped column from outer query"

Consider this situation where age_group(.) is a function that returns an age bracket for an age (0-17: 'minor', 18-64: 'adult' etc.)
SELECT
date_of_data,
age_group(age),
count(1),
(SELECT avg(salary)
FROM tbl2
WHERE age_group(tbl2.age) = age_group(tbl1.age)
AND tbl2.date_of_file = tbl1.date_of_file
AND type = 'junior') AS average_salary_as_junior,
(SELECT avg(salary)
FROM tbl2
WHERE age_group(tbl2.age) = age_group(tbl1.age)
AND tbl2.date_of_file = tbl1.date_of_file
AND type = 'senior') AS average_salary_as_senior,
(SELECT avg(salary)
FROM tbl2
WHERE age_group(tbl2.age) = age_group(tbl1.age)
AND tbl2.date_of_file = tbl1.date_of_file
AND type = 'principal') AS average_salary_as_principal,
-- 15 more types to go
FROM tbl1
GROUP BY
date_of_data, age_group(age);
This will not work unless the outer query is grouped by age in contrast to age_group(age), because the subquery uses age as an argument to a function, despite being the same function:
subquery uses ungrouped column "tbl1.age" from outer query..
If I group by age instead of age_group(age), there will be redundant identical records in the output.
Conditional aggregation might be a solution, and so is using DISTINCT on the whole output, albeit inefficient. Not sure if there are more techniques to achieve the same, but I am wondering whether there's a way to make Postgres realise that the same function call exists in the GROUP BY clause, and permit such a query to execute.

postgresql function error ERROR: query has no destination for result data

I have created one function in postgresql. but when i try to return data i am getting below error
ERROR: query has no destination for result data
HINT: If you want to discard the results of a SELECT, use PERFORM instead.
CONTEXT: PL/pgSQL function "fn_GetAllCountData"() line 27 at SQL statement
SQL state: 42601
Below is the my postgresql function. In this function I am getting task status count in one query
CREATE OR REPLACE FUNCTION public."fn_GetAllCountData"() RETURNS setof "AssignDetails" AS $BODY$
DECLARE
total_draft text;
total_pending text;
total_rejected text;
total_approved text;
total_prev_pending text;
"AssignDetails" text;
BEGIN
--Total pending application no by the user
Select k."UserCode" as "UserCode",count(S."taskAssignTo") as "TotalPending" into total_pending
from user
left Outer Join public."tbl_task" S
on k."UserCode"=S."taskAssignTo" and s.Status='P'
And to_char(S."assignDate"::date, 'dd-mm-yyyy') = to_char(current_Date, 'dd-mm-yyyy')
group by k."UserCode";
--Previous Pending
Select k."UserCode" as "UserCode",count(S."taskAssignTo") as "TotalPrevPending" into total_prev_pending
from kyc k
left Outer Join public."tbl_task" S
on k."UserCode"=S."taskAssignTo" and s.Status='P'
And S."assignDate" < CONCAT(current_Date, ' 00:00:00'):: timestamp
group by k."UserCode";
-- Total Objection raised by the user
Select k."UserCode" as "UserCode",count(S."taskAssignTo") as "TotalRejected" into total_rejected
from kyc k
left Outer Join tbl_task S
on k."UserCode"=S."taskAssignTo" and s.Status='R'
And to_char(S."objectionDate"::date, 'dd-mm-yyyy') = to_char(current_Date, 'dd-mm-yyyy')
group by k."UserCode";
-- Total Approved application no by the user
Select k."UserCode" as "UserCode",count(S."taskAssignTo") as "TotalApproved" into total_approved
from kyc k
left Outer Join public."tbl_task" S
on k."UserCode"=S."taskAssignTo" and s.Status='A'
And S."assignDate" < CONCAT(current_Date, ' 00:00:00'):: timestamp
group by k."UserCode";
--Application no with start Time and total time
Select K."UserCode",K."Status", K."AppType",ST."taskNo" as "TaskId", ST."startTime" as "StartTime",
case
when COALESCE(ST."endTime",'')=''
then (SELECT DATEDIFF('second', ST."startTime":: timestamp, current_timestamp::timestamp))
else (SELECT DATEDIFF('second', ST."startTime":: timestamp, ST."endTime"::timestamp))
end as "Totaltime"
into "Final"
from kyc K
left outer join public."tbl_task_details" ST
On K."UserCode"=ST."empCode";
--Total Checked In Draft application no through by the user
Select k."UserCode" as "UserCode",count(S."taskAssignTo") as "Status_Count" into total_draft
from kyc k
left Outer Join public."tbl_task" S
on k."UserCode"=S."taskAssignTo" and s.Status='D'
And S."assignDate" < CONCAT(current_Date, ' 00:00:00'):: timestamp
group by k."UserCode";
Select distinct K."UserCode",K."Status",K."AppType",K."LoginTime",K."LogoutTime",
F."TaskId",F."StartTime",F."Totaltime",
TP."TotalPending" as "Pending",
TR."TotalRejected" as "Objection",
TA."TotalApproved" as "Approved",
TS."TotalAssign" as "Total_Assigned",
TD."Status_Count" as "Draft_Count",
TPP."TotalPrevPending" As "Prev_Pending"
into "AssignDetails"
From "Final" F
Right outer join kyc K On K."UserCode"=F."UserCode"
left outer join total_scrutiny TS On K."UserCode"=Ts."UserCode"
left outer join total_draft TD On TD."UserCode"=K."UserCode"
left outer join total_pending TP On TP."UserCode"=K."UserCode"
left outer join total_rejected TR On TR."UserCode"=K."UserCode"
left outer join total_approved TA On TA."UserCode"=K."UserCode"
Left Outer Join total_prev_pending TPP On TPP."UserCode"=K."UserCode"
order by TS."TotalAssign" desc;
Select * From "AssignDetails";
END
$BODY$ LANGUAGE plpgsql;
I tried to return table with return query but still not working. I don't know what i am doing wrong. Please help me with this.
Please note that postgreSQL only reports one error at a time. In fact there is a very great deal wrong with your function, so much so that it would take too long to correct everything here.
I have therefore given you a cut-down version here, which should point you in the right direction. I will give the code first, and then explain the points.
CREATE OR REPLACE FUNCTION public.fn_getallcountdata() RETURNS TABLE (usercode text, totalpending integer) AS $BODY$
BEGIN
CREATE TEMP TABLE total_pending
(
usercode text,
totalpending int
) ON COMMIT DROP;
--Total pending application no by the user
INSERT INTO total_pending
Select k.usercode, count(s.taskassignto)::integer
from public.user k
left Outer Join public.tbl_task s
on k.usercode=s.taskassignto and s.status='P'
And s.assigndate::date = current_date
group by k.usercode;
RETURN QUERY
select t.usercode, t.totalpending From total_pending t;
END;
$BODY$ LANGUAGE plpgsql;
Points to note:
Firstly please avoid using mixed case names in postgreSQL. It means that you have to double quote everything which is a real pain!
Secondly, you were declaring variables as text, when in fact they were holding table data. This you cannot do (you can only put a single value in any variable). Instead you need to create temporary tables in the way I have done. Note in particular the use of ON COMMIT DROP. This is a useful way in postgreSQL to avoid having to remember to drop temporary tables when you are finished with them!
Thirdly your alias k is not referring to anything in your first select. Note also that user is a reserved word. If you insist on having user as a name for a table, then you will need to access it through public.user (assuming it is in the public schema).
(As an aside it is generally considered to be a security risk to use the public schema, because of guest access).
Fourthly there is no need to convert a date to string form in order to compare it. Casting a timestamp to a date and directly comparing to another date is in fact far faster, than converting both dates to a string representation and comparing the strings.
Fifthly COUNT in postgreSQL returns a bigint, which is why I generally cast it as integer, because an integer usually suffices!
I have defined the function to return a table containing named columns. You can use setof, but if you do it has to be a known table type.
For the final SELECT I have supplied the required RETURN QUERY first. Note also that I am using a table alias. This is because the column names in the returning table match those in the temporary table, so you need to be explicit as to what you are doing.
I strongly recommend that you experiment with a shorter function first, (as in my cutdown version) and then increase the complexity once you have it compiling (and running). To this end please also note that in postgreSQL, if a function compiles, it does not mean that it contains no runtime errors. Also if you change the return columns between different compilations, you will need to delete the previous version.
Hope this points you in the right direction, but please feel free to get back with any further issues.

What does a column assignment using an aggregate in the columns area of a select do?

I'm trying to decipher another programmer's code who is long-gone, and I came across a select statement in a stored procedure that looks like this (simplified) example:
SELECT #Table2.Col1, Table2.Col2, Table2.Col3, MysteryColumn = CASE WHEN y.Col3 IS NOT NULL THEN #Table2.MysteryColumn - y.Col3 ELSE #Table2.MysteryColumn END
INTO #Table1
FROM #Table2
LEFT OUTER JOIN (
SELECT Table3.Col1, Table3.Col2, Col3 = SUM(#Table3.Col3)
FROM Table3
INNER JOIN #Table4 ON Table4.Col1 = Table3.Col1 AND Table4.Col2 = Table3.Col2
GROUP BY Table3.Col1, Table3.Col2
) AS y ON #Table2.Col1 = y.Col1 AND #Table2.Col2 = y.Col2
WHERE #Table2.Col2 < #EnteredValue
My question, what does the fourth column of the primary selection do? does it produce a boolean value checking to see if the values are equal? or does it set the #Table2.MysteryColumn equal to some value and then inserts it into #Table1? Or does it just update the #Table2.MysteryColumn and not output a value into #Table1?
This same thing seems to happen inside of the sub-query on the third column, and I am equally at a loss as to what that does as well.
MysteryColumn = gives the expression a name also called a column alias. The fact that a column in the table#2 also has the same name is besides the point.
Since it uses INTO syntax it also gives the column its name in the resulting temporary table. See the SELECT CLAUSE and note | column_alias = expression and the INTO CLAUSE

Error in update query

I have two entities STOCK(name,amount) and PC_SYSTEMS(name,c_name), and i wish to update the components needed to create the PC_system "Alienware", therefore i want it to subtract 1 from the amount of the components, needed to create the alienware system, in Stock.
Here's my query:
"UPDATE stock SET amount=amount-1 WHERE name = ( SELECT p.c_name FROM pc_systems p WHERE p.name='Alienware');"
I get a weird error that says:
" more than one row returned by a subquery used as an expression"
Would be happy if someone could help.
Edit:
I SOLVED this by putting an "IN" in my query instead of "=". Final code:
UPDATE stock SET amount=amount-1 WHERE name IN ( SELECT p.c_name FROM pc_systems p WHERE p.name='Alienware');
What it means is this SQL returns more than 1 row. Make it so it returns exactly 1 row only.
SELECT p.c_name FROM pc_systems p WHERE p.name='Alienware'
Since your subquery is returning more than one record you cannot use that syntax. try something like this:
UPDATE S
SET S.amount=S.amount-1
FROM Stock S
INNER JOIN pc_systems p
ON S.name = p.c_name
WHERE p.name='Alienware'
or try this:
update stock
set s.amount=s.amount-1
from stock s
inner join pc_systems p on S.name = p.c_name
where p.name='Alienware'

Joining several tables: table specified more than once error

I am attempting to call data after joining all of my tables in a postgreSQL query.
I am getting the following error:
Error in postgresqlExecStatement(conn, statement, ...) :
RS-DBI driver: (could not Retrieve the result : ERROR: table name "place" specified more than once
)
Failed to execute SQL chunk
After referring to similar posts and online resources, I have attempted setting aliases (which only create new errors about not referring to the other tables in the FROM clause), reordering the table names (the cleanest, reordered chunk is posted below), and experimenting with UPDATE/FROM/JOIN as an alternative to SELECT/FROM/JOIN. However, I think I ultimately need to be using the SELECT clause.
SELECT *
FROM place
INNER JOIN place ON place.key = form.key
INNER JOIN form ON form.id = items.formid
INNER JOIN items ON items.recid = rec.id
INNER JOIN rec ON rec.id = sub.recid
INNER JOIN sub ON sub.id = type.subid
INNER JOIN type ON type.name = det.typeid;
You have "place" in your query twice, which is allowed but you would have to alias the second use of the table "place". Also you reference something called "det", but it's not a table or alias anywhere in your query. If you want only one place that's fine, just remove the INNER JOIN place and move your place.key = form.key to the form join or to a where clause.
If you want to place tables in their because you are trying to join the table to itself the alias the second one, but you will want to make sure that you then have a clause to join those two tables on (could be part of an on or a where)
The issue ended up being the order of table names. The code below joined everything just fine:
SELECT *
FROM place
INNER JOIN form ON place.key = form.key
INNER JOIN items ON form.id = items.formid
INNER JOIN rec ON items.recid = rec.id
INNER JOIN sub ON rec.id = sub.recid
INNER JOIN type ON sub.id = type.subid
INNER JOIN det ON type.name = det.typeid;