Matching tables on unordered sets (arrays) with optional subsets - arrays

I'm trying to match observations in two tables based on a set of characteristics.
Table1:
id1;set1
A;{1,2,3,4}
B;{6,9,4,5}
Table2:
id2;set2
F;{1,2,3,4}
G;{7,6,2,4}
H;{6,{1,9},4,5}
In theory sets are unordered and every element of the sets in table 1 should match an element in table 2, however, when the element is a subset, the element in table 1 should belong to the subset in table 2.
Result should be:
MATCH_TABLE:
id1;id2
A;F
B;H
"A" in table 1 matches "F" in table 2, trivially.
Match "B","H" is more complex. The second element of set1, "1" belongs to "{1,9}", the subset in "H", and that is way the all match.
How should I model this data in Postgresql and perform this match?
PS: Ignoring the case H, of sets with subsets, I had created set1 and set2 as arrays, ordered them, and INNER JOINed the tables on the array fields.

Install intarray extension in which you can find type query_int ideally fitted to your need.
create extension if not exists intarray;
create table table1 (id1 text, set1 int[]);
insert into table1 values
('A', '{1,2,3,4}'),
('B', '{6,9,4,5}');
create table table2 (id2 text, set2 query_int);
insert into table2 values
('F', '1 & 2 & 3 & 4'),
('G', '7 & 6 & 2 & 4'),
('H', '6 & (1 | 9) & 4 & 5');
select id1, id2
from table1
join table2
on set1 ## set2
id1 | id2
-----+-----
A | F
B | H
(2 rows)

Related

Postgresql | remove all arrays that contains by others

Let's for example I have the next table:
CREATE TABLE temp
(
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
arr bigint[] NOT NULL
);
And insert rows it:
INSERT INTO temp (arr) VALUES
(ARRAY[2, 3]),
(ARRAY[2,3,4]),
(ARRAY[4]),
(ARRAY[1, 2, 3])
So, I have now in the table:
I want to have a query that return only arrays which are unique (in a manner that are not contains by other arrays)
So, the return will be rows number 2 & 4 (the arr column)
This can be don using a NOT EXISTS condition:
select t1.*
from temp t1
where not exists (select *
from temp t2
where t1.id <> t2.id
and t2.arr #> t1.arr);

Postgres how to use ANY instead of IN

I have a query but it is not working correctly,
Select *
from "Firms"
Where "Properties" IN ('{1,2}')
That's my postgres query,
"Properties" column is int array.
Only those containing these two values ​​are coming, but I want to fetch records containing any of the values, and I want to list by number of matching values ​​if possible.
Test case:
create table array_any(id integer, array_fld int[]);
insert into array_any values (1, ARRAY[1,2]), (2, ARRAY[2,3]), (3, ARRAY[3,4]);
select id, count(*) from array_any,
lateral unnest(array_fld) as s where s = ANY(ARRAY[1,2]) group by id order by id;
id | count
----+-------
1 | 2
2 | 1

How to update table based on a json map?

If I have this table
CREATE TABLE tmp (
a integer,
b integer,
c text
);
INSERT INTO tmp (a, b, c) VALUES (1, 2, 'foo');
And this json:
{
"a": 4,
"c": "bar"
}
Where the keys map to the column names, and the values are the new values.
How can I update the tmp table without touching columns that aren't in the map?
I thought about constructing a dynamic string of SQL update statement that can be executed in pl/pgsql, but it seems the number of arguments that get passed to USING must be predetermined. But the actual number of arguments is determined by the number of keys in the map, which is dynamic, so this seems like a dead end.
I know I can update the table using multiple update statements as I loop over the keys, but the problem is that I have a trigger set up for the table that will revision the table (by inserting changed columns into another table), so the columns must be updated in a single update statement.
I wonder if it's possible to dynamically update a table with a json map?
Use coalesce(). Example table:
drop table if exists my_table;
create table my_table(id int primary key, a int, b text, c date);
insert into my_table values (1, 1, 'old text', '2017-01-01');
and query:
with jsondata(jdata) as (
values ('{"id": 1, "b": "new text"}'::jsonb)
)
update my_table set
a = coalesce((jdata->>'a')::int, a),
b = coalesce((jdata->>'b')::text, b),
c = coalesce((jdata->>'c')::date, c)
from jsondata
where id = (jdata->>'id')::int;
select * from my_table;
id | a | b | c
----+---+----------+------------
1 | 1 | new text | 2017-01-01
(1 row)

Lookup delimited values in a table in sql-server

In a table A i have a column (varchar*30) city-id with the value e.g. 1,2,3 or 2,4.
The description of the value is stored in another table B, e.g.
1 Amsterdam
2 The Hague
3 Maastricht
4 Rotterdam
How must i join table A with table B to get the descriptions in one or maybe more rows?
Assuming this is what you meant:
Table A:
id
-------
1
2
3
Table B:
id | Place
-----------
1 | Amsterdam
2 | The Hague
3 | Maastricht
4 | Rotterdam
Keep id column in both tables as auto increment, and PK.
Then just do a simple inner join.
select * from A inner join B on (A.id = B.id);
Ideal way to deal with such scenarios is to have a normalized table as Collin. In case that can't be done here is the way to go about -
You would need to use a table-valued function to split the comma-seperated value. If you are having SQL-Server 2016, there is a built-in SPLIT_STRING function, if not you would need to create one as shown in this link.
create table dbo.sCity(
CityId varchar(30)
);
create table dbo.sCityDescription(
CityId int
,CityDescription varchar(30)
);
insert into dbo.sCity values
('1,2,3')
,('2,4');
insert into dbo.sCityDescription values
(1,'Amsterdam')
,(2,'The Hague')
,(3,'Maastricht')
,(4,'Rotterdam');
select ctds.CityDescription
,sst.Value as 'CityId'
from dbo.sCity ct
cross apply dbo.SplitString(CityId,',') sst
join dbo.sCityDescription ctds
on sst.Value = ctds.CityId;

Inserting array values

How do I write and execute a query which inserts array values using libpqxx?
INSERT INTO exampleTable(exampleArray[3]) VALUES('{1, 2, 3}');
This example code gives me:
ERROR: syntax error at or near "'"
What is wrong? In PostgreSQL documentation I found that:
CREATE TABLE sal_emp (
name text,
pay_by_quarter integer[],
schedule text[][]
);
...
INSERT INTO sal_emp
VALUES ('Bill',
'{10000, 10000, 10000, 10000}',
'{{"meeting", "lunch"}, {"training", "presentation"}}');
You should use a column name without an index to insert an array:
create table example(arr smallint[]);
insert into example(arr) values('{1, 2, 3}');
-- alternative syntax
-- insert into example(arr) values(array[1, 2, 3]);
select * from example;
arr
---------
{1,2,3}
(1 row)
Use the column name with an index to access a single element of the array:
select arr[2] as "arr[2]"
from example;
arr[2]
--------
2
(1 row)
update example set arr[2] = 10;
select * from example;
arr
----------
{1,10,3}
(1 row)
You can use arr[n] in INSERT but this has special meaning. With this syntax you can create an array with one element indexed from the given number:
delete from example;
insert into example(arr[3]) values (1);
select * from example;
arr
-----------
[3:3]={1}
(1 row)
As a result you have an array which lower bound is 3:
select arr[3] from example;
arr
-----
1
(1 row)
ref: https://ubiq.co/database-blog/how-to-insert-into-array-in-postgresql/
A. use ARRAY
insert into employees (id, name, phone_numbers)
values (1, ' John Doe', ARRAY ['9998765432','9991234567']);
// less nested quotes
B. use '{}'
insert into employees (id, name, phone_numbers)
values (2, ' Jim Doe', '{"9996587432","9891334567"}');
OR
insert into employees (id, name, phone_numbers)
values (2, ' Jim Doe', '{9996587432,9891334567}');
// seems inner quotes " not necessary,
// number or string depends on column type.

Resources