Update subrequest and limit rownum - sql

I wrote this query:
UPDATE artpxvtemagtemp a
SET
origineprix = 'CEN',
pxvente = (
SELECT
ap.pxvtrpublic
FROM
artpxvte ap
JOIN article ar ON ar.idarticle = ap.idarticle
WHERE
ap.idarticle = a.idarticle
AND a.unite = ap.unite
AND ap.isdegressif = 0
AND ap.idtarifvte = 'T00002'
AND ap.datedebut <= pdateappli
AND ( ap.datefin IS NULL OR pdateappli < ( ap.datefin + 1 ) )
);
But sometimes the sub-query gives more than one result, so the update fails.
I want to order the result and select the first result of the sub-query to make the update.
So I do :
UPDATE artpxvtemagtemp a
SET
origineprix = 'CEN',
pxvente = (
SELECT
pxvtrpublic
FROM
(
SELECT
ap.pxvtrpublic
FROM
artpxvte ap
JOIN article ar ON ar.idarticle = ap.idarticle
WHERE
ap.idarticle = a.idarticle
AND a.unite = ap.unite
AND ap.isdegressif = 0
AND ap.idtarifvte = 'T00002'
AND ap.datedebut <= pdateappli
AND ( ap.datefin IS NULL
OR pdateappli < ( ap.datefin + 1 ) )
ORDER BY
CASE WHEN ap.datefin IS NULL THEN 0 ELSE 1 END ASC,
ap.datefin DESC,
ap.datedebut DESC
)
where rownnum <= 1
);
It does not work because the alias a is lost, so I have to add an additional sub-query just for the rownnum.
Erreur SQL : ORA-00904: "A"."UNITE" : identificateur non valide
00904. 00000 - "%s: invalid identifier"
In Oracle 12C, I don't need a sub-query to fetch the first Nth rows, but I have an old version of Oracle so I can't use this.
How can I make the alias a known?

Use aggregation instead:
pxvente = (select max(ap.pxvtrpublic) keep (dense rank first
order by case when ap.datefin is null then 0 else 1 end,
ap.datefin desc,
ap.datedebut desc
)
from . . .

Related

"ORA-00923: FROM keyword not found where expected\n what should I fix

I have an oracle query as follows but when I make changes to pagination the results are different. what should i pass for my code
SELECT *
FROM (
SELECT b.*,
ROWNUM r__
FROM (
select a.KODE_KLAIM,
a.NO_SS,
a.LA,
a.NAMA_TK,
a.KODE_K,
(
select tk.TEM_LAHIR
from KN.VW_KN_TK tk
where tk.KODE_K = a.KODE_K and rownum=1
) TEM_LAHIR,
(
select TO_CHAR(tk.TLAHIR, 'DD/MM/RRRR')
from KN.VW_KTK tk
where tk.KODE_K = a.KODE_K
and rownum=1
) TLAHIR
from PN.KLAIM a
where nvl(a.STATUS_BATAL,'X') = 'T'
and A.NOMOR IS NOT NULL
and A.TIPE_KLAIM = 'JPN01'
)b
)
where 1 = 1
WHERE ROWNUM < ( ( ? * ? ) + 1 )
WHERE r__ >= ( ( ( ? - 1 ) * ? ) + 1 )
but i run this query i have result ORA-00900: invalid SQL statement
You have three WHERE clauses at the end (and no ORDER BY clause). To make it syntactically valid you could change the second and third WHERE clauses to AND.
However, you mention pagination so what you probably want is to use:
SELECT *
FROM (
SELECT b.*,
ROWNUM r__
FROM (
select ...
from ...
ORDER BY something
)b
WHERE ROWNUM < :page_size * :page_number + 1
)
WHERE r__ >= ( :page_number - 1 ) * :page_size + 1
Note: You can replace the named bind variables with anonymous bind variables if you want.
Or, if you are using Oracle 12 or later then you can use the OFFSET x ROWS FETCH FIRST y ROWS ONLY syntax:
select ...
from ...
ORDER BY something
OFFSET (:page_number - 1) * :page_size ROWS
FETCH FIRST :page_size ROWS ONLY;
Additionally, you have several correlated sub-queries such as:
select tk.TEM_LAHIR
from KN.VW_KN_TK tk
where tk.KODE_K = a.KODE_K and rownum=1
This will find the first matching row that the SQL engine happens to read from the datafile and is effectively finding a random row. If you want a specific row then you need an ORDER BY clause and you need to filter using ROWNUM AFTER the ORDER BY clause has been applied.
From Oracle 12, the correlated sub-query would be:
select tk.TEM_LAHIR
from KN.VW_KN_TK tk
where tk.KODE_K = a.KODE_K
ORDER BY something
FETCH FIRST ROW ONLY

TERADATA, CASE INTO WHERE CLAUSE

I'd need help on this matter.
my where condition does not get accepted ... I know that is tricky the case in the where clause, so i think you could let me out... I created a field into a subquery with a over partition by, which then i bring into the main select ... then I'd need to apply the filter you see below... it returns me an error saying that B does not exist even tough if I just write B.CC = 1 then it gives me result...
any ideas?
Thanks in advance
SELECT
B.*
FROM
(
SELECT
A.*,
(Count(A.COD_ABI) Over (PARTITION BY A.COD_ABI, A.COD_KTO)) AS CC
FROM (
SELECT DISTINCT
T2.COD_PRODT_SALDO,
T2.COD_RESID_NPE,
T2.COD_DIVISA_UIC,
T2.COD_ABI,
T2.COD_NDG,
T2.COD_KTO,
T2.COD_PAESE_UIC_NPE,
T2.DAT_SCA,
T2.DAT_ACC,
T2.DAT_EST
FROM
(
SELECT
T1.COD_PRODT_SALDO
,T1.COD_RESID_NPE
,T1.COD_DIVISA_UIC
,T1.COD_ABI
,T1.COD_NDG
,'00753' ||T1.COD_PRODT_SALDO||T1.COD_CNTRT_SALDO AS COD_KTO
,T1.COD_CONTRATTO_SAL
,T1.COD_RIFER_ANNO
,T1.COD_RIFER_MESE
,T1.COD_RIFER_ANNO || T1.COD_RIFER_MESE AS COD_RIFER
,T1.COD_CONTB_ETR
,T1.DAT_EST
,T1.DAT_ACC
,T1.DAT_SCA
,T1.COD_PAESE_UIC_NPE
FROM ES777A.VA_ES_DB_ANAGR_CONTO AS T1,
ES777A.VE_BFD_PDC AS T2
WHERE T1.TMS_INIZIO_VALIDITA <= T2.TMS_PDC
AND T1.TMS_FINE_VALIDITA > T2.TMS_PDC
AND T1.TMS_CANC_FISICA IS NULL
AND T1.FLG_RIFACIMENTO = 0
AND T1.COD_ABI = T2.COD_ABI
AND T2.NOM_VISTA='VA_ES_DB_ANAGR_CONTO'
AND T2.NUM_PERIO_RIF = 20200131
AND T2.COD_PERIODICITA = 'G'
AND T1.COD_PRODT_SALDO NOT IN ('1398' , '1698')
AND T1.COD_PRODT_SALDO IN ('1801', '1803', '1901', '1903', '3301', '3304', '3311', '3401', '3411', '3421')
)
AS T2
INNER JOIN
(
SELECT
T1.COD_ABI,
'00753'||T1.COD_PRODT_SALDO||T1.COD_CNTRT_SALDO AS COD_KTO,
Max(T1.COD_RIFER_ANNO || COD_RIFER_MESE) AS MAX_COD_RIFER
FROM ES777A.VA_ES_DB_ANAGR_CONTO AS T1,
ES777A.VE_BFD_PDC AS T2
WHERE
T1.TMS_INIZIO_VALIDITA <= T2.TMS_PDC
AND T1.TMS_FINE_VALIDITA > T2.TMS_PDC
AND T1.TMS_CANC_FISICA IS NULL
AND T1.FLG_RIFACIMENTO = 0
AND T1.COD_ABI = T2.COD_ABI
AND T2.NOM_VISTA = 'VA_ES_DB_ANAGR_CONTO'
AND T2.NUM_PERIO_RIF = 20200131
AND T2.COD_PERIODICITA = 'G'
AND T1.COD_PRODT_SALDO NOT IN ('1398' , '1698')
AND T1.COD_PRODT_SALDO IN ('1801', '1803', '1901', '1903', '3301', '3304', '3311', '3401', '3411', '3421')
GROUP BY T1.COD_PRODT_SALDO,T1.COD_ABI,T1.COD_CNTRT_SALDO
)
AS T1
ON ( T2.COD_ABI = T1.COD_ABI AND T2.COD_KTO = T1.COD_KTO AND T2.COD_RIFER = T1.MAX_COD_RIFER )
WHERE
( T2.DAT_EST > '2019-11-02' OR T2.DAT_EST IS NULL ) -- -90GG
AND ( T2.DAT_SCA > '2019-11-02' OR T2.DAT_SCA IS NULL ) -- -90GG
)
A
)
B
WHERE b.cc =
WHEN (B.CC > 1 AND B.DAT_EST IS NOT NULL) THEN 1
WHEN (B.CC > 1 AND B.DAT_EST IS NULL) THEN 0
WHEN (B.CC = 1) THEN 1 ELSE 0
END
This answers the original version of the question.
In Teradata, you can simplify the logic to:
SELECT ...,
Count(A.COD_ABI) Over (PARTITION BY A.COD_ABI, A.COD_KTO) AS CC
FROM A
QUALIFY CC > 1 AND DATE_EST IS NOT NULL;
All the subqueries are unnecessary

Case on where clause ORACLE

SELECT *
FROM (
SELECT P.PC_ID, PC.PC, P.BLOK_ID, B.BLOK, B.ID_MATERIAL, M.MATERIAL, M.NO_MATERIAL, P.START_DTTM, TO_CHAR(P.START_DTTM,'yyyy-mm-dd') DATE_PERENCANAAN
FROM UTSG_PERENCANAAN P
INNER JOIN UTSG_PC PC
ON P.PC_ID = PC.ID_PC
INNER JOIN UTSG_BLOK B
ON P.BLOK_ID = B.ID_BLOK
LEFT JOIN UTSG_MATERIAL M
ON B.ID_MATERIAL = M.ID_MATERIAL
WHERE P.NO_LAMBUNG = '341'
AND P.LOKASI_ID = '2'
AND P.START_DTTM < TO_DATE('2019-01-09 23:40:52', 'yyyy-mm-dd hh24:mi:ss')
ORDER BY P.START_DTTM DESC
)
WHERE
CASE
WHEN BLOK = 'DD11'
THEN ROWNUM <= 1
ELSE
THEN ROWNUM <= 2
END
I have query like this, on case in where clause always show
error ORA-00905: missing keyword
You can't have the comparison operator within the case statement. Instead, your where clause should be something like:
WHERE
rownum <= CASE WHEN BLOK = 'DD11' THEN 1
ELSE 2
END
Why use a case expression?
WHERE (
(BLOK = 'DD11' AND ROWNUM <= 1)
OR
ROWNUM <= 2
)
In general it is advised to use "boolean logic" in where clauses, here is an blog of the topic: SQL WHERE clauses: Avoid CASE, use Boolean logic
I think you need to replace where clause to
((BLOK = 'DD11' and ROWNUM <= 1) or (ROWNUM <= 2))

Translating SQL Server 'OUTPUT' to Oracle?

I am having big issues translating my MSSQL (sql-server) query to Oracle (PL-SQL).
The goal is to do an update and a select on the updated field in one threadsafe operation.
My current MSSQL query:
UPDATE PDFCONVERT_G
SET PDF_STATUS = 1, PDF_STARTDATE = GETDATE(), PDF_CONVERTERNAME='inputConverterName'
OUTPUT Inserted.PDF_ACTION as Action,
Inserted.PDF_ARKMERK_VE As ARKMERK,
Inserted.PDF_TYPE_DL as DlTypeDT,
Inserted.PDF_DOKID_VE as DocId,
Inserted.PDF_DOKMALID_VE as DOKMALID,
Inserted.PDF_FILREF_VE as FILREF,
Inserted.PDF_FILTYPE_LF as Filtype,
Inserted.PDF_JPID_JP as JpId,
Inserted.PDF_LOCFILREF_VE as LOCFILREF,
Inserted.PDF_SAID_SA as SaId,
Inserted.PDF_SJEKKETUT_VE as SJEKKETUT,
Inserted.PDF_TGKODE_VE as TGKODE,
Inserted.PDF_VARIANT_VE as Variant,
Inserted.PDF_VERSJON_VE as Version,
Inserted.PDF_CHECKINAFTERCONVERT as CheckinAfterConvert
FROM PDFCONVERT_G t1
INNER JOIN (
SELECT TOP(1) *
FROM PDFCONVERT_G A WHERE (
(A.PDF_LAGRENH_VE = 'PROD' OR EXISTS(SELECT * FROM PDFCONVERT_G B WHERE A.PDF_JOBID=B.PDF_JOBID AND B.PDF_LAGRENH_VE='PROD' AND B.PDF_ACTION='MERGE'))
AND PDF_STATUS = 0 AND NOT EXISTS(
SELECT * FROM PDFCONVERT_G B where a.pdf_jobid = b.pdf_jobid and b.pdf_status > 0 and a.pdf_action != b.pdf_action))
ORDER BY A.PDF_PRIORITY DESC, A.PDF_JOBID, A.PDF_RNR
) t2 ON t2.PDF_JOBID = t1.PDF_JOBID
I can simply do this query in my .net code and the result will be the Output variables.
I know Oracle has the RETURNING INTO syntax but concidering how complex my WHERE clause is I simply get syntax errors all the time.
I would prefer to write a query without creating a function but even if I have to do that, I am having issues.
SELECT TOP(1) *
FROM PDFCONVERT_G A
WHERE (
( A.PDF_LAGRENH_VE = 'PROD'
OR EXISTS(SELECT *
FROM PDFCONVERT_G B
WHERE A.PDF_JOBID=B.PDF_JOBID
AND B.PDF_LAGRENH_VE='PROD'
AND B.PDF_ACTION='MERGE')
)
AND PDF_STATUS = 0
AND NOT EXISTS(
SELECT *
FROM PDFCONVERT_G B
where a.pdf_jobid = b.pdf_jobid
and b.pdf_status > 0
and a.pdf_action != b.pdf_action
)
)
ORDER BY A.PDF_PRIORITY DESC, A.PDF_JOBID, A.PDF_RNR
Can be rewritten (without the correlated sub-queries) as:
SELECT *
FROM (
SELECT a.*,
ROW_NUMBER() OVER ( ORDER BY PDF_PRIORITY DESC, PDF_JOBID, PDF_RNR ) AS rn
FROM (
SELECT a.*,
COUNT(
CASE WHEN DF_LAGRENH_VE = 'PROD'
AND PDF_ACTION = 'MERGE'
THEN 1 END
) OVER ( PARTITION BY pdf_jobid )
AS num_prod_merge,
COUNT(
CASE WHEN pdf_status > 0 THEN 1 END
) OVER ( PARTITION BY pdf_jobid )
AS num_all_actions,
COUNT(
CASE WHEN pdf_status > 0 THEN 1 END
) OVER ( PARTITION BY pdf_jobid, pdf_action )
AS num_same_actions
FROM PDFCONVERT_G a
) a
WHERE ( PDF_LAGRENH_VE = 'PROD' OR num_prod_merge > 0 )
AND PDF_STATUS = 0
AND num_all_actions = num_same_actions
)
WHERE rn = 1;
You can then rewrite your UPDATE to something like:
UPDATE PDFCONVERT_G
SET PDF_STATUS = 1,
PDF_STARTDATE = SYSDATE,
PDF_CONVERTERNAME='inputConverterName'
WHERE ROWID = (
SELECT ROWID
FROM (
-- as above
)
WHERE rn = 1
)
RETURNING PDF_ACTION -- , ...
INTO :Action -- , ...
(Note: Unable to test this at the moment so there may be some small syntax errors but you should get the general idea.)

How do I create a conditional SQL query

I am trying to create an Oracle Sql query using IF/Else statements
IF EXISTS
(
SELECT *
FROM baninst1.an_employee_position
WHERE baninst1.an_employee_position.person_uid = 593791
AND baninst1.an_employee_position.position_end_date IS NULL) THEN
SELECT *
FROM baninst1.an_employee_position
WHERE baninst1.an_employee_position.person_uid = 593791
AND (
baninst1.an_employee_position.position_end_date IS NULL
OR baninst1.an_employee_position.position_end_date > SYSDATE)
AND baninst1.an_employee_position.effective_start_date <= SYSDATE;ELSE
SELECT *
FROM (
SELECT *
FROM baninst1.an_employee_position
WHERE baninst1.an_employee_position.person_uid = 593791 )
WHERE ROWNUM = 1;END IF;
However I receive an "Unknown Command" error when I run it. No more error information
This may provide what you are looking for:
SELECT a.*
FROM employee_position a
where person_uid = 593791
and (
(a.position_end_date is null)
or
(
a.position_end_date =
(select max(position_end_date)
from employee_position b
where b.person_uid = a.person_uid
and b.position_end_date is not null
)
)
)
Another way
SELECT a.*
FROM employee_position a
where person_uid = 593791
and (
nvl(a.position_end_date, trunc(sysdate+100)) >=
(select max(position_end_date)
from employee_position b
where b.person_uid = a.person_uid
and b.position_end_date is not null
)
)