Finding the common element between two result sets in PostgreSQL - postgresql

I have created the following tables.
CREATE TABLE table1 (
idx SERIAL PRIMARY KEY,
refs_person TEXT[],
id_gps TEXT
);
CREATE TABLE table2 (
idx SERIAL PRIMARY KEY,
id_person TEXT,
city TEXT,
location INTEGER
);
I populated them with this information.
Table 1
idx || refs_person || id_gps
1 || {id_per_234, id_per_456} || gps_20
2 || {id_per_568} || gps_23
3 || {id_per_345, id_per_334, id_per_340} || gps_45
Table 2
idx || id_person || city || location
1 || id_per_234 || Paris || 20
2 || id_per_999 || York || 20
3 || id_per_213 || Paris || 20
4 || id_per_334 || Paris || 32
If I try to find out id_person in Paris with location 20.
select id_person from table2 where city = 'Paris' and location = '20';
id_per_234
id_per_213
Then, if I try to find out refs_person with id_gps 20 for table 1
select refs_person from table1 where id_gps = '20';
{id_per_234, id_per_456}
I'm having an issue relating to finding the common element between this two results.
For the this example, I want to get id_per_234.
I have tried using intersect statement without any success.
Any ideas?

You need to unnest the array, best using a LATERAL join, before you can INTERSECT the results:
SELECT rp.rp
FROM table1
CROSS JOIN LATERAL unnest(table1.refs_person) AS rp(rp)
WHERE id_gps = 'gps_20'
INTERSECT
SELECT id_person
FROM table2
WHERE city = 'Paris' AND location = 20;
rp
------------
id_per_234
(1 row)

Related

How to properly nest select queries in postgresql? A specific (somewhat complex) example

I'd like some help with a query that I'm trying to build.
I have the following query that I'm building:
select sd.address,
sd.colour_code,
s.id as deactivated_id,
s.type,
'http://site/groups/' || c.group_id || '/user/' || c.subject_id as URL
from sensors s
join contracts c on s.contract_id=c.id
join sensordevices sd on sd.id=s.device_id
where s.begin_time is not null and
s.end_time is not null and
c.end_date is null and
not exists (select * from sensors sb
where sb.begin_time is not null and --b properly entered
sb.end_time is null and -- b active
sb.contract_id=s.contract_id and
s.type=sb.type and
s.end_time<=sb.begin_time)
;
Which generates a table like this (without the barcode column which I would like to add):
On which I would like a barcode column, but the barcode is not in the database but a derived attribute.
In order to get barcodes I was given the following query:
SELECT
ean || '' ||
(
10
-
(
(
SELECT
SUM(digit)
FROM (
SELECT
ROW_NUMBER() over () AS pos,
digit
FROM (
SELECT
REGEXP_SPLIT_TO_TABLE(
ean::TEXT,
''::TEXT
)::INT AS digit
) AS split
) AS sub
WHERE pos < LENGTH(ean::TEXT)
AND pos % 2 = LENGTH(ean::TEXT) % 2
)
+
(
SELECT
SUM(digit * 3)
FROM (
SELECT
ROW_NUMBER() over () AS pos,
digit
FROM (
SELECT
REGEXP_SPLIT_TO_TABLE(
ean::TEXT,
''::TEXT
)::INT AS digit
) AS split
) AS sub
WHERE pos < LENGTH(ean::TEXT)
AND pos % 2 = (LENGTH(ean::TEXT) - 1) % 2
)
) % 10
) % 10 as barcode
FROM
(select '0' || sd.type || '00000' || sd.address as ean
from sensors s
join sensordevices sd on s.device_id = sd.id
) as ean;
Which returns a table with a single column, barcode.
So, my question is, how can I use the second query to select the barcode for the first statement?
What I tried was the following:
On my query after select I added brc.barcode and after from (SECOND-LARGE-QUERY-HERE) brc, but I got this error: [53100] ERROR: could not write to file "base/pgsql_tmp/pgsql_tmp62390.6721": No space left on device which I assume is because it's trying to temporarily save a list of every possible barcode before executing the query. I also tried adding some constraints inside the nested query, but I got another error there.
Could someone help me with the query?
Thank you very much for your time,
Bill

At least one of the duplicate records has 'x'. Postgres sql EXISTS or INNER JOIN

I have the below postgres query that finds duplicate records in a database but I'm hoping to add in another condition so that I can say AT LEAST ONE of the duplicated records has the values of v.varfield_type_code = 's' AND v.field_content ~ 'Greendale student cards%' (from a table called sierra_view.varfield v ON p.record_id = v.record_id).
I tried an INNER JOIN and am looking into EXISTS. Does anyone have any insight? Thank you.
SELECT
p.birth_date_gmt, 'p' || rm2.record_num || 'a' AS "patron",
n.last_name || ' ' || n.first_name || ' ' || n.middle_name as name,
count(*) as cnt
FROM
sierra_view.patron_record p
JOIN sierra_view.patron_record_fullname n ON p.record_id =
n.patron_record_id
JOIN sierra_view.record_metadata rm2 on p.record_id = rm2.id
/* JOIN sierra_view.varfield v on p.record_id =v.record_id */
WHERE p.birth_date_gmt BETWEEN '01-01-2001' AND '12-31-2017'
GROUP BY 1,2, 3
HAVING COUNT(1) > 1
ORDER BY 2,1
You can put these conditions in the HAVING section:
JOIN sierra_view.varfield v on p.record_id = v.record_id
WHERE ...
GROUP BY ...
HAVING COUNT(*) > 1 AND COUNT(CASE WHEN v.varfield_type_code = 's' AND v.field_content ~ 'Greendale student cards%' THEN 1 END) > 0
So:
COUNT(*) > 1 = Only include duplicate records (you already do this)
COUNT(CASE WHEN v.varfield_type_code = 's' AND v.field_content ~ 'Greendale student cards%' THEN 1 END) > 0 = Count the grouped records based on those two conditions; if a record matches, it gets a 1, otherwise a NULL (implicit), and NULLs are not counted. So if at least one of the grouped records matches the criteria, the whole "group" will be included in the results; if not, they won't be included.
Also worth double checking whether ~ 'Greendale student cards%' is correct; ~ is for a regex check, while % is a wildcard symbol for LIKE, unless of course you do mean to search for a literal % character.

Hoe to split data of one column in multiple columns on the basis of a condition

I have one table having data
Category. New data
Cost of equipment. 23
Price of equipments. 45
Cost of M&C. 13
Price of M&C. 12
And one another table having
Category
Equipments
M&C
Now i want data as below
Category Cost Price
Equipment 23 45
M&C 13 12
Can you please help me in solving this
You may try this. A better approach is to change your table design.
Note that while joining I had to use RTRIM to remove s from equipments. I am not aware of any other variations in your data which might not match between the two tables. Please change the join conditions appropriately ( or use a REGEXP match instead of ILIKE if they don't )
SQL Fiddle
PostgreSQL 9.6 Schema Setup:
CREATE TABLE Table1
(Category varchar(19), New_data int)
;
INSERT INTO Table1
(Category, New_data)
VALUES
('Cost of equipment', 23),
('Price of equipments', 45),
('Cost of M&C', 13),
('Price of M&C', 12)
;
CREATE TABLE Table2
(Category varchar(10))
;
INSERT INTO Table2
(Category)
VALUES
('Equipments'),
('M&C')
;
Query 1:
WITH t1
AS (
SELECT b.category
,a.new_data
FROM TABLE1 a
INNER JOIN TABLE2 b ON a.Category ILIKE '%cost%' || RTRIM(b.Category, 's') || '%'
)
,t2
AS (
SELECT c.category
,a.new_data
FROM TABLE1 a
INNER JOIN TABLE2 c ON a.Category ILIKE '%price%' || RTRIM(c.Category, 's') || '%'
)
SELECT t1.category
,t1.new_data AS cost
,t2.new_data AS price
FROM t1
INNER JOIN t2 ON t1.category = t2.category
Results:
| category | cost | price |
|------------|------|-------|
| Equipments | 23 | 45 |
| M&C | 13 | 12 |

How to create a polygon using fields in PostgreSQL?

I don't have PostGIS, hence I use built-in functions.
I have got below query working correctly.
However, I need to find these values from the table
select area(circle( (polygon '(43.5042,-96.8391),(33.508,-112.1254),(33.4912,-111.9237),(33.4912,-111.9237),(33.4912,-111.9237),(38,-97)' ) ))
Below queries return error.
Any help on how to have the polygon from fields from a table?
select id, polygon '('||array_to_string(array_agg('('||latdec_src||','||longdec_src||')'),',') ||')' from access where id='99999' and time >= '2017-01-03' and time < '2017-01-04' group by 1
select id, polygon array_agg('('||latdec_src||','||longdec_src||')') from access where id='99999' and time >= '2017-01-03' and time < '2017-01-04' group by 1
select id, polygon array_agg(point(latdec_src,longdec_src)) from acesss where id='99999' and time >= '2017-01-03' and time < '2017-01-04' group by 1
You can do something similar to:
WITH points (lat, lng, sort_order) AS
(
VALUES
(43.5042, -96.8391, 1),
(33.508, -112.1254, 2),
(33.4912,-111.9237, 3),
(33.4912,-111.9237, 4),
(33.4912,-111.9237, 5),
(38, -97, 6)
)
SELECT
area(circle(polygon( string_agg(one_point, ',') ))) AS area
FROM (
SELECT
'(' || lat || ',' || lng || ')' AS one_point
FROM
points
ORDER BY
sort_order
) AS s0 ;
If I understand well your tables (whose definitions you can include in your question), that would be
SELECT
area(circle(polygon( string_agg(one_point, ',') ))) AS area
FROM (
SELECT
'(' || latdec_src || ',' || longdec_src || ')' AS one_point
FROM
access
WHERE
id ='99999' and time >= '2017-01-03' and time < '2017-01-04'
ORDER BY
time
) AS s0 ;
(I really don't know if this is going to give you an area if you just use longitude and latitude values; but that's another story.)

how t use start with -connect by nocycle in postgresql

SELECT coalesce(RPAD('IN',16,' ') || RPAD( M.CASETYPE||'/' || M.CASENUMBER || '/' || M.CASEYEAR,16, ' '),' ') as inmatter
FROM (
select level as LEV, l1.LINKCASECCIN as CCI ,l1.linkcategorycode as lcode
from hclive.LINKEDMATTERS l1
start with l1.MAINCASECCIN ='001003201400100' and l1.linkcategorycode='I'
connect by nocycle prior l1.LINKCASECCIN = l1.MAINCASECCIN and l1.linkcategorycode = 'I'
) s1,
hclive.MAIN M
where M.CCIN=CCI
connect by is done with a recursive common table expression in Postgres.
with recursive tree as (
select 1 as level, l1.linkcaseccin as cci, l1.linkcategorycode as lcode
from hclive.linkedmatters l1
where l1.maincaseccin ='001003201400100'
and l1.linkcategorycode='I'
union all
select p.level + 1, c1.linkcaseccin as cci, c1.linkcategorycode as lcode
from hclive.linkedmatters c1
join tree p on p.maincaseccin = c1.linkcaseccin
where c1.linkcategorycode='I'
)
select coalesce(rpad('IN',16,' ') || rpad( m.casetype||'/' || m.casenumber || '/' || m.caseyear,16, ' '),' ') as inmatter
from tree t
join hclive.main M on m.ccin = t.cci;
The level column does not seem to be necessary as you don't use it at all in your query, but I left in there as an example to get the same information in Postgres.