sqlite3 UPDATE generating nulls - sql

I'm trying to transition from MySQL to SQLIte3 and running into an update problem. I'm using SQLite 3.6.20 on redhat.
My first line of code behaves normally
update atv_covar set noncomp= 2;
All values for noncomp (in the rightmost column) are appropriately set to 2.
select * from atv_covar;
A5202|S182|2
A5202|S183|2
A5202|S184|2
It is the second line of code that gives me problems:
update atv_covar
set noncomp= (select 1 from f4003 where
atv_covar.study = f4003.study and
atv_covar.rpid = f4003.rpid and
(rsoffrx="81" or rsoffrx="77"));
It runs without generating errors and appropriately sets atv_covar.noncomp to 1 where it matches the SELECT statement. The problem is that it changes atv_covar.noncomp for the non-matching rows to null, where I want it to keep them as 2.
select * from atv_covar;
A5202|S182|
A5202|S183|1
A5202|S184|
Any help would be welcome.

#Dan, the problem with your query is not specific to SQLite; you are updating all rows of atv_covar, but not all of them have correspondence in f4003, so these default to NULL. You should filter the update or provide a default value.
The following statement sets 1 only to the rows that macth the filtering condition:
UPDATE atv_covar
SET noncomp = 1
WHERE EXISTS (
SELECT 'x'
FROM f4003
WHERE atv_covar.study = f4003.study
AND atv_covar.rpid = f4003.rpid
AND (rsoffrx="81" or rsoffrx="77")
);
The following statement sets 1 or 2 for all rows of noncomp, depending on the filtering match (use this instead of two updates):
UPDATE atv_covar
SET noncomp = COALESCE((
SELECT 1
FROM f4003
WHERE atv_covar.study = f4003.study
AND atv_covar.rpid = f4003.rpid
AND (rsoffrx="81" or rsoffrx="77")
), 2);

Related

Snowflake ignores statement in where clause where I'm comparing timestamps

so I'm building a SCD type 2 in snowflake, but it ignores the where clause in which is comparision between "to_timestamp" and "expiry_date". Expiry_date is a variable that is set to '9999-08-17 07:31:29.901000000' (as infinity) and To_timestamp is a column in table. I want to query only the rows that have to_timestamp set to infinity (they are still active) but snowflake seems to ignore this part of where clause. Below is some of the code (it should update the rows that are expired - that means change their "to_timestamp" to current time. and it does but it does to rows with timestamps of all kind - it ignores last line)
SET EXPIRY_DATE_NTZ = '9999-08-17 07:31:29.901000000';
SET CURRENT_DATE_NTZ = TO_TIMESTAMP_NTZ(CURRENT_TIMESTAMP());
UPDATE CUSTOMER_TARGET CT
SET CT.TO_TIMESTAMP = $CURRENT_DATE_NTZ
FROM POC.SNOWFLAKE_POC.CUSTOMER_STAGE CS
WHERE CT.C_CUSTOMER_ID = CS.C_CUSTOMER_ID
AND (CT.C_FIRST_NAME <> CS.C_FIRST_NAME OR CT.C_LAST_NAME <> CS.C_LAST_NAME OR CT.C_BIRTH_YEAR
<> CS.C_BIRTH_YEAR OR CT.C_BIRTH_COUNTRY <> CS.C_BIRTH_COUNTRY OR CT.C_LAST_REVIEW_DATE<>CS.C_LAST_REVIEW_DATE)
AND CT.TO_TIMESTAMP = $EXPIRY_DATE_NTZ;
I have two of these update statements (one for updates and one for deletes) and a merge statement for inserts. And it ignores the comparision in every single one, updating the rows that have "to_timestamp" set to something like "2021-08-24 07:11:53.510000000". I've tried every combination possible (between ... and ..., >= ... <=, <=, >=, comparing in "case" statement of update,...) - nothing. What could be the cause/solution?
As we do not know the structure of CUSTOMER_TARGET I would suggest to explicitly set the data type of EXPIRY_DATE_NTZ variable to match the column data type:
SET EXPIRY_DATE_NTZ = '9999-08-17 07:31:29.901000000';
SELECT $EXPIRY_DATE_NTZ;
DESCRIBE RESULT LAST_QUERY_ID();
to:
-- TIMESTAMP_NTZ as an example
SET EXPIRY_DATE_NTZ = '9999-08-17 07:31:29.901000000'::TIMESTAMP_NTZ;
SELECT $EXPIRY_DATE_NTZ;
DESCRIBE RESULT LAST_QUERY_ID();
By doing that way there are no "implicit conversions" involved in the process.
Another advice is usage of IS DISTINCT FROM instead of <>. IS DISTINCT FROM is NULL safe, which is important if columns are defined as nullable.
UPDATE CUSTOMER_TARGET CT
SET CT.TO_TIMESTAMP = $CURRENT_DATE_NTZ
FROM POC.SNOWFLAKE_POC.CUSTOMER_STAGE CS
WHERE CT.C_CUSTOMER_ID = CS.C_CUSTOMER_ID
AND (CT.C_FIRST_NAME IS DISTINCT FROM CS.C_FIRST_NAME
OR CT.C_LAST_NAME IS DISTINCT FROM CS.C_LAST_NAME
OR CT.C_BIRTH_YEAR IS DISTINCT FROM CS.C_BIRTH_YEAR
OR CT.C_BIRTH_COUNTRY IS DISTINCT FROM CS.C_BIRTH_COUNTRY
OR CT.C_LAST_REVIEW_DATE IS DISTINCT FROM CS.C_LAST_REVIEW_DATE)
AND CT.TO_TIMESTAMP = $EXPIRY_DATE_NTZ;
Your SQL does not have any issues with the filters (ORs are surrounded by the brackets etc). I assume that you have checked the execution profile, and did not see your filter (CT.TO_TIMESTAMP = '9999-08-17 07:31:29.901000000'). In this case, all rows in the target table should have this value in the column TO_TIMESTAMP.
I highly recommend you check the data first. If you are running multiple UPDATE/MERGE commands, you may miss that the data has already updated with this value.

ORA-38104 when trying to update my table using merge

I have a stored procedure in which I want to update some columns, so I wrote below code:
PROCEDURE UPDATE_MST_INFO_BKC (
P_SAPID IN NVARCHAR2
) AS
BEGIN
MERGE INTO tbl_ipcolo_billing_mst I
USING (
SELECT
R4G_STATE, -- poilitical state name
R4G_STATECODE, -- poilitical state code
CIRCLE, -- city name
NE_ID,
LATITUDE,
LONGITUDE,
SAP_ID
FROM
R4G_OSP.ENODEB
WHERE
SAP_ID = P_SAPID
AND ROWNUM = 1
)
O ON ( I.SAP_ID = O.SAP_ID )
WHEN MATCHED THEN
UPDATE SET I.POLITICAL_STATE_NAME = O.R4G_STATE,
I.POLITICAL_STATE_CODE = O.R4G_STATECODE,
I.CITY_NAME = O.CIRCLE,
I.NEID = O.NE_ID,
I.FACILITY_LATITUDE = O.LATITUDE,
I.FACILITY_LONGITUDE = O.LONGITUDE,
I.SAP_ID = O.SAP_ID;
END UPDATE_MST_INFO_BKC;
But it is giving me error as
ORA-38104: Columns referenced in the ON Clause cannot be updated: "I"."SAP_ID"
What am I doing wrong?
You are joining the source to destination tables on I.SAP_ID = O.SAP_ID and then, when matched, are trying to update them and set I.SAP_ID = O.SAP_ID. You cannot update the columns used in the join ... and why would you want to as you have already determined that the values are equal.
Just remove the last line of the UPDATE:
...
O ON ( I.SAP_ID = O.SAP_ID )
WHEN MATCHED THEN
UPDATE SET I.POLITICAL_STATE_NAME = O.R4G_STATE,
I.POLITICAL_STATE_CODE = O.R4G_STATECODE,
I.CITY_NAME = O.CIRCLE,
I.NEID = O.NE_ID,
I.FACILITY_LATITUDE = O.LATITUDE,
I.FACILITY_LONGITUDE = O.LONGITUDE;
The error message tells you what the problem is - a MERGE statement cannot update the columns used in the ON clause - and even tells you what column is the problem: "I"."SAP_ID".
So Oracle hurls ORA-38104 because of this line in your WHEN MATCHED branch
I.SAP_ID = O.SAP_ID;
Remove it and your problem disappears. Fortunately the line is unnecessary: I.SAP_ID already equals O.SAP_ID, otherwise the record wouldn't go down the MATCHED branch.
The reason why is quite straightforward: transactional consistency. The MERGE statement operates over a set of records defined by the USING clause and the ON clause. Updating the columns used in the ON clause threatens the integrity of that set, and so Oracle forbids it.

group function is not allowed here (sql-oracle)

I want to update saboloo with the following table
update sagani
set saboloo=sum(sagani.qula + sagani.shualeduri + sagani.finaluri)
where sagnis_id='9';
Aggregation is not allowed in an update, because update changes values in the rows in the table; once the data is aggregated, the connection to the original rows is lost.
I can imagine that you mean one of two things. The first would be a simple sum within the row:
update sagani
set saboloo = (sagani.qula + sagani.shualeduri + sagani.finaluri)
where sagnis_id = 9; -- looks like a number so I assume it is a number
Alternatively, you may want to update multiple rows with the same value added up from all those rows:
update sagani s
set saboloo = (select sum(s2.qula + s2.shualeduri + s2.finaluri)
from sagani s2
where s2.sagnis_id = s.sagnis_id
)
where s.sagnis_id = 9;
Your question doesn't have enough information to infer your intention, although the use of sagnis_id suggests that there is only one row and you don't want aggregation at all.
SUM is not applicable here as your requirement is very straight forward. You can try this following script for your purpose-
UPDATE sagani
SET saboloo=(sagani.qula + sagani.shualeduri + sagani.finaluri)
WHERE sagnis_id='9';

Update a Table using a Join

I wish to update a table using, but need to use another table to get the correct field. The new information is not taken from another field from another table.
The following SQL statement returns the correct information:
SELECT PURCHASEHEADER.ORDERNOTES
FROM PURCHASEHEADER, ASSEMBLYLINESOURCE
WHERE ASSEMBLYLINESOURCE.HEADERSYSUNIQUEID = 72637001
AND PURCHASEHEADER.ORDERNUMBER = ASSEMBLYLINESOURCE.PURCHASEORDERNUMBER
I have tried the following:
UPDATE PURCHASEHEADER SET PURCHASEHEADER.ORDERNOTES = 'Updated'
WHERE EXISTS (
SELECT 1 FROM ASSEMBLYLINESOURCE
WHERE PURCHASEHEADER.ORDERNUMBER = ASSEMBLYLINESOURCE.PURCHASEORDERNUMBER
) AND ASSEMBLYLINESOURCE.HEADERSYSUNIQUEID = 72637001
An error is returned saying: " ...Column Unknown ASSEMBLYLINESOURCE.HEADERSYSUNIQUEID..." but it does exist as it works in the first query.
I have seen similar posts from Mark Rotteveel dated July 2017, but still can't get it to work.
There is an issue with your closing bracket. Try this, it worked for me.
UPDATE PURCHASEHEADER set PURCHASEHEADER.ORDERNOTES = 'Updated'
WHERE EXISTS (SELECT 1 FROM ASSEMBLYLINESOURCE WHERE
PURCHASEHEADER.ORDERNUMBER = ASSEMBLYLINESOURCE.PURCHASEORDERNUMBER AND
ASSEMBLYLINESOURCE.HEADERSYSUNIQUEID = 72637001)

SQL - WHERE clause on each SET command in UPDATE?

I'm trying to create an SQL query in PHP to update a table.
Is it possible to have a different WHERE clause for each affected row?
eg something like:
UPDATE table
SET val=X WHERE someproperty = 1,
SET val=Y WHERE someproperty = 2
etc?
Any help appreciated. Thanks
Yes, you can with a CASE statement.
UPDATE table
SET val = CASE someproperty
WHEN 1 THEN x
WHEN 2 THEN y
....
ELSE
val
END
Now, there is concern that one CASE statement is less readable when compared to several UPDATE statements. There is a valid argument here. For example, when 1000 rows are being updated, it just feels and looks better to use several UPDATE statements rather than 1000 different conditions to a single CASE.
However, sometimes a CASE statement is more appropriate. If, for example, you are updating rows based on some trait, say the even or odd nature of a field's value the table, then a CASE statement is a wonderfully concise and maintainable way to update rows in the table without having to resort to a huge number of UPDATE statements that all share a specific type of logic. Take this for example:
UPDATE table
SET val = CASE MOD(someproperty, 2)
WHEN 0 THEN x
WHEN 1 THEN y
END
This expression takes the modulus of someproperty and, when 0 (even), assigns value x to val and, when 1 (odd), assigns value y to val. The greater the volume of data being updated by this statement, the cleaner it is compared to doing so by multiple UPDATE statements.
In short, CASE statements are sometimes just as readable/maintainable as UPDATE statements. It all depends on what you are trying to do with them.
EDIT: Added the ELSE clause to be extra safe. The OP may be interested in updating only specific rows so the rest should remain as they prior to the UPDATE.
EDIT: Added a scenario where the CASE statement is a more effective approach than multiple UPDATE statements.
You cannot have multiple WHERE clauses for any SQL statement, however you can use a CASE statement to accomplish what you are trying to do. Another option that you have is to execute multiple UPDATE statements.
Here is a sample using the CASE statement:
UPDATE table
SET val = (
CASE someproperty
WHEN 1 THEN X
WHEN 2 THEN Y
ELSE val
END
);
Here is a sample using multiple UPDATE statements:
UPDATE table SET val=X WHERE someproperty = 1;
UPDATE table SET val=Y WHERE someproperty = 2;
Nope. Make it two updates:
UPDATE table SET val=X WHERE someproperty = 1;
UPDATE table SET val=Y WHERE someproperty = 2;
On second thought, you could use sub-queries or the case statement...
UPDATE table SET val= ( case when someproperty = 1 then X when someproperty = 2 then Y else val END )
You may need to make that a sub query like this:
UPDATE table t1 SET val = ( select CASE when someproperty = 1 then X when someproperty = 2 then Y ELSE val END from table t2 where t1.primarykey = t2.primary key )
UPDATE TABLE
SET VAL CASE SOMEPROPERTY WHEN 1 THEN X WHEN 2 THEN Y END
A compact and easily scaleable way:
UPDATE table1 SET val=ELT(FIND_IN_SET(someproperty, '1, 2'), X, Y);
make the query this way:
$condition = array(1, 2);
$newvals = array('X', 'Y');
$query = "UPDATE table1 SET val=ELT(FIND_IN_SET(someproperty, '". implode(',', $condition). "', ". implode(', ', $newvals). ")";
Use prepare_query to avoid SQL syntax errors if you deal with string values.