how to enter a date subquery in oracle - oracle

Hello I would like to add an additional column called (DATE), but that does not affect the previously selected data as I could add that column ... (DATE IS IN VARIABLE_VALORES_SMEC), try to do a subquery in the select but it sends me this error: single- row subquery returns more than one row
Select Max(A1.VALOR) AS VALOR ,
(SELECT FECHA AS FC FROM VARIABLE_VALORES_SMEC WHERE ID_AGENTE IN A1.ID_AGENTE <--here is the problem
) MES,
(SELECT CODIGO_AGENTE FROM AGENTES WHERE ID_AGENTE = A1.ID_AGENTE
) Agentess,
(SELECT NOMBRE_AGENTE FROM AGENTES WHERE ID_AGENTE = A1.ID_AGENTE
) Nombre_Agente
FROM VARIABLE_VALORES_SMEC A1
WHERE A1.VALOR < '1'
AND A1.VALOR != '0'
AND A1.ID_AGENTE IN (SELECT C1.ID_AGENTE FROM VARIABLE_VALORES_SMEC C1
WHERE A1.FECHA = C1.FECHA)
AND A1.ID_AGENTE IN (SELECT B1.ID_AGENTE
FROM AGENTES B1
WHERE ID_CATEGORIA_AGENTE = 'AC006'
)
AND (A1.FECHA between (ADD_MONTHS(TO_DATE(:FECHAIN,'MM/DD/YYYY'),-1)) AND (LAST_DAY(ADD_MONTHS(TO_DATE(:FECHAIN, 'MM/DD/YYYY'),-1))))
AND A1.ID_VARIABLE LIKE '%_calc_total_pot#%'
GROUP BY ID_AGENTE

single- row subquery returns more than one row
This error means that your subquery returns more than 1 row (replace FECHA with count(*) and you will see how many rows does it return), so you need:
aggregate returned values, for example using listagg() function, ie:
(select listagg(FECHA)within group(order by 1) from ...
or
2. analyze your predicates in the subquery so that returns just 1 row.
PS. To make your queries more clear and readable, it would be better to use aliases for all tables and columns, for example
(SELECT sq1.FECHA AS FC FROM VARIABLE_VALORES_SMEC sq1 WHERE sq1.ID_AGENTE IN A1.ID_AGENTE) MES,
PS2. Don't use IN for single value, just use "="

Your column FECHA is from table VARIABLE_VALORES_SMEC on which your main query is executing, then why don't you simply use direct column instead of subquery as follows:
Select Max(A1.VALOR) AS VALOR ,
Max(FECHA) keep (dense_rank last order by value) AS MES
.....
.....

Related

how to select specific columns from three different tables in Oracle SQL

I am trying to select values from three different tables.
When I select all columns it works well, but if I select specific column, the SQL Error [42000]: JDBC-8027:Column name is ambiguous. appear.
this is the query that selected all that works well
SELECT
*
FROM (SELECT x.*, B.*,C.* , COUNT(*) OVER (PARTITION BY x.POLICY_NO) policy_no_count
FROM YIP.YOUTH_POLICY x
LEFT JOIN
YIP.YOUTH_POLICY_AREA B
ON x.POLICY_NO = B.POLICY_NO
LEFT JOIN
YIP.YOUTH_SMALL_CATEGORY C
ON B.SMALL_CATEGORY_SID = C.SMALL_CATEGORY_SID
ORDER BY x.POLICY_NO);
and this is the error query
SELECT DISTINCT
x.POLICY_NO,
x.POLICY_TITLE,
policy_no_count ,
B.SMALL_CATEGORY_SID,
C.SMALL_CATEGORY_TITLE
FROM (SELECT x.*, B.*,C.* , COUNT(*) OVER (PARTITION BY x.POLICY_NO) policy_no_count
FROM YIP.YOUTH_POLICY x
LEFT JOIN
YIP.YOUTH_POLICY_AREA B
ON x.POLICY_NO = B.POLICY_NO
LEFT JOIN
YIP.YOUTH_SMALL_CATEGORY C
ON B.SMALL_CATEGORY_SID = C.SMALL_CATEGORY_SID
ORDER BY x.POLICY_NO);
I am trying to select if A.POLICY_NO values duplicate rows more than 18, want to change C.SMALL_CATEGORY_TITLE values to "ZZ" and also want to cahge B.SMALL_CATEGORY_SID values to null.
that is why make 2 select in query like this
SELECT DISTINCT
x.POLICY_NO,
CASE WHEN (policy_no_count > 17) THEN 'ZZ' ELSE C.SMALL_CATEGORY_TITLE END AS C.SMALL_CATEGORY_TITLE,
CASE WHEN (policy_no_count > 17) THEN NULL ELSE B.SMALL_CATEGORY_SID END AS B.SMALL_CATEGORY_SID,
x.POLICY_TITLE
FROM (SELECT x.*, B.*,C.* , COUNT(*) OVER (PARTITION BY x.POLICY_NO) policy_no_count
FROM YIP.YOUTH_POLICY x
LEFT JOIN
YIP.YOUTH_POLICY_AREA B
ON x.POLICY_NO = B.POLICY_NO
LEFT JOIN
YIP.YOUTH_SMALL_CATEGORY C
ON B.SMALL_CATEGORY_SID = C.SMALL_CATEGORY_SID
ORDER BY x.POLICY_NO);
If i use that query, I got SQL Error [42000]: JDBC-8006:Missing FROM keyword. ¶at line 3, column 80 of null error..
I know I should solve it step by step. Is there any way to select specific columns?
That's most probably because of SELECT x.*, B.*,C.* - avoid asterisks - explicitly name all columns you need, and then pay attention to possible duplicate column names; if you have them, use column aliases.
For example, if that select (which is in a subquery) evaluates to
select x.id, x.name, b.id, b.name
then outer query doesn't know which id you want as two columns are named id (and also two names), so you'd have to
select x.id as x_id,
x.name as x_name,
b.id as b_id,
b.name as b_name
from ...
and - in outer query - select not just id, but e.g. x_id.

How to select data from multiple row into one row with multiple column dynamically?

I am trying to select multiple rows of data into one row through multiple columns which will change dynamically.
This is in Oracle database. I want to count repeated work done by the LEAD_TECHNISIAN_ID within a duration. If the difference of last work delivery date and new work receive date is 15 or below 15 then LEAD_TECHNISIAN_ID has one repeated work.
List item
SELECT *
FROM (WITH CTE AS (
SELECT ROW_NUMBER () OVER (ORDER BY ID) AS RW,
RECEIVED_DATE,
DELIVERY_DATE,
SERVICE_NO,
LEAD_TECHNISIAN_ID,
ID,
SERVICE_CENTER
FROM ( SELECT cc.SERVICE_CENTER,
CC.ID,
CC.BARCODE,
TRUNC (cc.CREATED_DATE) RECEIVED_DATE,
TRUNC (CC.DELIVERY_DATE) DELIVERY_DATE,
cc.SERVICE_NO,
CC.LEAD_TECHNISIAN_ID
FROM customer_complains cc
WHERE cc.BARCODE IN (SELECT BARCODE
FROM (SELECT BARCODE,
COUNT (BARCODE)
FROM customer_complains c
WHERE c.BARCODE <> 'UNDEFINE'
AND C.BARCODE = NVL ('351950102757821', BARCODE)
AND c.SEGMENT3 = NVL ('',c.SEGMENT3)
AND c.SEGMENT3 IN (SELECT SEGMENT3
FROM ITEM_MST
WHERE PRODUCT_GROUP = NVL ('',PRODUCT_GROUP))
GROUP BY c.BARCODE
HAVING COUNT (c.BARCODE) >1))
ORDER BY ID DESC)
ORDER BY ID DESC)
SELECT a.id,
a.DELIVERY_DATE,
a.RECEIVED_DATE,
b.RECEIVED_DATE PRE_RCV,
b.DELIVERY_DATE PRE_DEL,
(a.RECEIVED_DATE - b.DELIVERY_DATE) AS DIFF,
a.SERVICE_NO,
a.LEAD_TECHNISIAN_ID,
b.LEAD_TECHNISIAN_ID PRE_TECH --, a.DELIVERY_DATE
FROM CTE a
LEFT JOIN CTE b ON a.RW = b.RW + 1
)
WHERE DIFF <= 15
Here is the output for a specific barcode. but when I try for All the barcode I have in My Customer_complains table. The query provides irrelevant output.
Currently your code is giving numbers 1,2,3,4... to rows irrespective of LEAD_TECHNISIAN_ID and then you are joining it with RW. It will not consider LEAD_TECHNISIAN_ID while giving row numbers.
RW must start with 1 for each LEAD_TECHNISIAN_ID.
You just need to change calculation of RW as following:
ROW_NUMBER () OVER (PARTITION BY LEAD_TECHNISIAN_ID ORDER BY ID) AS RW
Cheers!!

Adding filters in subquery from CTE quadruples run time

I am working on an existing query for SSRS report that focuses on aggregated financial aid data split out into 10 aggregations. User wants to be able to select students included in that aggregated data based on new vs. returning and 'selected for verification.' For the new/returning status, I added a CTE to return the earliest admit date for a student. 2 of the 10 data fields are created by a subquery. I have been trying for 3 days to get the subquery to use the CTE fields for a filter, but they won't work. Either they're ignored or I get a 'not a group by expression' error. If I put the join to the CTE within the subquery, the query time jumps from 45 second to 400 seconds. This shouldn't be that complicated! What am I missing? I have added some of the code... 3 of the chunks work - paid_something doesn't.
with stuStatus as
(select
person_uid, min(year_admitted) admit_year
from academic_study
where aid_year between :AidYearStartParameter and :AidYearEndParameter
group by person_uid)
--- above code added to get student information not originally in qry
select
finaid_applicant_status.aid_year
, count(1) as fafsa_cnt --works
, sum( --works
case
when (
package_complete_date is not null
and admit.status is not null
)
then 1
else 0
end
) as admit_and_package
, (select count(*) --does't work
from (
select distinct award_by_aid_year.person_uid
from
award_by_aid_year
where
award_by_aid_year.aid_year = finaid_applicant_status.aid_year
and award_by_aid_year.total_paid_amount > 0 )dta
where
(
(:StudentStatusParameter = 'N' and stuStatus.admit_year = finaid_applicant_status.aid_year)
OR
(:StudentStatusParameter = 'R' and stuStatus.admit_year <> finaid_applicant_status.aid_year)
OR :StudentStatusParameter = '%'
)
)
as paid_something
, sum( --works
case
when exists (
select
1
from
award_by_person abp
where
abp.person_uid = fafsa.person_uid
and abp.aid_year = fafsa.aid_year
and abp.award_paid_amount > 0
) and fafsa.requirement is not null
then 1
else 0
end
) as paid_something_fafsa
from
finaid_applicant_status
join finaid_tracking_requirement fafsa
on finaid_applicant_status.person_uid = fafsa.person_uid
and finaid_applicant_status.aid_year = fafsa.aid_year
and fafsa.requirement = 'FAFSA'
left join finaid_tracking_requirement admit
on finaid_applicant_status.person_uid = admit.person_uid
and finaid_applicant_status.aid_year = admit.aid_year
and admit.requirement = 'ADMIT'
and admit.status in ('M', 'P')
left outer join stuStatus
on finaid_applicant_status.person_uid = stuStatus.person_uid
where
finaid_applicant_status.aid_year between :AidYearStartParameter and :AidYearEndParameter
and (
(:VerifiedParameter = '%') OR
(:VerifiedParameter <> '%' AND finaid_applicant_status.verification_required_ind = :VerifiedParameter)
)
and
(
(:StudentStatusParameter = 'N' and (stuStatus.admit_year IS NULL OR stuStatus.admit_year = finaid_applicant_status.aid_year ))
OR
(:StudentStatusParameter = 'R' and stuStatus.admit_year <> finaid_applicant_status.aid_year)
OR :StudentStatusParameter = '%'
)
group by
finaid_applicant_status.aid_year
order by
finaid_applicant_status.aid_year
Not sure if this helps, but you have something like this:
select aid_year, count(1) c1,
(select count(1)
from (select distinct person_uid
from award_by_aid_year a
where a.aid_year = fas.aid_year))
from finaid_applicant_status fas
group by aid_year;
This query throws ORA-00904 FAS.AID_YEAR invalid identifier. It is because fas.aid_year is nested too deep in subquery.
If you are able to modify your subquery from select count(1) from (select distinct sth from ... where year = fas.year) to select count(distinct sth) from ... where year = fas.year then it has the chance to work.
select aid_year, count(1) c1,
(select count(distinct person_uid)
from award_by_aid_year a
where a.aid_year = fas.aid_year) c2
from finaid_applicant_status fas
group by aid_year
Here is simplified demo showing non-working and working queries. Of course your query is much more complicated, but this is something what you could check.
Also maybe you can use dbfiddle or sqlfiddle to set up some test case? Or show us sample (anonimized) data and required output for them?

select statement should return count as zero if no row return using group by clause

I have a table student_info, it has column "status", status can be P (present), A (absent), S (ill), T ( transfer), L (left).
I am looking for expected output as below.
status count(*)
P 12
S 1
A 2
T 0
L 0
But output is coming like as below:
Status Count(*)
P 12
S 1
A 2
we need rows against status T and L as well with count zero though no record exist in DB.
#mkuligowski's approach is close, but you need an outer join between the CTE providing all of the possible status values, and then you need to count the entries that actually match:
-- CTE to generate all possible status values
with stored_statuses (status) as (
select 'A' from dual
union all select 'L' from dual
union all select 'P' from dual
union all select 'S' from dual
union all select 'T' from dual
)
select ss.status, count(si.status)
from stored_statuses ss
left join student_info si on si.status = ss.status
group by ss.status;
STATUS COUNT(SI.STATUS)
------ ----------------
P 12
A 2
T 0
S 1
L 0
The CTE acts as a dummy table holding the five statuses you want to count. That is then outer joined to your real table - the outer join means the rows from the CTE are still included even if there is no match - and then the rows that are matched in your table are counted. That allows the zero counts to be included.
You could also do this with a collection:
select ss.status, count(si.status)
from (
select column_value as status from table(sys.odcivarchar2list('A','L','P','S','T'))
) ss
left join student_info si on si.status = ss.status
group by ss.status;
It would be preferable to have a physical table which holds those values (and their descriptions); you could also then have a primary/foreign key relationship to enforce the allowed values in your existing table.
If all the status values actually appear in your table, but you have a filter which happens to exclude all rows for some of them, then you could get the list of all (used) values from the table itself instead of hard-coding it.
If your initial query was something like this, with a completely made-up filter:
select si.status, count(*)
from student_info si
where si.some_condition = 'true'
group by si.status;
then you could use a subquery to get all the distinct values from the unfiltered table, outer join from that to the same table, and apply the filter as part of the outer join condition:
select ss.status, count(si.status)
from (
select distinct status from student_info
) ss
left join student_info si on si.status = ss.status
and si.some_condition = 'true'
group by ss.status;
It can't stay as a where clause (at least here, where it's applying to the right-hand-side of the outer join) because that would override the outer join and effectively turn it back into an inner join.
You should store somewhere your statuses (pherhaps in another table). Otherwise, you list them using subquery:
with stored_statuses as (
select 'P' code, 'present' description from dual
union all
select 'A' code, 'absent' description from dual
union all
select 'S' code, 'ill' description from dual
union all
select 'T' code, 'transfer' description from dual
union all
select 'L' code, 'left' description from dual
)
select ss.code, count(*) from student_info si
left join stored_statuses ss on ss.code = si.status
group by ss.code

Oracle update statement with analytics is failing

The Table_B contains duplicate records as seen below. What I am trying to do is lookup Table_A using Table_B.SERIAL_NUM and update Table_A .COVERAGE_END coloumn with the most recent Date value in COVERAGE_TO coloumn in Table_B.
Table_B
SERIAL_NUM ,COVERAGE_FROM ,COVERAGE_TO
123456 ,26/12/2014 ,13/12/2015
123456 ,14/12/2015 ,13/12/2016
23456 ,18/12/2014 ,13/12/2015
23456 ,14/12/2015 ,13/12/2016
Following is the update statement I am using.
update Table_A J
set ( J.COVERAGE_END_DATE)
=(select COVERAGE_TO from
(
select SERIAL_NUM, COVERAGE_TO, row_number() over(partition by SERIAL_NUM order by COVERAGE_TO desc) as rn from TABLE_B B
)where rn = 1
)
where exists
(
select * from TABLE_B Q where Q.SERIAL_NUM = J.SERIAL_NUMBER
)
;
However I get the following error
ORA-01427: single-row subquery returns more than one row
Can Some one please help me with this Query?
You have to compare J's SERIAL_NUMBER with B's to get the only proper value.
where rn = 1 and J.SERIAL_NUMBER = SERIAL_NUM
If not, subquery will return max values for every SERIAL_NUM.
I'm not sure why partitioning is needed here.
Would a simple MAX() not produce the needed result?
update table_a
set coverage_end_date = (
select max(coverage_to)
from table_b b inner join table_a a on b.serial_num = a.serial_num
)
;

Resources