How to debug the error of invalid identifier in the following PL/SQL block? - sql

For the below PLSQL code , I am getting Error report -
ORA-00904: "SRC"."PART_ID_CONSOLIDATED": invalid identifier
ORA-06512: at line 37 , I tried debugging it by printing the values of I.item_no , I.PART_ID_CONSOLIDATED , getting values correctly printed but still its showing invalid identifier , unable to debug this , please guide .
DECLARE
BEGIN
FOR T IN
(
SELECT * FROM TDTEMP.ITEM_MTRL_SPLIT_TMP
where regexp_like(MATERIAL_NAME, '[[:digit:]],[[:digit:]] % +[[:alpha:]]*')
)
LOOP
FOR I IN
(
WITH parsed as(
SELECT /*+ parallel(t,8) materialize */
T.item_no,T.item_type,T.bu_code_sup,T.bu_type_sup,T.FROM_PACK_DATE,T.PART_ID,T.MATERIAL_NAME,T.PART_ID_CONSOLIDATED,T.reporting_name,
regexp_substr(REGEXP_REPLACE(replace(replace(T.MATERIAL_NAME,'% ','% '),', ',','), '(\d+),(\d+)', '\1.\2'),'[^,]+',1,ROWNUM)
AS split_value
FROM dual
CONNECT BY level <= regexp_count(REGEXP_REPLACE(replace(T.MATERIAL_NAME,'% /','%/'), '(\d+),(\d+)', '\1.\2'),'[^,]+')
)
,in_pairs as(
select /*+ parallel(k,8) materialize */
item_no,item_type,bu_code_sup,bu_type_sup,FROM_PACK_DATE,PART_ID,material_name,PART_ID_CONSOLIDATED,reporting_name
,regexp_substr(split_value, '[0-9]+[.]*[0-9]+') as percentage
,trim(substr(split_value, instr(split_value, '%') + 1)) as component
from parsed k where split_value LIKE '%\%%' ESCAPE '\'
)
select /*+ parallel(it,8) */
distinct item_no,item_type,bu_code_sup,bu_type_sup,FROM_PACK_DATE,PART_ID,material_name,percentage,component,PART_ID_CONSOLIDATED,reporting_name
from in_pairs it
)
LOOP
merge into TDTEMP.ITEM_MTRL_SPLIT_TMP targ
using (
SELECT I.item_no,I.item_type,I.bu_code_sup,I.bu_type_sup,I.FROM_PACK_DATE,I.PART_ID,I.material_name,I.percentage,I.component,I.PART_ID_CONSOLIDATED,
I.reporting_name FROM DUAL
)src
on ( targ.item_no = src.item_no
and targ.item_type = src.item_type
and targ.bu_code_sup = src.bu_code_sup
and targ.bu_type_sup = src.bu_type_sup
and targ.part_id = src.part_id
and targ.from_pack_date = src.from_pack_date
and targ.component = src.component
and targ.percentage = src.percentage
and targ.material_name = src.material_name
and targ.PART_ID_CONSOLIDATED = src.PART_ID_CONSOLIDATED
)
when not matched then
insert (item_no ,
item_type ,
bu_code_sup,
bu_type_sup ,
from_pack_date ,
part_id ,
part_id_consolidated,
material_name ,
percentage ,
component ,
reporting_name,
plastic,
ii_date )
values( src.item_no ,
src.item_type ,
src.bu_code_sup ,
src.bu_type_sup ,
src.from_pack_date,
src.part_id ,
src.part_id_consolidated ,
src.material_name ,
src.percentage ,
src.component ,
src.reporting_name,
'N',
sysdate
)
when matched then
update set targ.percentage = src.percentage ,
targ.component = src.component ;
END LOOP ;
END LOOP ;
END ;

The short answer is that because you are selecting from dual, which only has a single dummy column, you need to give aliases to all of the values you are selecting in your using clause:
using (
SELECT I.item_no AS item_no, I.item_type AS item_type, I.bu_code_sup AS bu_code_sup,
I.bu_type_sup AS bu_type_sub, I.FROM_PACK_DATE AS from_pack_date,
I.PART_ID AS part_id, I.material_name AS material_name, I.percentage AS percentage,
I.component AS component, I.PART_ID_CONSOLIDATED AS part_id_consolidated,
I.reporting_name AS reporting_name
FROM DUAL
) src
db<>fiddle with a very simplified example. To some extent that also addresses the "how to debug" part of your question - break your failing block of code down into smaller and simpler parts to make it easier to see what's happening. And if you still can't work it out, you're much closer to a minimum reproducible example you can post without so much noise for others to wade through.
The long answer is to avoid the loops and do a single merge, as MTO suggested in a comment.

Related

Can you explain the meaning of a minus in a SQL select statement?

I am working with SQL and I found this snippet, my question is: what does it mean those minus symbols (-) inside the select statement? I know is a kind of some trick, but I can't find information online about how it is used, please any insight would be welcome.
I am referring to:
SELECT - sum(st.sales) AS sales
- sum(st.orders) AS orders
- sum(st.aov) AS aov
It seems to be related to ledger tables, if you have any documentation, blog or pdf please give me the link to check it.
The full SQL looks like this:
INSERT INTO sales_test
WITH source_query AS --find the existing values in the ledger table and invert them
(
SELECT
st.og_date
, st.merchant
, st.store_name
, st.country
, st.kam
, st.class
, st.origin
, - sum(st.sales) AS sales
, - sum(st.orders) AS orders
, - sum(st.aov) AS aov
, et.source_file_name
, et.source_file_timestamp
FROM
sales_test st
INNER JOIN
ext_sales_test et
ON
city_hash(et.og_date, et.merchant, et.store_name, et.country, et.kam, et.class, et.origin) = city_hash(st.og_date, st.merchant, st.store_name, st.country, st.kam, st.class, st.origin)
AND st.og_date = et.og_date
AND st.merchant = et.merchant
GROUP BY
st.og_date
, st.merchant
, st.store_name
, st.country
, st.kam
, st.class
, st.origin
, et.source_file_name
, et.source_file_timestamp
)
, union_query AS --if we union the incoming data with the inverted existing data, we get the difference that needs to be ledgered
(
SELECT *
FROM
source_query
UNION ALL
SELECT *
FROM
ext_sales_text
)
It makes the numeric value negative(if numeric value is negative, - - is positive), in your case it first performs the sum and then it makes it negative or positive:
As an example:
USE tempdb;
GO
DECLARE #Num1 INT;
SET #Num1 = 5;
SELECT #Num1 AS VariableValue, -#Num1 AS NegativeValue;
GO
Result set:
VariableValue NegativeValue
------------- -------------
5 -5
(1 row(s) affected)
Further info here

Use merge with certain conditions and with ROW_NUMBER function

I am trying to do a merge (insert and update) with the row_number function so that the ID_TRANS field are unique values ​​in the remaining fields apply certain conditions. But when executing it I get a right parenthesis error, it is worth mentioning that I have modified and added parentheses and it remains unresolved.
MERGE INTO TBL_TRANSAC trans
USING (
SELECT ID_TRANS,
TIT,
BEN,
BAN,
CTA_EMI,
CTA_REC,
INST,
TYPE_TRANS,
TYPE_MOV,
CONC,
DATE_OPER,
MONT,
DIV,
ID_CONT
FROM (
SELECT T1.*
, ROW_NUMBER() OVER (PARTITION BY T1.ID_TRANS ORDER BY T1.ID_TRANS DESC)ENUMERADO
FROM (
SELECT
'speibco1_'||UPPER(REPLACE( AREA,' ',''))||
UPPER(REPLACE( FVALOR,' ',''))||
UPPER(REPLACE( CLAVE_RASTREO,' ','')) ,
TIT ,
BEN,
BAN_EM_DES,
REPLACE(UPPER(NO_TP_CTA_EMISOR),' ',''),
LTRIM(CTA_REC,'0'),
'BAN ACTINVER',
'CTA_EXTER',
'SPEI ENTRADA BCO',
CONC_2 ,
TO_DATE(TO_CHAR(FVALOR),'YYYY-MM-DD'),
REPLACE(REPLACE(IMPORTE,'-',''),' ',''),
'MXN' ,
LTRIM(CTA_REC,'0')||'0999'
FROM (SELECT *
FROM IBM_I2.I2_SPEI WHERE REPLACE(NO_TP_CTA_EMISOR,' ','') IS NOT NULL
AND ID_OPERACION='0007'
AND ESTATUS='06'
AND CTA_REC NOT IN ('70000997', '7909567'))
)
WHERE ENUMERADO=1
AND ID_TRANS IS NOT NULL
)SPEI
ON (
trans.ID_TRANS = SPEI.ID_TRANS
)
WHEN MATCHED THEN
UPDATE SET
ID_TRANS = SPEI.ID_TRANS,
TIT = SPEI.TIT ,
BEN= SPEI.BEN,
BAN=SPEI.BAN_EMISOR,
CTA_EMI=SPEI.CTA_EMI,
CTA_REC =SPEI.CTA_REC,
INST= SPEI.INST,
TYPE_TRANS=SPEI.TYPE_TRANS,
TYPE_MOV=SPEI.TYPE_MOV,
CONC=SPEI.CONC,
DATE_OPER=SPEI.DATE_OPER,
MONT=SPEI.MONT,
DIV= SPEI.DIV,
ID_CONT= SPEI.ID_CONT
WHEN NOT MATCHED THEN
INSERT (
ID_TRANS,
TIT,
BEN,
BAN,
CTA_EMI,
CTA_REC,
INST,
TYPE_TRANS,
TYPE_MOV,
CONC,
DATE_OPER,
MONT,DIV,
ID_CONT
)
VALUES
(
SPEI.ID_TRANS,
SPEI.TIT ,
SPEI.BEN,
SPEI.BAN_EMISOR,
SPEI.CTA_EMI,
SPEI.CTA_REC,
SPEI.INST,
SPEI.TYPE_TRANS,
SPEI.TYPE_MOV,
SPEI.CONC ,
SPEI.DATE_OPER,
SPEI.MONT,
SPEI.DIV ,
SPEI.ID_CONT
);
MARK ERROR THAT MISSING RIGHT PARENTESIS AFTER AND ID_TRANS IS NOT NULL
STILL PLACING THE PARENTESIS.
Looks like a closing parenthesis is missing, here:
)) --> here; should be 2, not only 1
WHERE ENUMERADO=1
AND ID_TRANS IS NOT NULL
Put parentheses and aliases to each of them, as well as the fields that are called in USING put aliases, and that worked.
FROM (SELECT *
FROM IBM_I2.I2_SPEI WHERE REPLACE(NO_TP_CTA_EMISOR,' ','') IS NOT NULL
AND ID_OPERACION='0007'
AND ESTATUS='06'
AND CTA_REC NOT IN ('70000997', '7909567')
)
)T1
)T2
WHERE ENUMERADO=1
AND ID_TRANS IS NOT NULL
)SPEI
ON (
trans.ID_TRANS = SPEI.C1_ID_TRANS
)

How to use regex to split using last occurrence of forward slash in BigQuery

I have sample data as
with temp_table as
(
select "/category/sub-category/title-of-the-page" as pagename
union all
select "premier-league/splash"
union all
select "portal"
union all
select "news/1970/01/01/new-billion"
union all
select "/premier-league/transfers/"
union all
select "/premier-league/tfflive"
)
, clean_pagename as
(
select * ,
if (regexp_contains(pagename, "^/+" ) , regexp_extract(pagename, "^/+(.*)/?$") , pagename) as clean_page
from temp_table
)
, dated_content as
(
select *, if (
regexp_contains(clean_page , "/[0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9]/") ,
regexp_replace(clean_page , "[0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9]", "dated-content" ),
clean_page
) as new_pagename
from clean_pagename
)
,category_and_titles as
(
select *, split(new_pagename, "/")[offset(0)] as page_category,
coalesce(REGEXP_EXTRACT(new_pagename, r'/([^/]+)?$') , "no-title") as title,
regexp_replace(new_pagename, r'[^/]+$', "") as path
from dated_content
)
select pagename,
page_category ,
path,
title
from category_and_titles
Here is what I am doing - I remove the first / in the string and replace date-content using a regex. Next I would like to extract 3 things
category - first section of the string before first /
path - that component of string from 0 until last / has been encountered
title - everything after last / in the string.
There are instances where / is not present at all (record #3). In this case I want all the 3 parts to be equal to original string.
For example - for string as /premier-league/transfers/, I would like my output to be -
category = "premier-league" , path = "premier-league/transfers/" , title = ""
My current code gives me results as
Whereas, I need -
Without much refactoring and leaving all your original logic intact - just do below changes for category_and_titles CTE
...
, category_and_titles AS (
SELECT *,
SPLIT(new_pagename, "/")[OFFSET(0)] AS page_category,
IF(REGEXP_CONTAINS(new_pagename, r'/'), REGEXP_REPLACE(new_pagename, r'[^/]+$', ""), new_pagename) AS path,
IF(REGEXP_CONTAINS(new_pagename, r'/'), COALESCE(REGEXP_EXTRACT(new_pagename, r'/([^/]+)?$'), "no-title"), new_pagename) AS title
FROM dated_content
)
...
with this minor change result will be as expected

PL/SQL fetch records from JOIN clause problem

It's the second question I'm asking for the same issue, so I'll try to be more specific and brief as I can.
In my pl/sql script, i try to insert into a table some records from lots of different tables. I achieve that, except for a field that comes from a JOIN of 2 tables.
The INSERT statement is placed into the following loop:
FOR FST_DEMAND_rec IN (
SELECT *
FROM A
WHERE FK_DEPOSIT_ACCOACC = DEPOSIT_ACC_rec.ACCOUNT_NUMBER
AND TRX_DATE BETWEEN '01-JAN-2018' AND '31-DEC-2018'
ORDER BY TRANS_SER_NUM , ENTRY_SER_NUM ASC)
LOOP
This loop is placed into the following cursor loop :
FOR T IN MOF_CURSOR LOOP
So the INSERT statement, which actually lies in 2 loops, is the following :
INSERT INTO MOF_OUT
VALUES(
T.MOF_REQUEST_ID,
LOC_SERIAL_NUM,
'2B',
CAST(FST_DEMAND_rec.TRX_UNIT || TO_CHAR(FST_DEMAND_rec.TRX_DATE,'YYYYMMDD') || FST_DEMAND_rec.TRX_USR || FST_DEMAND_rec.TRX_SN AS CHAR(50) ),
TO_CHAR(FST_DEMAND_rec.TRX_DATE,'YYYY-MM-DD') ,
CAST(FST_DEMAND_rec.TRX_UNIT AS CHAR(4) ) ,
UNIT_rec.UNIT_NAME ,
CAST(FST_DEMAND_rec.ID_TRANSACT AS CHAR(6) ),
PRFT_TRANS_rec.DESCRIPTION,
-- 'MY PROBLEMATIC FIELD'
TO_CHAR(FST_DEMAND_rec.TIMESTAMP,'hh24miss'),
FST_DEMAND_rec.ENTRY_AMOUNT,
LOC_DC_FLAG,
LOC_PROGR_BALANCE,
LOC_PROGR_BAL_IND
) ;
This INSERT statement works fine, but I don't know how to fill a record which comes from the following SELECT statement with the JOIN clause:
SELECT A.ENTRY_COMMENTS || ' ' || B.DESCRIPTION
FROM FST_DEMAND_EXTRAIT A INNER JOIN JUSTIFIC B ON A.ID_JUSTIFIC = B.ID_JUSTIFIC
For example, the PRFT_TRANS_rec variable that I use in the INSERT, it's declared as PRFT_TRANSACTION%ROWTYPE; and I have the following SELECT statement for it which is within these 2 loops :
SELECT *
INTO PRFT_TRANS_rec
FROM PRFT_TRANSACTION PRFT_TRANS
WHERE PRFT_TRANS.ID_TRANSACT = FST_DEMAND_rec.ID_TRANSACT;

"end-of-file on communication channel" error with UNION of DISTINCT columns

I'm cleaning up SQL code from a previous engineer (not a programmer).
One query UNIONs the results to 2 almost identical queries, with an exactly identical sub-query, and the original code has a lot of "where" clauses (in both queries) to filter the data.
I am trying to use "with" tables to filter the data first, and then do the sub-queries and the union.
I keep getting a generic "end-of-file on communication channel" error during the "Prepare" step, but when I remove the DISTINCT clause from the sub-queries, it works - but it doesn't give me the results I need.
Here is the code I've "reduced" to show the error:
with
FilteredData as
(
select
ST.part
, ST.order_No
, ST.induct_Date
, ST.complete_Date
from
Some_Table ST
where
(
ST.part is not null
and ST.order_No is not null
)
-- MUCH more filtering goes on here, to limit the number of records to look at
)
,
TempTable_01A as
(
select
FD.part
, count( DISTINCT FD.part ) Count_1 -- The DISTINCT needs to be removed for it to compile
, 0 Count_2
, 0 AvgLengthOpen
from
FilteredData FD
where
FD.induct_Date is not null
and ( FD.induct_Date >= to_date( '01-01-2013', 'MM-DD-YYYY' ) )
and ( FD.induct_Date < ( to_date( '01-31-2013', 'MM-DD-YYYY' ) + 1 ) )
group by
FD.part
)
,
TempTable_01B as
(
select
FD.part
, 0 Count_1
, count( DISTINCT FD.part ) Count_2 -- The DISTINCT needs to be removed for it to compile
, avg( FD.complete_Date - FD.induct_Date ) AvgLengthOpen
from
FilteredData FD
where
FD.complete_Date is not null
and ( FD.complete_Date >= to_date( '01-01-2013', 'MM-DD-YYYY' ) )
and ( FD.complete_Date < ( to_date( '01-31-2013', 'MM-DD-YYYY' ) + 1 ) )
group by
FD.part
)
,
UnionTable as
(
select
TT_A.part
, TT_A.Count_1
, TT_A.Count_2
, TT_A.AvgLengthOpen
from
TempTable_01A TT_A
union
select
TT_B.part
, TT_B.Count_1
, TT_B.Count_2
, TT_B.AvgLengthOpen
from
TempTable_01B TT_B
)
select
UT.part
, max( UT.Count_1 ) MaxCount_1
, max( UT.Count_2 ) MaxCount_2
, max( UT.AvgLengthOpen ) MaxAvgLengthOpen
from
UnionTable UT
group by
UT.part
order by
1
NOTE: I am using Oracle SQL, version 10.0.2.1697. I get this same error whether I'm using PLSQL Developer, or my Perl program.