PostgreSQL: Create array by grouping values of the same id - sql

Given the following input data:
id
category
1
A
1
B
2
A
2
R
2
C
3
Z
I aim aiming to get the following output table:
id
categories
1
{"A","B"}
2
{"A","R","C"}
3
{"Z"}
using the following query:
SELECT DISTINCT id,
ARRAY(SELECT DISTINCT category::VARCHAR FROM test) AS categories
FROM my_table
But what I get is the following table:
id
categories
1
{"A","B","R","C","Z"}
2
{"A","B","R","C","Z"}
3
{"A","B","R","C","Z"}
How can I obtain the desired output?
Note: The GROUP BY clause did not work in this case as I'm not using an aggregation function.

What about using the JSON_AGG aggregation function?
SELECT id,
JSON_AGG(category) AS category
FROM tab
GROUP BY id
ORDER BY id
Check the demo here.

Assuming table has name test
select distinct id,
array(select distinct category::varchar from test b where b.id = a.id) as categories
from test a

Related

Find duplicate values only if separate column id differs

I have the following table:
id item
1 A
2 A
3 B
4 C
3 H
1 E
I'm looking to obtain duplicate values from the id column only when the item column differs in value. The end result should be:
1 A
1 E
3 B
3 H
I've attempted:
select id, items, count(*)
from table
group by id, items
HAVING count(*) > 1
But this is giving only duplicate values from the id column and not taking into account the items column.
Any suggestions will be greatly appreciated.
You can use a window function for this, this is generally far more efficient than using a self-join
SELECT
t.id,
t.items,
t.count
from (
SELECT *,
COUNT(*) OVER (PARTITION BY t.id) AS count
FROM YourTable t
) t
WHERE t.count > 1;
db<>fiddle

Sum distinct by separate ID column

I have some data of the form:
ID Value
A 2
B 2
C 3
A 2
A 2
C 3
B 2
I want to sum value by distinct IDs.
select sum(distinct value) from table would give the sum of 2 and 3 = 5. I don't want that, I want the sum of value for each ID, i.e. A=2, B=2, C=3, there's 3 distinct IDs so sum(2,2,3) = 7.
In 'sql-ish' I want something like select sum(distinct value by ID) from table. Is this possible?
Get the distinct combinations of ID and Value in a subquery and then the sum of Values:
SELECT SUM(Value) sum_value
FROM (SELECT DISTINCT ID, Value FROM tablename) t
Another way to do it is with SUM() window function:
SELECT DISTINCT SUM(MAX(Value)) OVER() sum_value
FROM tablename
GROUP BY ID
See the demo.

COUNT of GROUP of two fields in SQL Query -- Postgres

I have a table in postgres with 2 fields: they are columns of ids of users who have looked at some data, under two conditions:
viewee viewer
------ ------
93024 66994
93156 93151
93163 113671
137340 93161
92992 93161
93161 93135
93156 93024
And I want to group them by both viewee and viewer field, and count the number of occurrences, and return that count
from high to low:
id count
------ -----
93161 3
93156 2
93024 2
137340 1
66994 1
92992 1
93135 1
93151 1
93163 1
I have been running two queries, one for each column, and then combining the results in my JavaScript application code. My query for one field is...
SELECT "viewer",
COUNT("viewer")
FROM "public"."friend_currentfriend"
GROUP BY "viewer"
ORDER BY count DESC;
How would I rewrite this query to handle both fields at once?
You can combine to columns from the table into a single one by using union all then use group by as below:
select id ,count(*) Count from (
select viewee id from vv
union all
select viewer id from vv) t
group by id
order by count(*) desc
Results:
This is a good place to use a lateral join:
select v.viewx, count(*)
from t cross join lateral
(values (t.viewee), (t.viewer)) v(viewx)
group by v.viewx
order by count(*) desc;
You can try this :
SELECT a.ID,
SUM(a.Total) as Total
FROM (SELECT t.Viewee AS ID,
COUNT(t.Viewee) AS Total
FROM #Temp t
GROUP BY t.Viewee
UNION
SELECT t.Viewer AS ID,
COUNT(t.Viewer) AS Total
FROM #Temp t
GROUP BY t.Viewer
) a
GROUP BY a.ID
ORDER BY SUM(a.Total) DESC

Get Count Based on Combinations of Values from Second Column

I have a table format like below:
Id Code
1 A
1 B
2 A
3 A
3 C
4 A
4 B
I am trying to get count of code combinations like below:
Code Count
A,B 2 -- Row 1,2 and Row 6,7
A 1 -- Row 3
A,C 1 -- Row 4
I am unable to get the combination result. All I can do is group by but I am not getting count of IDs based in combinations.
You need to aggregate the rows, somehow, and do that twice. The code looks something like this:
select codes, count(*) as num_ids
from (select id, group_concat(code order by code) as codes
from t
group by id
) id
group by code;
group_concat() might be spelled listagg() or string_agg() depending on the database.
In SQL Server, use string_agg():
select codes, count(*) as num_ids
from (select id, string_agg(code, ',') within group (order by code) as codes
from t
group by id
) id
group by code;

SQL query exclude rows if having two different values

Basically my select statement returns below:
ID Status
100 1
100 2
101 1
What i'm looking for is to return if a ID having status as 1 and if the same ID has another status ID as 2 then exclude both
In Short results as below:
ID Status
101 1
Thanks in advance !
The following query returns ID values that occur only once.
SELECT ID
FROM t
GROUP BY ID
HAVING COUNT(*) = 1
It should be sufficient for the sample data you provided. If there are other cases then let me know.
SQL Fiddle
You gonna need subquery and NOT IN here.
The following would work if you have column status as INT datatype
SELECT *
FROM table
WHERE status = 1
AND ID NOT IN (
SELECT ID
FROM table
WHERE status = 2
);
Making a generic query, which will remove all duplicated rows, not only for a particular ID :
select ID
from table where ID NOT IN
(select ID from table GROUP BY ID HAVING count(Status) > 1)
/* Subquery will fetch ID's having multiple entries*/
SQL Fiddle
The CTE 'IDs' retrieves all IDs which have single record in DB. This is then joined to original table to return the result as a pair (ID, Status)
;with IDs as
(
select ID
from yourtable
group by ID
having count(*) = 1
)
select i.ID, y.Status
from yourtable y
inner join IDs i on y.ID = i.ID
order by i.ID