In a PostgreSQL 9.5.1 database I have a table:
CREATE TABLE test.table01 (
pgid serial NOT NULL,
sample_id text NOT NULL,
all_data jsonb NOT NULL,
CONSTRAINT table01_pkey
PRIMARY KEY (pgid)
)
And a view of that table:
CREATE OR REPLACE VIEW test.test_view AS
SELECT table01.sample_id,
table01.all_data ->> 'technician'::text AS technician,
table01.all_data ->> 'depth'::text AS depth,
table01.all_data ->> 'colour'::text AS colour,
table01.all_data ->> 'duplicate of'::text AS dupe_of
FROM test.table01;
Finally, on that view, I have created a RULE that aims to correctly modify the underlying jsonb object on updates against the view:
CREATE OR REPLACE RULE upd_test_view AS
ON UPDATE TO test.test_view WHERE new.colour <> old.colour
DO INSTEAD
UPDATE test.table01 SET all_data = jsonb_set(table01.all_data, '{colour}'::text[], (('"'::text || new.colour) || '"'::text)::jsonb);
When I subsequently issue
UPDATE test.test_view SET colour = 'Purple' WHERE sample_id = '1234567';
I get back
ERROR: no relation entry for relid 2
********** Error **********
ERROR: no relation entry for relid 2
SQL state: XX000
I must be doing something wrong, but I can't quite get my head around it. Your expertise is very much appreciated. Thank you.
I am no expert in this at all, but I ran into the same error message, and in my case I could solve this by removing the WHERE part of the rule. This will make the rule trigger more frequently, but it solved this problem for me. See if it works for you as well if this is still relevant.
Related
Allright this one is bugging me. Im not that versed in PostgreSQL yet, so it's probably a gap in my knowledge
Consider this:
insert into aaa (afdel_id, elev_id,periode,primaer_afd) select :AFD_ID, :ELEV_ID,
daterange(:PR_DATO, null, '[]'), true
ON CONFLICT ON CONSTRAINT afdel_elev_periode_ck
DO UPDATE SET primaer_afd = true, periode = daterange(least(lower(periode), :PR_DATO), null, '[]')
it gives me the error "column reference "periode" is ambiguous" propably due to this periode = daterange(least(lower(periode), :PR_DATO), null, '[]')
What I want to do is setting the lower part of the daterange [periode] to the first date of lower(periode) and :PR_DATO. (and just set any upper(periode) to null)
What am I missing?
You are using ON CONFLICT so you have access to different versions of a column when you do an UPDATE. The original version which is accessed as table_name.col_name and the proposed new value which is exclude.col_name. This is where the error is coming from. Postgres does not know which value you want to use for periode in daterange(least(lower(periode).
For more information see:
https://www.postgresql.org/docs/current/sql-insert.html#SQL-ON-CONFLICT
You need to prefix the column name with the table name to avoid the ambiguity
insert into aaa (afdel_id, elev_id,periode,primaer_afd)
select :AFD_ID, :ELEV_ID, daterange(:PR_DATO, null, '[]'), true
ON CONFLICT ON CONSTRAINT afdel_elev_periode_ck
DO UPDATE
SET primaer_afd = true,
periode = daterange(least(lower(aaa.periode), :PR_DATO), null, '[]')
I create a domain to catch empty strings:
CREATE DOMAIN TEXTN AS TEXT
CONSTRAINT non_empty CHECK (length(VALUE) > 0);
Then I replace all text/varchars fields on the DB with TEXTN.
However, when I get a error, it not give much info:
DbError { severity: "ERROR", parsed_severity: Some(Error),
code: SqlState("23514"),
message: "value for domain textn violates check constraint \"non_empty\"",
detail: None, hint: None, position: None, where_: None,
schema: Some("libs"),
table: None,
column: None, datatype: Some("textn"),
constraint: Some("non_empty")}
It not even tell me in what table and field the check fail.
If is even possible to print the row to insert better, but at least table and field is possible?
PostgreSQL (I checked version 11) simply does not provide this information as part of the protocol. Consider these statements:
=> CREATE DOMAIN TEXTN AS TEXT CONSTRAINT non_empty CHECK (length(VALUE) > 0);
CREATE DOMAIN
=> CREATE TABLE test_table (test_column textn);
CREATE TABLE
=> INSERT INTO test_table VALUES ('');
ERROR: value for domain textn violates check constraint "non_empty"
The error message on the wire looks like this:
S ERROR
V ERROR
C 23514
M value for domain textn violates check constraint "non_empty\
s public
d textn
n non_empty
F execExprInterp.c
L 3494
R ExecEvalConstraintCheck
There is no trace of test_table or test_column.
If you have some control over how your framework creates tables, it may be possible to use named table constraints instead of domain types, like this:
CREATE TABLE test_table (
test_column text
CONSTRAINT test_column_check CHECK (length(test_column) > 0));
If you make sure that the constraint name uniquely identifies the column, you can use that to recover the problematic column.
Even for a CHECK constraint defined on the column, as in CREATE TABLE test_table (test_column text CHECK (length(test_column) > 0));, PostgreSQL does not report the column name. You only get the name of the constraint, which is autogenerated by PostgreSQL on table creation and usually starts with the column name, but this is not guaranteed.
I am running an update query like
update datavalue
set categoryoptioncomboid = '21519'
where dataelementid = '577' and
categoryoptioncomboid = '471';
but it is giving an error
ERROR: duplicate key value violates unique constraint "datavalue_pkey"
DETAIL: Key (dataelementid, periodid, sourceid, categoryoptioncomboid, attributeoptioncomboid)=(577, 35538, 10299, 21519, 15) already exists.
Is there a way to make postgres continue updating and skip any errors? Is there a way without using procedure for loop?
I'd try something like this:
update datavalue
set categoryoptioncomboid = '21519'
where
dataelementid = '577' and categoryoptioncomboid = '471'
and not exists (
select 1
from datavalue dv
where dv.dataelementid=datavalue.dataelementid
and dv.periodid=datavalue.periodid
and dv.sourceid=datavalue.sourceid
and dv.categoryoptioncomboid='21519'
and dv.attributeoptioncomboid=datavalue.attributeoptioncomboid
);
Another idea is to insert with on conflict and then delete unneeded rows. But it requires knowledge of the full definition of datavalue table columns.
I am trying to get the values from a small table, that are not present as columns in an existing table.
Here is some code I tried in SQL Server 2012:
BEGIN TRAN;
GO
CREATE TABLE [dbo].[TestValues](
[IdValue] [int] IDENTITY(1,1) NOT NULL,
[Code] [nvarchar](100) NULL,
) ON [PRIMARY];
GO
CREATE TABLE [dbo].[TestColumns](
[DateHour] [datetime2](7) NULL,
[test1] [nvarchar](100) NULL,
[test2] [nvarchar](100) NULL
) ON [PRIMARY]
GO
INSERT INTO [dbo].[TestValues] ([Code])
VALUES
(N'test1')
, (N'test2')
, (N'test3')
;
GO
SELECT
v.[Code]
, c.[name]
FROM
[dbo].[TestValues] AS v
LEFT OUTER JOIN [sys].[columns] AS c ON v.[Code] = c.[name]
WHERE
(c.[object_id] = OBJECT_ID(N'[dbo].[TestColumns]'))
AND (c.[column_id] > 1)
;
WITH
cteColumns AS (
SELECT
c.[name]
FROM
[sys].[columns] AS c
WHERE
(c.[object_id] = OBJECT_ID(N'[dbo].[TestColumns]'))
AND (c.[column_id] > 1)
)
SELECT
v.[Code]
, c.[name]
FROM
[dbo].[TestValues] AS v
LEFT OUTER JOIN cteColumns AS c ON v.[Code] = c.[name]
;
GO
ROLLBACK TRAN;
GO
In my opinion the two selects should have the same output. Can someone offer an explanation please?
TestValues is a table receiving data. TestColumns is a table that was created, when the project was started, by persisting a PIVOT query. Recently the process inserting into TestValues received some new data. I tried to get the new values using the first query and I was surprised when the result didn't show anything new.
Edit 1: Thank you dean for the answer, it sounds like a good explanation. Do you have any official page describing the behaviours of unpreserved tables? I did a quick google search and all I got was links towards Oracle. (added as an edit because I do not have enough reputation points to comment)
I'm using postgresql 9.0 beta 4.
After inserting a lot of data into a partitioned table, i found a weird thing. When I query the table, i can see an empty row with null-like values in 'not-null' fields.
That weird query result is like below.
689th row is empty. The first 3 fields, (stid, d, ticker), are composing primary key. So they should not be null. The query i used is this.
select * from st_daily2 where stid=267408 order by d
I can even do the group by on this data.
select stid, date_trunc('month', d) ym, count(*) from st_daily2
where stid=267408 group by stid, date_trunc('month', d)
The 'group by' results still has the empty row.
The 1st row is empty.
But if i query where 'stid' or 'd' is null, then it returns nothing.
Is this a bug of postgresql 9b4? Or some data corruption?
EDIT :
I added my table definition.
CREATE TABLE st_daily
(
stid integer NOT NULL,
d date NOT NULL,
ticker character varying(15) NOT NULL,
mp integer NOT NULL,
settlep double precision NOT NULL,
prft integer NOT NULL,
atr20 double precision NOT NULL,
upd timestamp with time zone,
ntrds double precision
)
WITH (
OIDS=FALSE
);
CREATE TABLE st_daily2
(
CONSTRAINT st_daily2_pk PRIMARY KEY (stid, d, ticker),
CONSTRAINT st_daily2_strgs_fk FOREIGN KEY (stid)
REFERENCES strgs (stid) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT st_daily2_ck CHECK (stid >= 200000 AND stid < 300000)
)
INHERITS (st_daily)
WITH (
OIDS=FALSE
);
The data in this table is simulation results. Multithreaded multiple simulation engines written in c# insert data into the database using Npgsql.
psql also shows the empty row.
You'd better leave a posting at http://www.postgresql.org/support/submitbug
Some questions:
Could you show use the table
definitions and constraints for the
partions?
How did you load your data?
You get the same result when using
another tool, like psql?
The answer to your problem may very well lie in your first sentence:
I'm using postgresql 9.0 beta 4.
Why would you do that? Upgrade to a stable release. Preferably the latest point-release of the current version.
This is 9.1.4 as of today.
I got to the same point: "what in the heck is that blank value?"
No, it's not a NULL, it's a -infinity.
To filter for such a row use:
WHERE
case when mytestcolumn = '-infinity'::timestamp or
mytestcolumn = 'infinity'::timestamp
then NULL else mytestcolumn end IS NULL
instead of:
WHERE mytestcolumn IS NULL