Postgres 10.5: Create Materialized View where column data may be empty/null? - postgresql

I am creating a Materialized View from two tables, using the array_agg function to join strings from table_b to table_a. Essentially, column_c on table_a is a nullable array of numbers corresponding to the id column of table_b (which has only two columns, id and description). However, the Materialized View fails to include a row for any row on table_a that is null / empty on column_c.
Is it possible to make the Materialized either (1) enter an empty array; or (2) a null value, when table_a column_c value is null?
CREATE MATERIALIZED VIEW my_materialized_view
AS
SELECT
id,
column_a,
column_b,
array_agg(description) as column_c
FROM table_a
JOIN table_b on table_b.id = any(column_c)
GROUP BY table_a.id
ORDER BY table_a.id ASC
WITH DATA;

Use LEFT JOIN:
CREATE MATERIALIZED VIEW my_materialized_view
AS
SELECT
id,
column_a,
column_b,
array_agg(description) as column_c
-- or
-- coalesce(array_agg(description), '{}') as column_c
FROM table_a
LEFT JOIN table_b on table_b.id = any(column_c)
GROUP BY table_a.id
ORDER BY table_a.id ASC
WITH DATA;

Related

In postgresql, Copying data of a column from table1 to table2 which is of different datatype in table1 and table2

Text datatype of a column in table1 has to be converted to integer datatype in table2 while copying the data. That is 3 categories are there in a column of table1 which has to be converted to integer type like(1, 2,3) in table2
Frist create select sql command from table 1 with the casting column and then create insert statement like this
insert into table2 (categories) select categories ::integer from table1
if you have more then 1 comunm then
insert into table2 (categories,column1) select categories ::integer,column1 from table1

Postgres join involving tables having join condition defined on an text array

I have two tables in postgresql
One table is of the form
Create table table1(
ID serial PRIMARY KEY,
Type []Text
)
Create table table2(
type text,
sellerID int
)
Now i want to get all the rows from table1 which are having type same that in table2 but the problem is that in table1 the type is an array.
In case the type in the table has an identifiable delimiter like ',' ,';' etc. you can rewrite the query as regexp_split_to_table(type,',') or versions later than 9.5 unnest function can be use too.
For eg.,
select * from
( select id ,regexp_split_to_table(type,',') from table1)table1
inner join
select * from table2
on trim(table1.type) = trim(table2.type)
Another good example can be found - https://www.dbrnd.com/2017/03/postgresql-regexp_split_to_array-to-split-string-using-different-delimiters/
SELECT
a[1] AS DiskInfo
,a[2] AS DiskNumber
,a[3] AS MessageKeyword
FROM (
SELECT regexp_split_to_array('Postgres Disk information , disk 2 , failed', ',')
) AS dt(a)
You can use the ANY operator in the JOIN condition:
select *
from table1 t1
join table2 t2 on t2.type = any (t1.type);
Note that if the types in the table1 match multiple rows in table2, you would get duplicates (from table1) because that's how a join works. Maybe you want an EXISTS condition instead:
select *
from table1 t1
where exists (select *
from table2 t2
where t2.type = any(t1.type));

PostgreSQL - Append a table to another and add a field without listing all fields

I have two tables:
table_a with fields item_id,rank, and 50 other fields.
table_b with fields item_id, and the same 50 fields as table_a
I need to write a SELECT query that adds the rows of table_b to table_a but with rank set to a specific value, let's say 4.
Currently I have:
SELECT * FROM table_a
UNION
SELECT item_id, 4 rank, field_1, field_2, ...
How can I join the two tables together without writing out all of the fields and without using an INSERT query?
EDIT:
My idea is to join table_b to table_a somehow with the rank field remaining empty, then simply replace the null rank fields. The rank field is never null, but item_id can be duplicated and table_a may have item_id values that are not in table_b, and vice-versa.
I am not sure I understand why you need this, but you can use jsonb functions:
select (jsonb_populate_record(null::table_a, row)).*
from (
select to_jsonb(a) as row
from table_a a
union
select to_jsonb(b) || '{"rank": 4}'
from table_b b
) s
order by item_id;
Working example in rextester.
I'm pretty sure I've got it. The predefined rank column can be inserted into table_b by joining to the subset of itself with only the columns left of the column behind which you want to insert.
WITH
_leftcols AS ( SELECT item_id, 4 rank FROM table_b ),
_combined AS ( SELECT * FROM table_b JOIN _leftcols USING (item_id) )
SELECT * FROM _combined
UNION
SELECT * FROM table_a

Joining Null values

Table 1
Table 2
select col1, col2, etc
from table 1
left join table 2
on table1.col1 = table2.col1
If table2.col1 has null values, will this somehow screw up my join results?
No, table2 null values do not matter in this case. Left join will match all rows from table1 to table2. If a row from table2 does not have a match in table1 it will not appear in the result set.

How to retrieve duplicate records and delete them in table A, also insert these duplicate records in another table B (in postgres)

how to retrieve duplicate records and delete them in table A, also insert these retrieved duplicate records in another table B (in postgres db)
SQL query's are required for my project.
To delete duplicates without having a unique column you can use the ctid virtual column which is essentially the same thing as the rowid in Oracle:
delete from table_A t1
where ctid <> (select min(t2.ctid)
from table_A t2
where t1.unique_column = t2.unique_column);
You can use the returning clause to get the deleted rows and insert them into the other table:
with deleted as (
delete from table_A x1
where ctid <> (select min(t2.ctid)
from table_A t2
where t1.unique_column = t2.unique_column);
returning *
)
insert into table_B (col_1, col_2)
select unique_column, some_other_column
from deleted;
If you further want to see those deleted rows, you can throw in another CTE:
with deleted as (
delete from table_A x1
where ctid <> (select min(t2.ctid)
from table_A t2
where t1.unique_column = t2.unique_column);
returning *
), moved as (
insert into table_B (col_1, col_2)
select unique_column, some_other_column
from deleted
returning *
)
select *
from moved;