Oracle "Cannot update to NULL" - oracle

I have this query on Oracle 10g:
UPDATE "SCHEMA1"."CELLS_GLIST"
SET ("GLIST_VALUE_ID", "USER_ID", "SESSION_ID") = (
SELECT "GLIST_VALUE_ID", 1 AS "USER_ID", 123456 AS "SESSION_ID"
FROM "SCHEMA1"."GLISTS_VALUES_UOR"
WHERE ("UOR_ID"=3)
AND ("GLIST_ID"=67)
AND ("GLIST_VALUE_DESC" = (
SELECT "GLIST_VALUE_DESC"
FROM "BMAN_TP1"."GLISTS_VALUES_UOR"
WHERE ("UOR_ID"=3)
AND ("GLIST_VALUE_ID"="CELLS_GLIST"."GLIST_VALUE_ID")
))
)
WHERE EXISTS (......)
It keeps saying ORA-01407: cannot update ("SCHEMA1"."CELLS_GLIST"."SESSION_ID") to NULL
"SESSION_ID" is obviously Not Nullable, but I'm actually passing a value to that field, so I do not understand the problem.

From your comments, I read that you seem to want to write a default record to your target table, in case the subquery doesn't return any records. So the correct way to phrase your query would be using a MERGE statement as such:
MERGE INTO "SCHEMA1"."CELLS_GLIST" dst
USING (
-- rephrase your subquery here. This is your "merge data source". The number
-- of records returned in this subquery will correspond to the number of
-- affected records in dst
) src
ON (
-- the missing exists condition here. Everytime this condition matches a record
-- between dst and src, an UPDATE is performed. Otherwise, an INSERT is
-- performed
)
WHEN MATCHED THEN UPDATE
SET dst."GLIST_VALUE_ID" = src."GLIST_VALUE_ID"
WHEN NOT MATCHED THEN INSERT ("GLIST_VALUE_ID", "USER_ID", "SESSION_ID")
VALUES (NULL, 1, 123456);
This is just to give you an idea. I'm not quite sure what you're trying to achieve in detail, so I omitted the subqueries and conditions

I found this query also to work:
UPDATE "BMAN_TP1"."CELLS_GLIST"
SET "GLIST_VALUE_ID" = (
SELECT "GLIST_VALUE_ID"
FROM "BMAN_TP1"."GLISTS_VALUES_UOR"
WHERE ("UOR_ID"=3)
AND ("GLIST_ID"=67)
AND ("GLIST_VALUE_DESC" = (
SELECT "GLIST_VALUE_DESC"
FROM "BMAN_TP1"."GLISTS_VALUES_UOR"
WHERE ("UOR_ID"=3)
AND ("GLIST_VALUE_ID"="CELLS_GLIST"."GLIST_VALUE_ID")
))
),
"SESSION_ID" = 123456,
"USER_ID" = 1
WHERE EXISTS (......)
But, it performs really really fast... I doubt I'm missing something...

Related

How to retrieve data from 3 tables using sub query oracle SQL

I want to retrieve users name and there responsibility_key where there end_date is null and i want to convert it to (sysdate+1) using nvl but i am only able to retrieve the responsibility_key not the name please help.
The error in the image says "column ambiguously defined". Take a close look. Your last END_DATE could refer to either the u alias or the table from the subquery. Change it to match the rest of your subquery (FIND_USER_GROUPS_DIRECT.END_DATE)
EDIT
Your query is
select u.USER_NAME, d.responsibility_key from FND_USER u,FND_RESPONSIBILITY_VL d
where responsibility_id in(
select responsibility_id from
FND_USER_RESP_GROUPS_DIRECT WHERE END_USER_RESP_GROUPS_DIRECT.END_DATE=nvl(END_DATE,sysdate+1)) and
u.END_DATE=nvl(END_DATE,SYSDATE + 1)
;
The query isn't formatted, which makes it hard to read.
Not all columns are qualified with table name (or aliases), as mentioned in the comments.
The query currently uses an implicit join.
The query is impossible to understand without seeing the table definitions (desc [table_name]).
For points 1 and 2, a properly formatted query will look something like
select u.user_name, d.responsibility_key
from
fnd_user u,
fnd_responsibility_vl d
where
d.responsibility_id in (
select urgd.responsibility_id
from
fnd_user_resp_groups_direct urgd
where
urgd.end_date = nvl(u.end_date, sysdate+1)
) and
u.end_date = nvl(urgd.end_date, sysdate + 1)
;
This makes it easier to read and in addition to this, you can see that without table definitions I guessed (see point 4) as to which tables the end_date column belongs in your query. If I had to guess, so does Oracle. That means you have an ambiguity problem. To fix it, take a close look at the end_date column as it appears in your original query and where you do not prefix it with anything, you need to prefix it with the appropriate alias (after you have aliased all your tables).
For point 3, you can write your query more clearly with an explicit join and by using aliases for all columns. As for the explicit join I have no idea what your tables look like but one possibility is something like
select u.user_name, d.responsibility_key
from fnd_user u
join fnd_responsibility_vl d
on u.id = d.user_id
where
d.responsibility_id in (
select responsibility_id
from fnd_user_resp_groups_direct urgd
where
urgd.end_date = nvl(u.end_date, sysdate+1)
) and
u.end_date = nvl(urgd.end_date, sysdate+1)
;
If you follow these points you will get to the root of the error.

Update statement with joins in Oracle

I need to update one column in table A with the result of a multiplication of one field from table A with one field from table B.
It would be pretty simple to do this in T-SQL, but I can't write the correct syntax in Oracle.
What I've tried:
UPDATE TABLE_A
SET TABLE_A.COLUMN_TO_UPDATE =
(select TABLE_A.COLUMN_WITH_SOME_VALUE * TABLE_B.COLUMN_WITH_PERCENTAGE
from TABLE_A
INNER JOIN TABLE_B
ON TABLE_A.PRODUCT_ID = TABLE_B.PRODUCT_ID
AND TABLE_A.SALES_CHANNEL_ID = TABLE_B.SALES_CHANNEL_ID)
WHERE TABLE_A.MONTH_ID IN (201601, 201602, 201603);
But I keep getting errors. Could anybody help me, please?
I generally prefer to use the below format for such cases since this will ensure there's no update performed if there's no data in the table(query extracted temp table) whereas in the above solution provided by Brian Leach will update the new value as null if there's no record present in the 2nd table but exists in the first table.
UPDATE
(
select TABLE_A.COLUMN_TO_UPDATE
, TABLE_A.PRODUCT_ID
, TABLE_A.COLUMN_WITH_SOME_VALUE * TABLE_B.COLUMN_WITH_PERCENTAGE as value
from TABLE_A
INNER JOIN TABLE_B
ON TABLE_A.PRODUCT_ID = TABLE_B.PRODUCT_ID
AND TABLE_A.SALES_CHANNEL_ID = TABLE_B.SALES_CHANNEL_ID
AND TABLE_A.MONTH_ID IN (201601, 201602, 201603)
) DATA
SET DATA.COLUMN_TO_UPDATE = DATA.value;
This solution can cause key preserved value issues which shouldn't be an issue here since i expect a single row in both the tables for one product(ID).
More on Key Preserved table concept in inner join can be found here
https://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:548422757486
#Jayesh Mulwani raiesed a valid point, this will set the value to null if there is no matching record. This may or may not be the desired result. If it isn't, and no change is desirect, you can change the select statement to:
coalesce((SELECT table_b.column_with_percentage
FROM table_b
WHERE table_a.product_id = table_b.product_id AND table_a.sales_channel_id = table_b.sales_channel_id),1)
If this is the desired outcome, Jayesh's solution will be more efficient as it will only update matching records.
UPDATE table_a
SET table_a.column_to_update = table_a.column_with_some_value
* (SELECT table_b.column_with_percentage
FROM table_b
WHERE table_a.product_id = table_b.product_id
AND table_a.sales_channel_id = table_b.sales_channel_id)
WHERE table_a.month_id IN (201601, 201602, 201603);

Oracle: Invalid identifier

I am using the following query in oracle. However, it gives an error saying that "c.par" in line 5 is an invalid parameter. No idea why. The columns exist. I checked. I have been struggling with this for a long time. All I want to do is to merge one table into another and update it using oracle. Could someone please help?
MERGE INTO SPRENTHIERARCHIES
USING ( SELECT c.PARENTCATEGORYID AS par,
e.rootcategoryId AS root
FROM SPRENTCATEGORIES c,SPRENTHIERARCHIES e
WHERE e.root (+)= c.par
) SPRENTCATEGORIES
ON (SPRENTHIERARCHIES.rootcategoryId = SPRENTCATEGORIES.parentcategoryId)
WHEN MATCHED THEN
UPDATE SET e.root=c.par
The e and c aliases only exist within the query in the using clause. You're trying to refer to them in the update clause. You're also using a column alias from the using clause against the target table, which doesn't have that column (unless your tables have both rootcategoryId and root, and parentCategoryId and par).
So this:
UPDATE SET e.root=c.par
should be:
UPDATE SET SPRENTHIERARCHIES.rootcategoryId= SPRENTCATEGORIES.par
And in that using clause you're trying to use column aliases as the same level of query, so this:
WHERE e.root (+)= c.par
should be:
WHERE e.rootcategoryId (+)= c.PARENTCATEGORYID
Your on clause is wrong too, as that is not using the column alias:
ON (SPRENTHIERARCHIES.rootcategoryId = SPRENTCATEGORIES.par)
But I'd suggest you replace the old syntax in the using clause with proper join clauses:
MERGE INTO SPRENTHIERARCHIES
USING ( SELECT c.PARENTCATEGORYID AS par,
e.rootcategoryId AS root
FROM SPRENTCATEGORIES c
LEFT JOIN SPRENTHIERARCHIES e
ON e.rootcategoryId = c.PARENTCATEGORYID
) SPRENTCATEGORIES
ON (SPRENTHIERARCHIES.rootcategoryId = SPRENTCATEGORIES.par)
WHEN MATCHED THEN
UPDATE SET SPRENTHIERARCHIES.rootcategoryId= SPRENTCATEGORIES.par
You have a more fundamental problem though, as you're trying to update a joining column; this will get:
ORA-38104: Columns referenced in the ON Clause cannot be updated
As Gordon Linoff suggested you can use an update rather than a merge. Something like:
UPDATE SPRENTHIERARCHIES h
SET h.rootcategoryId = (
SELECT c.PARENTCATEGORYID
FROM SPRENTCATEGORIES c
WHERE c.PARENTCATEGORYID = h.rootCategoryID
)
WHERE EXISTS (
SELECT null
FROM SPRENTCATEGORIES c
WHERE c.PARENTCATEGORYID = h.rootCategoryID
)
The where exists clause is there in case there not be a matching record - which the outer join in your original query implies. But in this form it's even more obvious that you're going to update rootcategoryId to the same value, since you're selecting the parentCategoryID which is equal to it. So the update (or merge) seems to be pointless.

Subquery returning multiple rows during update

I have two tables T_SUBJECTS (subject_id, date_of_birth) and T_ADMISSIONS (visit_id, subject_id, date_of_admission, age). I want to update the age column with the age at time of admission. I wrote the update query and get the "single row sub-query returns more than one row". I understand the error but thought the where exists clause will solve the problem. Below is the query.
UPDATE
t_admissions
SET
t_admissions.age =
(
SELECT
TRUNC(months_between(t_admissions.date_of_admission,
t_subjects.date_of_birth)/12)
FROM
t_admissions,
t_subjects
WHERE
t_admissions.subject_id = t_subjects.subject_id
AND t_admissions.age = 0
AND t_admissions.date_of_admission IS NOT NULL
AND t_subjects.date_of_birth IS NOT NULL
)
WHERE
EXISTS
(
SELECT
1
FROM
t_admissions, t_subjects
WHERE
t_admissions.subject_id = t_subjects.subject_id
);
The problem is that your subquery in the SET clause returns multiple rows.
Having a WHERE clause will only filter which records get updated and nothing else.
In addition, your where clause will either always return true or always return false.
You should look into how to properly do a correlated update:
https://stackoverflow.com/a/7031405/477563
A correlated update is what I need as suggested in the above link. See answer below.
UPDATE
(
SELECT
t_admissions.visit_id,
t_admissions.date_of_admission doa,
t_admissions.age age,
t_subjects.date_of_birth dob
FROM
t_admissions,
t_subjects
WHERE
t_admissions.subject_id = t_subjects.subject_id
AND t_admissions.age = 0
AND t_admissions.date_of_admission IS NOT NULL
AND t_subjects.date_of_birth IS NOT NULL
)
SET
age = TRUNC(months_between(doa,dob)/12);

ORA-01791 Pl-Sql error

hi guy i have a query that give me the followin error:
ORA-01791: not a SELECTed expression
this is the select expresison , please can you tell me why ?
declare
freqLettura varchar2(64);
billingcy varchar2(64);
begin
freqLettura := null;
billingcy := null;
for rec in ( select distinct(fn_get_facilityid(z.uidfacility) ) as a, 1 as b
from facilityhistory z,
locality l ,
plant p ,
ztmp_sam_tb_sdv zsdv ,
ztmp_sam_tb_plantcode zplant ,
sam_tb_ca_pdr sam,
meterhistory mh,
meter m ,
meterclass mc
where
Z.UIDLOCALITY = L.UIDLOCALITY and
p.UIDPLANT = L.UIDPLANT and
z.uidaccount = zsdv.uidaccount and
p.plantcode = zplant.plantcode and
sam.uidfacility = z.uidfacility and
z.stoptime is null and
sam.status = 'U' and
mh.uidfacility = z.uidfacility and
mh.uidmeter = m.uidmeter and
m.uidmeterclass = mc.uidmeterclass and
(billingcy is null or p.UIDBILLINGCYCLE = billingcy )
AND
(
(
(freqLettura = 'G') AND ( mh.corrmeterid is not null and mh.stoptime is null and mc.maxflowmeter >= SAM_FN_GET_PARAMETER_FLOAT('MAXFLOWMET_DETT_GIORN'))
)
OR
(
nvl(freqLettura,'nullo') <> 'G' AND (freqLettura is null or sam.readfrequency = freqLettura)
)
) and ROWNUM = 1 order by sam.stoptime, sam.uidsamtbpdr desc ) loop
begin
insert into ztmp_sam_tb_elab_pdr (facilityid, uidbatchrequest) VALUES (rec.a, rec.b);
exception
when dup_val_on_index then
null;
end;
end loop;
end;
Whenever you get an Oracle error message you don't understand, the first thing to do is look up the meaning. One way is simply to Google it. In this case the full description found in
Oracle9i Database Error Messages is:
ORA-01791 not a SELECTed expression
Cause: There is an incorrect ORDER
BY item. The query is a SELECT DISTINCT query with an ORDER BY clause.
In this context, all ORDER BY items must be constants, SELECT list
expressions, or expressions whose operands are constants or SELECT
list expressions.
Action: Remove the inappropriate ORDER BY item from the SELECT list
and retry the statement.
(Oddly this error message isn't documented in the 10G or 11G manuals, despite still being raised!)
This matches the statement you have written, which is a SELECT DISTINCT query where you are trying to order the results by a column that you did not select.
If you think about it, what you are asking for doesn't make sense: by selecting DISTINCT values that do not include sam.stoptime (for example) you may be consolidating many rows with different values for sam.stoptime, so which one would govern the ordering?
Also, as Noel's answer points out, there is no reason to have an ORDER BY clause in this code anyway, so the solution is simply to remove it.
If you are using DISTINCT in your SELECT query, then your ORDER BY clause should contain only those columns that your selecting. In this case sam.stoptime, sam.uidsamtbpdr are not there in SELECT statement. You can remove the ORDER BY clause, as it is not doing anything useful in your example.

Resources