how to compare two list values using oracle? - sql

Select main.gr_number from
(
Select st.GR_NUMBER from student st where upper(st.class_id)=upper('jtm.online137') and st.is_active_flg='Y'
and st.status='STUDYING'
and upper(st.class_days) like '%'||TO_CHAR(to_date('31-OCT-2019'),'DY')||'%'
) main
where (Select GR_NUMBER from student_class_attend where upper(class_id)=upper('jtm.online137')
and attend_date ='31-OCT-2019') not in (main.GR_NUMBER);
it is giving me error
single-row subquery returns more than one row

Looks like NOT EXISTS to me, i.e.
SELECT main.gr_number
FROM (SELECT st.GR_NUMBER
FROM student st
WHERE UPPER (st.class_id) = UPPER ('jtm.online137')
AND st.is_active_flg = 'Y'
AND st.status = 'STUDYING'
AND UPPER (st.class_days) LIKE
'%'
|| TO_CHAR (TO_DATE ('31-OCT-2019', 'dd-mon-yyyy'),
'DY')
|| '%') main
WHERE NOT EXISTS
(SELECT GR_NUMBER
FROM student_class_attend
WHERE UPPER (class_id) = UPPER ('jtm.online137')
AND attend_date = TO_DATE ('31-OCT-2019', 'dd-mon-yyyy')
AND gr_number = main.GR_NUMBER);
Note that I modified your "date" values by applying missing format mask and TO_DATE function as you shouldn't compare dates to strings. Even better: use date literal, e.g. date '2019-10-31' instead.

You can't use WHERE with a subquery that returns more than a row.
Instead of WHERE try using a left join and (for NOT IN) check for null value in left joined key:
Select main.gr_number
from (
Select st.GR_NUMBER
from student st
where upper(st.class_id)=upper('jtm.online137')
and st.is_active_flg='Y'
and st.status='STUDYING'
and upper(st.class_days) like '%'||TO_CHAR(to_date('31-OCT-2019'),'DY')||'%'
) main
LEFT JOIN (
Select GR_NUMBER
from student_class_attend
where upper(class_id)=upper('jtm.online137')
and attend_date ='31-OCT-2019'
) t ON t.GR_NUMBER main.GR_NUMBER
AND t.GR_NUMBER is null;

Related

For Pivot Columns need to apply group by

I want to apply the group by function based on columns generated by the PIVOT function.
In the query below, I wanted to apply Sum(TC.MB_Usage) so I could use group by at the end. However I am unable to apply the group by function to columns that are generated by the PIVOT function (SITES).
Comments are mentioned in BOLD
With TC as(
select /*+ NO_MERGE(T1) NO_MERGE(T2)
PARALLEL(T1,4) PARALLEL(T2,4) */
T1.* from (
select /*+
DRIVING_SITE(A) NO_MERGE(A) NO_MERGE(fips) NO_MERGE(fw) PARALLEL(A,4)
PARALLEL(fips,4) PARALLEL(fw,4) */
distinct
resource_value,
resource_type,
L3_IMSI as IMSI
,L9_Calling_Number as MDN
,L9_ECID as Curr_ECID
,trunc(START_TIME) as Usage_Date
,trim(TO_CHAR (TO_NUMBER (SUBSTR (L9_ECID,1,LENGTH(L9_ECID) - 2 ),'XXXXXXXXX'),'000000')) as enodeb
,substr(trim(TO_CHAR (TO_NUMBER (SUBSTR (L9_ECID,1,LENGTH(L9_ECID) - 2 ),'XXXXXXXXX'),'000000')),1,2) as fips_cd
,STATE_CODE
,STATE_NAME
,Sum(L3_ROUNDED_UNIT/1024) as MB_Usage
from RT_ET A
INNER JOIN
FIPS_STATEfips
ON trim(to_char(fips.FIPS_CODE,'00')) = substr(trim(TO_CHAR (TO_NUMBER (SUBSTR (A.L9_ECID,1,LENGTH(A.L9_ECID) - 2 ),'XXXXXXXXX'),'000000')),1,2)
INNER JOIN
DVC_ADDRfw
ON trim(L3_IMSI) = trim(to_char(FW.IMSI))
Where A.L9_ECID not in (' ','0') AND A.L3_IMSI not in (' ','0')
AND trunc(A.start_time) > trunc(sysdate-8)
AND trunc(start_time) > trunc(FW.ODS_INSERT_DATE)
group by
resource_value
,resource_type
,L3_IMSI
,L9_Calling_Number
,L9_ECID
,trunc(START_TIME)
,trim(TO_CHAR (TO_NUMBER (SUBSTR (L9_ECID,1,LENGTH(L9_ECID) - 2 ),'XXXXXXXXX'),'000000'))
,substr(trim(TO_CHAR (TO_NUMBER (SUBSTR (L9_ECID,1,LENGTH(L9_ECID) - 2 ),'XXXXXXXXX'),'000000')),1,2)
,STATE_CODE
,STATE_NAME
) T1
where NOT EXISTS (
SELECT
1 FROM DVC_ENODEB T2
WHERE T1.IMSI = trim(to_char(T2.IMSI))
AND T1.MDN = T2.MDN
AND T1.ENODEB = T2.ENODEB
)
)
select
distinct
SITES.*,
TC.resource_value,
TC.resource_type,
TC.IMSI,
TC.MDN,
TC.Curr_ECID,
TC.Usage_Date,
TC.enodeb,
TC.fips_cd,
TC.STATE_CODE,
TC.STATE_NAME,
**TC.MB_Usage -- Need to apply Sum(TC.MB_Usage)**
from
(
with
endb as
(select
e.IMSI, e.MDN,e.site_id, E.ENODEB,
ROW_NUMBER ()OVER (PARTITION BY e.IMSI||e.MDN
ORDER BY e.IMSI||e.MDN ) row_id
from
FIXED_WIRELESS_DVC_ADDR_ENODEB e
)
select *
from (select IMSI,MDN,IMSI||MDN as IMSI_MDN,site_id,row_id
from endb
)
pivot (max(site_id) siteid for row_id in (1,2,3,4,5,6,7,8,9,10,11,12,13)) ) SITES
INNER JOIN TC
ON ((TC.IMSI = trim(to_char(SITES.IMSI))) AND TC.MDN = SITES.MDN)
**Unable to apply Group by
based on below PIVOT columns (SITES.*), if I use SUM for MD_USAGE
Group BY
TC.resource_value,
TC.resource_type,
TC.IMSI,
TC.MDN,
TC.Curr_ECID,
TC.Usage_Date,
TC.enodeb,
TC.fips_cd,
TC.STATE_CODE,
TC.STATE_NAME,
SITES.***
You will need to specify the individual columns in your GROUP BY.
It looks like your SITES alias will have the columns IMSI, MDN, IMSI_MDN, and then 1,2,3,4,5,6,7,8,9,10,11,12,13 from the PIVOT clause.
So try listing those individually, and for the numeric ones put them in quotes:
GROUP BY
...
SITES."1", SITES."2", etc.

Union a table with a synthetic table to get result even if query result is empty

I have a data table which i want to select some fields filtering by date.
If the result is empty, based on the sysdate I need to decide if it is ok or not.
To be able to do that I am creating a synthetic table with a flag field which I expect to be populated in result set even if there is no data in my actual table at that date.
WITH const AS (
SELECT
'NAME 1' AS name,
(CASE WHEN TO_TIMESTAMP(TO_CHAR(CURRENT_TIMESTAMP, 'HH24:MI:SS'), 'HH24:MI:SS') < TO_TIMESTAMP('01:00:00', 'HH24:MI:SS') THEN 1 ELSE 0 END) AS flag
FROM
Data_Table
UNION
SELECT
'ANY NAME' AS name,
(CASE WHEN TO_TIMESTAMP(TO_CHAR(CURRENT_TIMESTAMP, 'HH24:MI:SS'), 'HH24:MI:SS') < TO_TIMESTAMP('01:00:00', 'HH24:MI:SS') THEN 1 ELSE 0 END) AS flag )
SELECT Data_Table.sysname, const.flag FROM const LEFT OUTER JOIN Data_Table ON Data_Table.sysname = const.name WHERE Data_Table.date=TO_CHAR(sysdate, 'DD-MM-YYYY')
I expect to get results like below:
sysname flag
Name1 1
(null) 1
But getting empty result if there is no data with that date.
Here's general example. If I understand correctly you need to be able to return a value even if query returns no rows:
SELECT table_name FROM all_tables
WHERE table_name = 'YOUR_TABLE'
UNION ALL
SELECT '1' table_name FROM dual
WHERE NOT EXISTS
(
SELECT table_name FROM all_tables
WHERE table_name = 'YOUR_TABLE'
)
/
The result is 1 as there is no table as 'YOUR_TABLE' in my database. But if I put a valid table name then i will get results from the top query. If not then always get 1 or any other value from second query. The table names in both queries must be the same. The second one is a copy of the top one.
I see the problem in your last statement that is
SELECT Data_Table.sysname, const.flag
FROM const
LEFT OUTER JOIN Data_Table
ON Data_Table.sysname = const.name
WHERE Data_Table.date=TO_CHAR(sysdate, 'DD-MM-YYYY')-- Here is the problem
You are doing a left outer join and then filtering the data using where condition, the where condition will never be true in this case. You need to push that condition into the join so that it does not affect the overall result:
SELECT Data_Table.sysname, const.flag
FROM const
LEFT OUTER JOIN Data_Table
ON Data_Table.sysname = const.name
AND Data_Table.date=TO_CHAR(sysdate, 'DD-MM-YYYY')

Oracle SQL: Return null value when no listagg result

I am using the following script to return some basic info. the script returns 65 lines (as expected)...
select unique
trunc(li.cre_dat) cre_date,
li.cre_usr,
li.catnr,
li.av_part_no,
li.artist,
li.title,
li.prodtyp,
li.packtyp,
nvl(sp.name_for_customer,sp.name) pack_type
from leos_item li,
scm_packtyp sp
where li.cunr in ('816900','816901','816902')
and li.item_type = 'FP'
and li.av_part_no is null
and trunc(li.cre_dat) >= '01-JAN-2016'
and li.model_force_creation_idc != 'Y'
and li.i_status != 'I'
and li.packtyp = sp.packtyp
...but, when I add Listagg in to my selects, the report only returns 55 lines. 10 lines does not have a listagg result therefore are omitted from the results...
select unique
trunc(li.cre_dat) cre_date,
li.cre_usr,
li.catnr,
li.av_part_no,
li.artist,
li.title,
li.prodtyp,
li.packtyp,
nvl(sp.name_for_customer,sp.name) pack_type,
regexp_replace(listagg(nvl(bom.av_part_no,'No'), ', ')
within group (order by bom.item_id),'([^,]+)(,\1)+', '\1') masters
from leos_item li,
scm_packtyp sp,
TABLE(leos_flatbom_pkg.GetFlatBOM(li.item_id)) bom,
leos_item li1
where li.cunr in ('816900','816901','816902')
and li.item_type = 'FP'
and li.av_part_no is null
and trunc(li.cre_dat) >= '01-JAN-2016'
and li.model_force_creation_idc != 'Y'
and li.i_status != 'I'
and li.packtyp = sp.packtyp
and bom.item_id = li1.item_id
and li1.item_type = 'MT'
group by li.cre_dat,
li.cre_usr,
li.catnr,
li.av_part_no,
li.artist,
li.title,
li.prodtyp,
li.packtyp,
nvl(sp.name_for_customer,sp.name)
But, I also need to see these lines. is there a way to return the 10 lines where no listagg result is found. I have tried the following combinations of nullif and nvl but with no luck;
nullif(regexp_replace(listagg(nvl(bom.av_part_no,'No'), ', ') within group (order by bom.item_id),'([^,]+)(,\1)+', '\1'),'No Master')
nvl(regexp_replace(listagg(nvl(bom.av_part_no,'No'), ', ') within group (order by bom.item_id),'([^,]+)(,\1)+', '\1'),'No Master')
The problem is not with LISTAGG it is that you are performing an inner join to the TABLE collection expression for leos_flatbom_pkg.GetFlatBOM(li.item_id) and that contains zero rows so the parent row is filtered out of the results.
Replace it with a correlated sub-query something like this:
select unique
trunc(li.cre_dat) cre_date,
li.cre_usr,
li.catnr,
li.av_part_no,
li.artist,
li.title,
li.prodtyp,
li.packtyp,
nvl(sp.name_for_customer,sp.name) pack_type,
( SELECT regexp_replace(listagg(nvl(bom.av_part_no,'No'), ', ')
within group (order by bom.item_id),'([^,]+)(,\1)+', '\1')
FROM TABLE( leos_flatbom_pkg.GetFlatBOM(li.item_id)) bom
INNER JOIN leos_item li1
ON ( bom.item_id = li1.item_id )
WHERE li1.item_type = 'MT'
) masters
from leos_item li
INNER JOIN
scm_packtyp sp
ON ( li.packtyp = sp.packtyp )
where li.cunr in ('816900','816901','816902')
and li.item_type = 'FP'
and li.av_part_no is null
and li.cre_dat >= DATE '2016-01-01'
and li.model_force_creation_idc != 'Y'
and li.i_status != 'I'
Some other points:
Please change to using the ANSI join syntax. The old Oracle comma join syntax is difficult to know how the columns are joined (especially for outer joins) as the join condition is buried in the WHERE clause.
Do not use string literals for dates (i.e. '01-JAN-2016') Oracle will do an implicit TO_DATE() on them using the NLS_DATE_FORMAT session parameter as the format mask and if this ever changes then the query will break (without ever changing the text of the query) and it will be a pain to debug. Even worse, this is a session parameter so it is possible for one user to change it and then it will work for everyone else and not for them. Use date literals (i.e. DATE '2016-01-01') or explicitly call TO_DATE() and supply the format mask and correct NLS settings.
li.cre_dat >= TRUNC( li.cre_dat ) so if TRUNC( li.cre_dat ) >= DATE '2016-01-01' is true then li.cre_dat >= DATE '2016-01-01' will also be true. The conculsion is you can eliminate the TRUNC() call.
You could also solve it using your second query and converting the TABLE colection expression to be an OUTER JOIN:
from leos_item li
scm_packtyp sp,
TABLE(leos_flatbom_pkg.GetFlatBOM(li.item_id)) (+) bom,
leos_item li1
where ...
and li.packtyp = sp.packtyp
and li1.item_id = bom.item_id (+)

ORACLE ALIAS in WHERE Clause Subquery [duplicate]

This question already has answers here:
Using an Alias in a WHERE clause
(5 answers)
Closed 9 months ago.
Here is my SQL code.
I used subquery and labeled it, but when I call column from that subquery, it shows that as invalid identifier.
SELECT TSR.Merchant_id, denomination, SUM (no_of_cards)
FROM sales_details
WHERE invoice_id IN (
SELECT invoice_id
FROM sales_header TSR
WHERE entered_by = (
(SELECT account_code
FROM bk_dsr_account_codes
WHERE user_name = 'C'
AND PASSWORD = 'D'
AND mobile_no = '8994035090213391259'))
AND entered_date BETWEEN (TO_DATE ('2013/04/01', 'yyyy/mm/dd')
)
AND (TO_DATE ('2013/06/30', 'yyyy/mm/dd')
))
GROUP BY denomination
error as per below
ORA-00904: "TSR"."MERCHANT_ID": invalid identifier
Please help me to sort out this issue.
I need to call subquery's columns also in my final SQL view.
You can only use colums that are in your FROM clause. So, your query should be something like:
SELECT TSR.Merchant_id, SD.denomination, SUM (SD.no_of_cards)
FROM sales_details SD
JOIN sales_header TSR on SD.invoice_od = TSR.invoice_id
WHERE entered_by = (
(SELECT account_code
FROM bk_dsr_account_codes
WHERE user_name = 'C'
AND PASSWORD = 'D'
AND mobile_no = '8994035090213391259'))
AND entered_date BETWEEN (TO_DATE ('2013/04/01', 'yyyy/mm/dd')
)
AND (TO_DATE ('2013/06/30', 'yyyy/mm/dd')
)
GROUP BY SD.denomination
select * from table1, table2 where table1.userid=x and table2.sdsd=x
also
select * from table1 t1, table2 t2 where t1.userid=x and t2.sdsd=x
same output these 2 above...
try this
SELECT TSR.Merchant_id, denomination, SUM (no_of_cards)
FROM sales_details,TSR
WHERE invoice_id IN (
SELECT invoice_id
FROM sales_header TSR
WHERE entered_by = (
(SELECT account_code
FROM bk_dsr_account_codes
WHERE user_name = 'C'
AND PASSWORD = 'D'
AND mobile_no = '8994035090213391259'))
AND entered_date BETWEEN (TO_DATE ('2013/04/01', 'yyyy/mm/dd')
)
AND (TO_DATE ('2013/06/30', 'yyyy/mm/dd')
))
GROUP BY denomination

Oracle: Get a query to always return exactly one row, even when there's no data to be found

I have a query like this:
select data_name
into v_name
from data_table
where data_table.type = v_t_id
Normally, this query should return exactly one row. When there's no match on v_t_id, the program fails with a "No data found" exception.
I know I could handle this in PL/SQL, but I was wondering if there's a way to do this only in a query. As a test, I've tried:
select case
when subq.data_name is null then
'UNKNOWN'
else
subq.data_name
end
from (select data_name
from data_table
where data_table.type = '53' /*53 does not exist, will result in 0 rows. Need fix this...*/
) subq;
...but this will obviously not work (because subq being empty is not the same as subq.data_name is null). Is this even possible or should I just check in my PL/SQL solution?
(oracle 10g)
There's ways to make this simpler and cleaner, but this basically spells out the technique:
SELECT data_name
FROM data_table
WHERE data_table.type = v_t_id
UNION ALL
SELECT NULL AS data_name
FROM dual
WHERE NOT EXISTS (
SELECT data_name
FROM data_table
WHERE data_table.type = v_t_id
)
When the first part of the union is empty the second will contain a row, when the first part is not empty, the second will contain no rows.
If the query is takes to much time, use this one:
SELECT * FROM (
SELECT data_name
FROM data_table
WHERE data_table.type = v_t_id
UNION ALL
SELECT NULL AS data_name
FROM dual
) WHERE data_name is not null or ROWNUM = 1
I would prefer to handle the exception. However, this would work as you specify:
select min(data_name) data_name
into v_name
from data_table
where data_table.type = v_t_id
Note that this also "works" if the query returns more than 1 row - i.e. TOO_MANY_ROWS is not raised.
select coalesce(data_table.data_name, d.data_name) data_name
into v_name
from
(SELECT 'UNKNOWN ' as data_name FROM DUAL) d
LEFT JOIN data_table
ON data_table.type = v_t_id
or a.data_table.data_name is null
Here is my simple solution using LEFT OUTER JOIN:
CREATE TABLE data_table(data_name VARCHAR2(20), data_type NUMBER(2));
INSERT INTO data_table(data_name, data_type) VALUES('fifty-one', 51);
SELECT coalesce(data_name, 'unknown')
FROM dual
LEFT OUTER JOIN (SELECT data_name FROM data_table WHERE data_type = 53) o
ON 1 = 1;
SELECT coalesce(data_name, 'unknown')
FROM dual
LEFT OUTER JOIN (SELECT data_name FROM data_table WHERE data_type = 51) o
ON 1 = 1;
https://stackoverflow.com/a/4683045/471149 answer is nice, but there is shorter solution
select * from my_table ce, (select 150 as id from dual) d
where d.id = ce.entry_id (+)
If you always expect zero or one row then you can use a group function i.e.:
select dump(max(dummy)) from dual
where dummy = 'Not Found'
You will always get at least one row and a value of NULL in the case where the record is not found.