Update Postgresl table, skip row if conflict - postgresql

I have a question that's very similar to other SO questions, but I haven't been able to find my exact case. I would like to update a PostgreSQL table as follows:
update my_table
set my_timestamp = null
where TO_CHAR(my_timestamp :: DATE, 'dd-mm-yyyy') = '01-01-1970' and cast(my_timestamp as time) > '10:10:10'
The problem is setting my_timestamp = null violates a uniqueness constraint. In these cases I would like to skip that particular row. So I added the following line to my code.
update my_table
set my_timestamp = null
where TO_CHAR(my_timestamp :: DATE, 'dd-mm-yyyy') = '01-01-1970' and cast(my_timestamp as time) > '10:10:10'
ON CONFLICT ON CONSTRAINT my_constraint do nothing
But this gives a syntax error and I can't figure out the exact right way to fix it. What's the right way to do this?

Related

PostgreSQL using timestamp difference in partial index for upsert

I need to get real-time data and put it into a Postgres table so compare the columns oid and rcv_time respectively with newly received ones.
If this oid previously has been inserted and its received time is more than two hours from now should be inserted otherwise only need to be updated based on oid
So I want to create a partial index like below which indicates timestamp difference as conditional unique constraint:
CREATE UNIQUE INDEX oid_uqidx ON my_table (oid,rcv_time) where EXTRACT(EPOCH FROM (CURRENT_TIMESTAMP - rcv_time)) / 3600 < 2;
and as a sample my upsert query would be :
INSERT INTO my_table (oid, rcv_time, name)
VALUES ('730048b','2020-04-24 02:46:00','test')
ON CONFLICT ON CONSTRAINT oid_uqidx
DO UPDATE SET (rcv_time,name) = (EXCLUDED.rcv_time,EXCLUDED.name);
But when I try to create index the following error occurs:
ERROR: functions in index predicate must be marked IMMUTABLE
I also tried to work around without partial index by putting the where clause in upsert query
and instead, create a unique constraint on oid.
INSERT INTO my_table (oid, rcv_time, name)
VALUES ('730048b','2020-04-24 02:46:00','test')
ON CONFLICT(oid) where EXTRACT(EPOCH FROM (CURRENT_TIMESTAMP - rcv_time)) / 3600 < 2
DO UPDATE SET (rcv_time,name) = (EXCLUDED.rcv_time,EXCLUDED.name);
But It doesn't let me have multiple same oid and always do the update.
How can I approach the problem?

Exclusion constraint that allows overlapping at the boundaries

I tried to have a PostgreSQL constraint so that there will be no overlap between two date intervals. My requirement is that the date c_from for one entry can be the same as c_until for another date.
Eg: "01/12/2019 12/12/2019" and "12/12/2019 31/21/2019" are still date ranges that do not conflict. I have "[]" in my query but it seems not to work.
user_no INTEGER NOT NULL REFERENCES usr,
c_from DATE DEFAULT NOW(),
c_until DATE DEFAULT 'INFINITY',
CONSTRAINT unique_user_per_daterange EXCLUDE USING gist (user_no WITH =, daterange(c_from, c_until, '[]') WITH && )
When I have the date range above, I get this error:
(psycopg2.IntegrityError) conflicting key value violates exclusion constraint "unique_user_per_daterange"
Could you please help?
Use ranges that do not include one of the ends:
daterange(c_from, c_until, '[)')
Then they won't conflict, even if one interval ends at the same point where another begins.

MemSql > workaround for SELECT ... FOR UPDATE

I am using MemSql as my DB and I need to have SELECT ... FOR UPDATE functionality. However it is not supported in 6.5 version, which I am using. Is there any workaround for this problem?
My problem is as follows: multiple processes pick a single record (that has not been process yet) from the same table, do some job out of SQL code then do UPDATE for marking the record as processed. If I had a possibility to do SELECT ... FOR UPDATE then I could lock the record for assuring that only one process can pick it.
As a workaround that I can think of is using some LockToken column and do something like
UPDATE Tbl SET LockToken = 'a_unique_token' WHERE LockToken IS NULL LIMIT 1;
SELECT * FROM Tbl WHERE LockToken = 'a_unique_token';
but in this case I get
Error Code: 1749. Feature 'UPDATE...LIMIT must be constrained to a single partition' is not supported by MemSQL Distributed.
I could also do the job with LOCK TABLES, but according to this they are not supported as well.
Is there any workaround to this type of problem?
Yes, your workaround is a good idea. One way you could workaround that error is to pick a specific row to lock instead of using LIMIT 1, like UPDATE Tbl SET LockToken = 'a_unique_token' WHERE LockToken IS NULL and id = (select id from Tbl WHERE LockToken IS NULL limit 1). (Or you could use (select min(id) from Tbl WHERE LockToken IS NULL) or something similar to pick an id depending on what you want.) This should work well if you have an index on id.
Also, you could check out version 6.7 where select for update is now supported: https://docs.memsql.com/sql-reference/v6.7/select/.

Postgresql Update statement

I am currently operating with 2 tables: one is a live one and one is a stage one. Above code updates values in the live table using staging table as a source. It only updates values in column "firstname" if the row in the stage table already exists in the live table and some other simple criteria.
Update LiveTable
SET LiveTable.firstname = TestTable.firstname
FROM TestTable
WHERE EXISTS (SELECT 1 FROM LiveTable WHERE LiveTable.userid = TestTable.userid)
AND TestTable.firstname IS NOT NULL
AND LEN(TestTable.firstname) > len(LiveTable.firstname);
Above code jets the job done but takes quite some time. I was wondering if there is any faster way to do it.
I have tries to create FUNCTION to do the same thing, but was not able to get it to work.
Use a join between the two tables
Update LiveTable
SET LiveTable.firstname = TestTable.firstname
FROM TestTable
WHERE LiveTable.userid = TestTable.userid
AND TestTable.firstname IS NOT NULL
AND length(TestTable.firstname) > len(LiveTable.firstname);
The condition TestTable.firstname IS NOT NULL is not really needed because length(TestTable.firstname) > len(LiveTable.firstname) will filter out rows where firstname is null anyway. And it should be length() not len().

I want to update multiple rows in a table but iff the value of a certain column does not exist in a different table?

This select query give me the columns I want to modify
Select * From Location
where Location.DeviceAddress not in (Select DeviceAddress From Device) order by DeviceAddress desc
However, this update query
Update Location
set DeviceAddress = NULL
where Location.DeviceAddress not in (Select DeviceAddress From Device)
Gives me the following error:
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
The statement has been terminated.
For reference I am using Microsoft Server 2008 , and, as always, assistance is much appreciated
Turns out this error was being caused by a query in an update trigger on the Location table so I was able to solve it by disabling (and after some time fixing) the trigger. Thank you to all who took the time to help me.
you might want to try
Update Location set DeviceAddress = NULL where Location.DeviceAddress not in (Select
top 1 DeviceAddress From Device where Device.DeviceAddress == Location.DeviceAddress)
in this case your subquery will return only 1 value instead of multiple.
try
Update
Location
set
DeviceAddress = NULL
where
not exists (Select null From Device where Device.DeviceAddress = Location.DeviceAddress)