Unique serial value for two distinct columns in postgres - postgresql

I have two tables:
table_A and table_B
In table_A, I have unique constraint on following columns:
col_1
col_2
This generates a unique sequence explicitly via following: (col_id which is foreign key for table_B)
FEATURESET_ID_SEQ = Sequence('featureset_id_seq')
col_id = Column(Integer, FEATURESET_ID_SEQ, primary_key=True, nullable=False, server_default=FEATURESET_ID_SEQ.next_value())
Now, I want to generate sequential id in table_B for following scenario:
whenever,
col_id generated by above explicitly unique sequence (col_1 and col_2 from table_A) let's say 100
unique value of col_3 from table_B (abcd_123) is present
I want a sequence for column id in table_B.
Basically, I want following:
col_id col_3 id
100 + abcd_123 --> 1
100 + abcd_124 --> 2
100 + abcd_125 --> 3
100 + abcd_126 --> 4
101 + abcd_127 --> 1
101 + abcd_128 --> 2
102 + abcd_129 --> 1
102 + abcd_130 --> 2
102 + abcd_131 --> 3

Related

How to find duplicates in associated fields in PostgreSQL?

I have table in postgresql that has the following values:
KEY VALNO
1 a1
2 x1
3 x2
4 a3
5 a1
6 x2
7 a4
8 a5
9 x6
4 x7
7 a6
KEY expects unique values, but there are duplicates (4,7). VALNO should have a unique KEY assigned to them, but same VALNO had used multiple KEY (a1 used both 1 & 5, x2 used both 3 & 6).
I tried the following sql to find duplicates, but could not succeed.
select KEY, VALNO from mbs m1
where (select count(*) from mbs m2
where m1.KEY = m2.KEY) > 1
order by KEY
Is there a better way to find same VALNO's have used different KEYS, and same KEY's have used different VALNO's?
ie
Duplicate VALNO
KEY VALNO
1 a1
5 a1
3 x2
6 x2
Duplicate KEY
KEY VALNO
4 x7
7 a6
For VALNO duplicate records, we can use COUNT as an analytic function:
WITH cte AS (
SELECT *, COUNT(*) OVER (PARTITION BY VALNO) cnt
FROM mbs
)
SELECT "KEY", VALNO
FROM cte
WHERE cnt > 1;
The logic for the KEY duplicate query is almost identical, except that we can use this for the count definition:
COUNT(*) OVER (PARTITION BY "KEY") cnt

Concatenate JSON rows

I have the following table with sample records:
create table jtest
(
id int,
jcol json
);
insert into jtest values(1,'{"name":"Jack","address1":"HNO 123"}');
insert into jtest values(1,'{"address2":"STREET1"}');
insert into jtest values(1,'{"address3":"UK"}');
select * from jtest;
id jcol
-------------------------------------------
1 {"name":"Jack","address":"HNO 123 UK"}
1 {"address2":"STREET1"}
1 {"address3":"UK"}
Expected result:
id jcol
--------------------------------------------------------------------------------------------
1 {"name":"Jack","address":"HNO 123 UK", "address2":"STREET1", "address3":"UK"}
Tried the following query:
select id,json_agg(jcol) as jcol
from jtest
group by id;
But getting result is unexpected:
id jcol
--------------------------------------------------------------------------------------------
1 [{"name":"Jack","address":"HNO 123 UK"}, {"address2":"STREET1"}, {"address3":"UK"}]
demo:db<>fiddle
SELECT
id,
json_object_agg(key, value) -- 2
FROM
t,
json_each(jcol) -- 1
GROUP BY id
First you have to extract all elements into one row
Afterwards you can reaggregate all of them

Getting ID1s that doesn't have occurrences on group of ID2s

Suppose I have two columns, ID1 and ID2. I want the query to return ID values where it doesn't have any occurrences of group of ID2s.
ID1 ID2
1 3
1 4
1 5
2 1
2 3
3 1
3 6
4 4
4 7
5 1
5 8
Suppose I want ID1 to return IDs which doesn't have (3,4,5) values, the result should be 3,5 here.
What should be the query in postgresql?
Thanks
You can use the following query:
SELECT ID1
FROM mytable
GROUP BY ID1
HAVING COUNT(CASE WHEN ID2 IN(3,4,5) THEN 1 END) = 0
Demo here
This will return ID1 values that are not related to even one ID2 value contained in (3,4,5).
With a table created like this:
CREATE TABLE temp
(
id1 integer,
id2 integer
);
insert into temp values(1,3);
insert into temp values(1,4);
insert into temp values(1,5);
insert into temp values(2,1);
insert into temp values(2,3);
insert into temp values(3,1);
insert into temp values(3,6);
insert into temp values(4,4);
insert into temp values(4,7);
insert into temp values(5,1);
insert into temp values(5,8);
The query for the example is just:
select distinct a.id1 from temp a where a.id1 not in (select b.id1 from temp b where b.id2 in (3,4,5) and b.id1 is not null)

Postgresql left join without duplicates

DB structure:
CREATE TABLE page
(
id serial primary key,
title VARCHAR(40) not null
);
CREATE TABLE page_rating
(
id serial primary key,
page_id INTEGER,
rating_type INTEGER,
rating INTEGER
);
CREATE TABLE user_history
(
id serial primary key,
page_id INTEGER
)
Data:
INSERT INTO page (id,title) VALUES(1,'Page #1');
INSERT INTO page (id,title) VALUES(2,'Page #2');
INSERT INTO page (id,title) VALUES(3,'Page #3');
INSERT INTO page (id,title) VALUES(4,'Page #4');
INSERT INTO page (id,title) VALUES(5,'Page #5');
INSERT INTO page_rating VALUES (1,1,60,100);
INSERT INTO page_rating VALUES (2,1,99,140);
INSERT INTO page_rating VALUES (3,1,58,120);
INSERT INTO page_rating VALUES (4,1,70,110);
INSERT INTO page_rating VALUES (5,2,60,50);
INSERT INTO page_rating VALUES (6,2,99,60);
INSERT INTO page_rating VALUES (7,2,58,90);
INSERT INTO page_rating VALUES (8,2,70,140);
Purpose - select unique values for rating_type ​​in a table "page" sorted by "rating_page.rating". And exclude table user_history from the result
My query:
SELECT DISTINCT ON(pr.rating_type) p.*,pr.rating,pr.rating_type FROM page as p
LEFT JOIN page_rating as pr ON p.id = pr.page_id
LEFT JOIN user_history uh ON uh.page_id = p.id
WHERE
pr.rating_type IN (60, 99, 58, 45, 73, 97, 55, 59, 70, 43, 74, 97, 64, 71, 46)
AND uh.page_id IS NULL
ORDER BY pr.rating_type,pr.rating DESC
Result:
ID TITLE RATING RATING_TYPE
1 "Page #1" 120 58
1 "Page #1" 100 60
2 "Page #2" 140 70
1 "Page #1" 140 99
Duplicate values ( Ideal:
ID TITLE RATING RATING_TYPE
1 "Page #1" 120 58
1 "Page #2" 50 60
Thx for help!
You almost certainly need a UNIQUE constraint on {page_id, rating_type} in the table "page_rating". You're also missing every necessary foreign key constraint. The primary key on "user_history" is suspicious, too.
Purpose - select unique values for rating_type ​​in a table "page"
sorted by "rating_page.rating".
You can select distinct values for rating_type without referring to any other tables. And you should, at first. Let's look at the data.
select page_id, rating_type, rating
from page_rating
order by page_id, rating_type;
page_id rating_type rating
--
1 58 120 *
1 60 100
1 70 110
1 99 140
2 58 90
2 60 50 *
2 70 140
2 99 60
You seem to want one row per page_id. Those rows are marked with an asterisk in the table above. How can we get those two rows?
Those rows have different values for rating_type, so we can't just use rating_type in the WHERE clause. The values in rating are neither the max nor the min for both values of rating_type, so we can't use GROUP BY with max() or min(). And we can't use GROUP BY with an aggregate function, because you want the unaggregated value of "rating" for an arbitrary value of "rating_type".
So, based on what you've told us, the only way to get the result set you want is to specify rating_type and page_id in the WHERE clause.
select page_id, rating_type, rating
from page_rating
where (page_id = 1 and rating_type = 58)
or (page_id = 2 and rating_type = 60)
order by page_id, rating_type;
page_id rating_type rating
--
1 58 120
2 60 50
I'm not going to follow through with the joins, because I'm 100% confident that you don't really want to do this.

DB2 query group by id but with max of date and max of sequence

My table is like
ID FName LName Date(mm/dd/yy) Sequence Value
101 A B 1/10/2010 1 10
101 A B 1/10/2010 2 20
101 X Y 1/2/2010 1 15
101 Z X 1/3/2010 5 10
102 A B 1/10/2010 2 10
102 X Y 1/2/2010 1 15
102 Z X 1/3/2010 5 10
I need a query that should return 2 records
101 A B 1/10/2010 2 20
102 A B 1/10/2010 2 10
that is max of date and max of sequence group by id.
Could anyone assist on this.
-----------------------
-- get me my rows...
-----------------------
select * from myTable t
-----------------------
-- limiting them...
-----------------------
inner join
----------------------------------
-- ...by joining to a subselection
----------------------------------
(select m.id, m.date, max(m.sequence) as max_seq from myTable m inner join
----------------------------------------------------
-- first group on id and date to get max-date-per-id
----------------------------------------------------
(select id, max(date) as date from myTable group by id) y
on m.id = y.id and m.date = y.date
group by id) x
on t.id = x.id
and t.sequence = x.max_seq
Would be a simple solution, which does not take account of ties, nor of rows where sequence is NULL.
EDIT: I've added an extra group to first select max-date-per-id, and then join on this to get max-sequence-per-max-date-per-id before joining to the main table to get all columns.
I have considered your table name as employee..
check the below thing helped you.
select * from employee emp1
join (select Id, max(Date) as dat, max(sequence) as seq from employee group by id) emp2
on emp1.id = emp2.id and emp1.sequence = emp2.seq and emp1.date = emp2.dat
I'm a fan of using the WITH clause in SELECT statements to organize the different steps. I find that it makes the code easier to read.
WITH max_date(max_date)
AS (
SELECT MAX(Date)
FROM my_table
),
max_seq(max_seq)
AS (
SELECT MAX(Sequence)
FROM my_table
WHERE Date = (SELECT md.max_date FROM max_date md)
)
SELECT *
FROM my_table
WHERE Date = (SELECT md.max_date FROM max_date md)
AND Sequence = (SELECT ms.max_seq FROM max_seq ms);
You should be able to optimize this further as needed.