Create a column in a table view with a value based on a group of rows in another table - postgresql

I'd like to create a table view and include a new column that is based on values from another table.
Many rows of table B belong to one row of table A.
Table B has a status column (with values like active, completed, etc) and a foreign key (for table A).
In the new table view (for A) I want to create an active column (true / false) that is based on any related rows in table B having a status value of active and a matching foreign key.

If it is just about checking if the value exists, then this should do the job
select A.c1,
A.c2,
-- other columns from A
case when exists (select 1 from B_Table B where A.FK = B.FK and B.status = 'active')
then 'true'
else 'false'
end as Active
from A_Table B

Related

It takes a long time to compare two table values (large volume)

Table a has 100 row with name columns.
Table b is the same structure as Table A, but has 10 million rows.
Create a query to verify that the value of table a is not in table b.
However, comparing the value of table a with the value of table b takes too long.
I want to complete the work in 5 seconds, but I don't know how.
Below is the method I tried. Both table name columns have b-tree indexes.
1.
select
name
from
a
where
and not exists (select
name
from
b
where
a.name = b.name
);
select
a.name
from
a left outer join b
on a.name = b.name
where
b.name is null;
You want the following index on the B table:
CREATE INDEX name_idx ON b (name);
This should allow Postgres to rapidly lookup any of the 100 names in the a table against the above index. This should avoid the need to do a full table scan of the b table, which, as you are seeing, can be costly.

dynamically choose fields from different table based on existense

I have two tables A and B.
Both the tables have same number of columns.
Table A always contains all ids of Table B.
Need to fetch row from Table B first if it does not exist then have
to fetch from Table A.
I was trying to dynamically do this
select
CASE
WHEN b.id is null THEN
a.*
ELSE
b.*
END
from A a
left join B b on b.id = a.id
I think this syntax is not correct.
Can some one suggest how to proceed.
It looks like you want to select all columns from table A except when a matching ID exists in table B. In that case you want to select all columns from table B.
That can be done with this query as long as the number and types of columns in both tables are compatible:
select * from a where not exists (select 1 from b where b.id = a.id)
union all
select * from b
If the number, types, or order of columns differs you will need to explicitly specify the columns to return in each sub query.

Insert into Table using JOIN T-SQL

I want to insert into a specific column in my table A which belongs to DB 1
from my DB 2 table B
In table A I have a unique ID field called F6 same goes for table B field name F68; both fields are the same they are simply a copy of each other which gives me the opportunity to do a join on them.
So far so good, what I want now is to insert into my table A in the field F110 the values from table B F64 since I did a join on the "ID's" they should be in the right manner.
All fields are of type VARCHAR.
INSERT INTO [D061_15018659].[dbo].[A](F110)
SELECT v.F64,v.F68
FROM [VFM6010061V960P].[dbo].[B] v LEFT JOIN
ON v.F68 = F6
I have the problem that I have an error on "ON" why so ever I can't figure it out.
Your select query provide 2 columns ==> you need concatenate the columns
You need repeat the tabel A in join clause.
Try this :
INSERT INTO [D061_15018659].[dbo].[A] (F110)
SELECT
v.F64 || v.F68 as theNewF110
FROM
[VFM6010061V960P].[dbo].[B] v
LEFT JOIN
[D061_15018659].[dbo].[A] w ON v.F68 = w.F6

Map column value to table name and join

I have a composite type that looks like
CREATE TYPE member AS (
id BIGINT,
type CHAR(1)
);
I have a table that relies on this member type with an array.
CREATE TABLE relation (
id BIGINT PRIMARY KEY,
members member[]
);
I have three other tables each with a different schema (but having common id field)
CREATE TABLE table_x (
id BIGINT PRIMARY KEY,
some_text TEXT
);
CREATE TABLE table_y (
id BIGINT PRIMARY KEY,
some_int INT
);
CREATE TABLE table_z (
id BIGINT PRIMARY KEY,
some_date TIMESTAMP
);
type field in member type is just one character to find out table that specific member belongs to. A row in relation table can have a mix of different types.
I have a scenario which requires returning relation ids with at least one member fulfilling a certain condition based on it's type (let's say for x => some_text is not empty or y => some_int is greater than 10 or z => some_date is a week is from now).
I can implement this scenario on the application side by making multiple requests to the database:
unnest relation table
collect member data per relation
make new requests to find out relations
I am wondering if there is a way to map column values to table names and join them.
Assumption
I´m assuming that relation.members array does not have more than one member element of the same type. Correct?
Query to try
with unnested_members as (
-- Unnest members array
select id, unnest(members) members
from relation
)
, members_joined as (
-- left join on a per type basis with table_x, table_y and table_z.
select r.id, (r.members).id idext, (r.members).type,
x.some_text, y.some_int, z.some_date -- more types, more columns here
from unnested_members r
left join table_x x on (x.id = (r.members).id and (r.members).type = 'x')
left join table_y y on (y.id = (r.members).id and (r.members).type = 'y')
left join table_z z on (z.id = (r.members).id and (r.members).type = 'z')
-- More types, more tables to left join
)
select id,
max(some_text) some_text, -- use max() to get not null value for this id
max(some_int) some_int, -- use max() to get not null value for this id
max(some_date) some_date -- use max() to get not null value for this id
-- more types, more max() columns here
from members_joined
group by id -- get one row per relation.id with data from joined table_* columns
If you need to include more tables then you have to include these tables in the left join part, include the column in the select list and in the max() section as well.
#JNevill had a good point about this database design. Although this approach may not seem optimal, it keeps the table definitions clearly separate without any relations in between them. Also the size of relation table is fairly small compared to other three tables.
I solved the problem by simply fetching rows per type and merging them:
SELECT relation.* FROM relation, UNNEST(relation.members) member INNER JOIN table_x ON member.id = table_x.id WHERE member.type = 'x' AND table_x.some_text = 'some text value'
UNION
SELECT relation.* FROM relation, UNNEST(relation.members) member INNER JOIN table_y ON member.id = table_y.id WHERE member.type = 'y' AND table_y.some_int = 123
UNION
SELECT relation.* FROM relation, UNNEST(relation.members) member INNER JOIN table_z ON member.id = table_z.id WHERE member.type = 'z' AND table_z.some_date > '2017-01-11 00:00:00';

Merging two tables with one table having an extra attribute

I have two tables A and B that are identical. B has one extra attribute that holds boolean values. I want to insert non identical values from A into B and set the boolean attributes of all newly added A values in B to false. Here is my current work
Table A(id, first, last)
Table B(id, first, last, present*)
*present is the boolean value
INSERT INTO B
(SELECT * FROM A
WHERE not exists(
SELECT * FROM B
WHERE id=A.id AND
first=A.first AND
last=A.last)
)
This adds the values into B but leaves present as blank/null. How do I go about assigning false to all newly added values into B.
I was close!
INSERT INTO B (SELECT *,false FROM A WHERE not exists( SELECT * FROM B WHERE id=A.id AND first=A.first AND last=A.last) )
I needed to add " ,false " following the SELECT * in the beginning of the SELECT statement