Set value of a column based on another column - postgresql

I have the following table in Postgres 11.
col1 col2 source col3
a abc curation rejected
a abc DB
b etg DB accepted
c jfh curation
How can I assign value in col3 based on the values in col1
The expected output is:
col1 col2 source col3
a abc curation rejected
a abc DB rejected
b etg DB accepted
c jfh curation null
Is there a way to check if values in col1 and col2 in subsequent rows are identical, then assign same col3 to all the rows (if the col3 value in other row is null).
Any help is highly appreciated.

You're not entirely clear on what the criteria is, but at a basic level it could depend on how you want to query this data, there are multiple ways you could do this.
Generated Columns
drop table if exists atable ;
CREATE TABLE atable (
cola text ,
colb text GENERATED ALWAYS AS (case when cola='a' then 'rejected' else
null end) STORED
);
insert into atable(cola) values ('a')
A View.
create or replace view aview as
select cola, case when cola='a' then 'rejected' else null end as colb
from atable;
Both would yield the same results.
cola|colb |
----+--------+
a |rejected|
Other options could be a materialized view, simple query logic.
You have options.

update a2 set
col3 =
case when col1 = 'a' then 'rejected'
when col1 = 'b' then 'accepted'
when col1 = 'c' then 'null' end
where col3 is null
returning *;
You can also set triggers. But generated columns only available from 12. So you need upgrade to use generated columns.
db fiddle

Related

select distinct values in multiple column and save in common column with column tags

I have a table in postgres with two columns:
col1 col2
a a
b c
d e
f f
I would like to have distinct on the two columns and make one column and later assign the tag of column name from where it is coming. The desired output is:
col source
a col1, col2
b col1
c col1
d col1
e col1
f col1, col2
I am able to find distinct in individual columns but not able to make a single column and add label source.
below is the query i am using:
select distinct on (col1, col2) col1, col2 from table
Any suggestions would be really helpful.
You can un-pivot the columns and the aggregate them back:
select u.value, string_agg(distinct u.source, ',' order by u.source)
from data
cross join lateral (
values('col1', col1), ('col2', col2)
)as u(source,value)
group by u.value
order by u.value;
Online example
Alternatively, if you don't want to list each column, you can convert the row to a JSON value and then un-pivot that:
select x.value, string_agg(distinct x.source, ',' order by x.source)
from data d
cross join lateral jsonb_each_text(to_jsonb(d)) as x(source, value)
group by x.value
order by x.value;

PostgreSQL - check if a row is completely filled in

I've seen questions for checking if a row merely exists, But I haven't seen anything (on SO or elsewhere) about whether or not all the data is filled in.
I was hoping that SELECT true FROM myTable WHERE name='myRow' AND * IS NOT NULL; would work, but it doesn't.
What wildcard will work in place of the asterisk, if there is one? Will I have to put in each column name into the query individually?
You can indeed reference the whole row, but not using *, but by using the table name:
SELECT true
FROM myTable
WHERE name='myRow'
AND myTable IS NOT NULL;
The IS NOT NULL operator on a row value returns true if all columns of the row are not null.
The following statement:
with mytable (col1, col2, col3) as (
values
(1,null,null),
(null,1,null),
(null,null,1),
(1,1,1)
)
select *
from mytable
where mytable is not null;
will return:
col1 | col2 | col3
-----+------+-----
1 | 1 | 1
The opposite btw. is not true. where mytable is null will not return anything because a row is by definition never null (because then it wouldn't exist). To find rows where at least one column is null you would need to use where not (mytable is not null)
A similar problem is described here: https://dba.stackexchange.com/q/143959/1822

NOT NULL constraint on a column when another column has a particular value

create table test (
col1 varchar(20),
col2 varchar(20)
)
When col1 has value '1', col2 cannot be null.
When col1 has any other value, col2 can be null.
Is there a way to write a check constraints based on values of particular columns?
You can write a table-level constraint, sure.
CREATE TABLE test (
col1 VARCHAR(20),
col2 VARCHAR(20),
CHECK (col1 != '1' OR col2 IS NOT NULL)
);
Either col1 isn't '1' (and col2 can be anything), or col1 is '1' (and col2 can't be null).
See the third example in the manual.

PostgreSQL - How to get distinct on two columns separately?

I've a table like this:
Source table "tab"
column1 column2
x 1
x 2
y 1
y 2
y 3
z 3
How can I build the query to get result with unique values in each of two columns separately. For example I'd like to get a result like one of these sets:
column1 column2
x 1
y 2
z 3
or
column1 column2
x 2
y 1
z 3
or ...
Thanks.
What you're asking for is difficult because it's weird: SQL treats rows as related fields but you're asking to make two separate lists (distinct values from col1 and distinct values from col2) then display them in one output table not caring how the rows match up.
You can so this by writing the SQL along those lines. Write a separate select distinct for each column, then put them together somehow. I'd put them together by giving each row in each results a row number, then joining them both to a big list of numbers.
It's not clear what you want null to mean. Does it mean there's a null in one of the columns, or that there's not the same number of distinct values in each column? This one problem from asking for things that don't match up with typical relational logic.
Here's an example, removing the null value from the data since that confuses the issue, different data values to avoid confusing rowNumber with data and so there are 3 distinct values in one column and 4 in another. This works for SQL Server, presumably there's a variation for PostgreSQL.
if object_id('mytable') is not null drop table mytable;
create table mytable ( col1 nvarchar(10) null, col2 nvarchar(10) null)
insert into mytable
select 'x', 'a'
union all select 'x', 'b'
union all select 'y', 'c'
union all select 'y', 'b'
union all select 'y', 'd'
union all select 'z', 'a'
select c1.col1, c2.col2
from
-- derived table giving distinct values of col1 and a rownumber column
( select col1
, row_number() over (order by col1) as rowNumber
from ( select distinct col1 from mytable ) x ) as c1
full outer join
-- derived table giving distinct values of col2 and a rownumber column
( select col2
, row_number() over (order by col2) as rowNumber
from ( select distinct col2 from mytable ) x ) as c2
on c1.rowNumber = c2.rowNumber

Find all rows same value in Col1 but different values in Col2

Given a table similar to this:
Col1 Col2
---- ----
A A
A A
B B
C C
C D
I'm trying to write a query which will identify all values in Col1 which appear more than once AND have differing values in Col2. So a query that would return only rows with C in Col1 (because there are two rows with C in Col1, and they have differing values in Col2).
Groupy by col1 and take only the ones having more than 1 unique col2. These automatically have more than one col1 value too.
select col1
from your_table
group by col1
having count(distinct col2) > 1