PostgresQL: Value is only allowed in one of two columns - postgresql

I have a database with two tables "Config" and "Config_xml", each consisting of the same columns (id, content, modifier, etc...). The only difference is, that config only contains non-xml strings in its content column, whereas config_xml contains an xml string in its content column.
Now I'd like to combine these two tables into one, providing a content column and an xml_content column, to simplify querying, because at the moment I always have to query on both tables.
Now is there a way to constrain each row to allow a value in either content or xml_content?
Thanks in advance.

You can use a check constraint that requires one column to be null.
alter table the_table
add constraint check_content
check (num_nulls(config, config_xml) = 1);
To also avoid empty strings, you might want to use:
check (num_nulls(nullif(trim(config::text), ''), nullif(trim(config_xml::text), '')) = 1)

Related

Postgresql: How can I duplicate a table with its default values on columns?

Is it even possible to copy a structure from a table without data but with the columns definitions specially like defaults and nullable values ?
This is not working:
select *
into new_ledger_table
from details_table
where 1 = 2;
Yes, that's what create table (like ..) is for:
create table new_ledger_table (like details_table including defaults)
The including part has more options to optionally include constraints and indexes.

I have two columns, I want the second column to have the same values as the first column

I have two columns, I want the second column to have the same values as the first column always, in PostgreSQL.
The columns are landmark_id (integer) and name (varchar), I want the name column to always have the same values (id's) from landmark_id.
landmark_id (integer) | name (varchar)
1 1
2 2
3 3
I don't understand why you would want to do that, but I can think of two ways to accomplish your request. One is by using a generated column
CREATE TABLE g (
landmark_id int,
name varchar(100) GENERATED ALWAYS AS (landmark_id::varchar) STORED
)
and the other is by enforcing a constraint
CREATE TABLE c (
landmark_id int,
name varchar(100),
CONSTRAINT equality_cc CHECK (landmark_id = name::varchar)
)
Both approaches will cause the name column to occupy disk space. The first approach will not allow you to specify the name column in INSERT or UPDATE statements. In the latter case, you will be forced to specify both columns when inserting.
You could also have used a trigger to update the second column.
Late edit: Others suggested using a view. I agree that it's a better idea than what I wrote.
Create a view, as suggested by #jarlh in comments. This automatically generates column name for you on the fly. This is usually preferred to storing essentially the same data multiple times as in an actual table, where the data occupies more disk space and also can get out of sync. For example:
CREATE VIEW landmarks_names AS
SELECT landmark_id,
landmark_id::text AS name
FROM landmarks;

PostgreSQL - Dynamic addition of large no of columns

Assume I have a table named tracker with columns (issue_id,ingest_date,verb,priority)
I would like to add 50 columns to this table.
Columns being (string_ch_01,string_ch_02,.....,string_ch_50) of datatype varchar.
Is there any better way to add columns with single procedure rather than executing the following alter command 50 times?
ALTER TABLE tracker ADD COLUMN string_ch_01 varchar(1020);
Yes, a better way is to issue a single ALTER TABLE with all the columns at once:
ALTER TABLE tracker
ADD COLUMN string_ch_01 varchar(1020),
ADD COLUMN string_ch_02 varchar(1020),
...
ADD COLUMN string_ch_50 varchar(1020)
;
It's especially better when there are DEFAULT non-null clauses for the new columns, since each of them would rewrite the entire table, as opposed to rewriting it only once if they're grouped in a single ALTER TABLE.

How to query PostgreSQL for all records where hstore is empty?

I would like to query my PostgreSQL table for all rows that have an empty hstore. It must be obvious to all but me, as I can't find any documentation on how to do it nor other StackOverflow questions answering the question. Checking for NULL isn't helpful, as I get back all rows, even those rows where properties has no keys/values:
SELECT widgets.*
FROM "widgets"
WHERE properties IS NOT NULL
Any ideas how to do this?
One option would be to return all keys of the column as an array and check if that array is not empty:
SELECT *
FROM widgets
WHERE properties IS NOT NULL
AND array_length(akeys(properties),1) > 0;
A simpler way of doing this as per a message on the PostgreSQL listerve is:
SELECT * FROM widgets WHERE properties = ''::HSTORE;
an aside:
As a general rule, I would recommend that you don't have a column which can be empty sometimes and NULL other times, outside of distinct cases where you want a semantic difference there, e.g. for an application that interprets the two differently. Especially for BOOLEAN columns, I generally choose to prevent this extra degree of freedom.
I often do something do something similar to:
ALTER TABLE widgets ALTER COLUMN properties SET NOT NULL;
-- OR:
ALTER TABLE widgets ADD CONSTRAINT its_null_or_nothin CHECK ( properties <> ''::HSTORE );
Depending on what you find easier to remember, you can also create an empty hstore via hstore('{}'::TEXT[]).

How to constrain that a table gets multiple values in t-sql?

I thought of creating a trigger in t-sql that constrains having multiple values of the same column. It has three unique keys - which needs to be unique.
How to get the current row in a t-sql trigger? Is it possible?
If those values are predefined you can create an other table which contain all these unique values and then create FK constraint.
For me it looks like as standard look up table: