'Smart' grouping in postgres - postgresql

I need somehow to group my rows by specific condition
|id | address | last_name | Count of purchases | customer_number |
|1 | de Berlin | name_1 | 1 | 11111 |
|2 | de Berlin | name_2 | 1 | 12345 |
|3 | de Berlin | name_1 | 1 | 12345 |
So the problem is that I need to group by address AND last_name BUT in this case row with ID = 2 will not be in set because it has different last_name BUT it shares the same customer_number number with row with ID = 3. Can I do it somehow with one query?
So basically I want to receive something like
select SUM(Count_of_purchases), array_agg(last_name), array_agg(customer_number)
from table
group by f(address, last_name, customer_number)
| 3 | {name_1, name_2} | {11111, 12345} |

Related

PostgreSQL - Calculate SUM() of COUNT()

Basically I have a table called cities which looks like this:
+------+-----------+---------+----------+----------------+
| id | name | lat | lng | submitted_by |
|------+-----------+---------+----------+----------------|
| 1 | Pyongyang | 39.0392 | 125.7625 | 15 |
| 2 | Oslo | 59.9139 | 10.7522 | 8 |
| 3 | Hebron | 31.5326 | 35.0998 | 8 |
| 4 | Hebron | 31.5326 | 35.0998 | 10 |
| 5 | Paris | 48.8566 | 2.3522 | 12 |
| 6 | Hebron | 31.5326 | 35.0998 | 7 |
+------+-----------+---------+----------+----------------+
Desired result:
+-----------+---------+
| name | count |
|-----------+---------|
| Hebron | 3 |
| Pyongyang | 1 |
| Oslo | 1 |
| Paris | 1 |
| Total | 6 | <-- The tricky part
+-----------+---------+
In other words, what I need to do is SELECT the SUM of the COUNT in the query I'm currently using:
SELECT name, count(name)::int FROM cities GROUP BY name;
But apparently nested aggregated functions are not allowed in PostgreSQL. I'm guessing I need to use ROLLUP in some way but I can't seem to get it right.
Thanks for the help.
You need to UNION ALL the total sum.
WITH ROLLUP works by summing up the total for every group separate and can't be used here.
CREATE TABLE cities (
"id" INTEGER,
"name" VARCHAR(9),
"lat" FLOAT,
"lng" FLOAT,
"submitted_by" INTEGER
);
INSERT INTO cities
("id", "name", "lat", "lng", "submitted_by")
VALUES
('1', 'Pyongyang', '39.0392', '125.7625', '15'),
('2', 'Oslo', '59.9139', '10.7522', '8'),
('3', 'Hebron', '31.5326', '35.0998', '8'),
('4', 'Hebron', '31.5326', '35.0998', '10'),
('5', 'Paris', '48.8566', '2.3522', '12'),
('6', 'Hebron', '31.5326', '35.0998', '7');
SELECT name, COUNT(name)::int FROM cities GROUP BY name
UNION ALL
SELECT 'Total', COUNT(*) FROM cities
name | count
:-------- | ----:
Hebron | 3
Pyongyang | 1
Oslo | 1
Paris | 1
Total | 6
db<>fiddle here

How do I join tables while putting the results in a json array?

Table name: people
+----+------+-------------+-------+
| id | name | city | state |
+----+------+-------------+-------+
| 1 | Joe | Los Angeles | CA |
+----+------+-------------+-------+
| 2 | Jill | Miami | FL |
+----+------+-------------+-------+
| 3 | Asa | Portland | OR |
+----+------+-------------+-------+
Table name: pets
+----+----------+------+
| id | pet_name | type |
+----+----------+------+
| 1 | Spike | dog |
+----+----------+------+
| 1 | Fluffy | cat |
+----+----------+------+
| 2 | Oscar | dog |
+----+----------+------+
How would I join the two tables above to include a column containing JSON of results matched in the 'pets' table (PostgreSQL)?
+----+------+------------------------------------------------------------+
| id | name | pets |
+----+------+------------------------------------------------------------+
| 1 | Joe | [{name:'Spike', type:'dog'}, {name: 'Fluffy', type:'cat'}] |
+----+------+------------------------------------------------------------+
| 2 | Jill | [{name:'Oscar', type:'dog'}] |
+----+------+------------------------------------------------------------+
| 3 | Asa | [] |
+----+------+------------------------------------------------------------+
Use json_agg() to aggregate over json-objects:
SELECT people.id
, name
, json_agg(
CASE WHEN pet_name IS NOT NULL THEN
json_build_object(
'name', pet_name
, 'type', type
)
END
)
FROM people
LEFT JOIN pets ON people.id = pets.id
GROUP BY
people.id
, name
ORDER BY
people.id;

postgreSQL - Sum hours by unique ID and more

I am trying to figure out how to SUM the time by unique ID (meaning only one per ID). Here is a markup of some of the data. I need to GROUP BY f_name, l_name and area. I also need group count (unique count of id) and group participants (just a simple count of the ids).
+----+------+-------+-------+------+--+
| ID | Time | fname | lname | Area | |
+----+------+-------+-------+------+--+
| 1 | 3:30 | Jeff | Chose | LA | |
| 1 | 3:30 | Jeff | Chose | LA | |
| 1 | 3:30 | Jeff | Chose | LA | |
| 2 | 4:00 | Jeff | Chose | LA | |
+----+------+-------+-------+------+--+
The data should look like:
+------+-------+-------+------+-------------+--------------------+
| Time | fname | lnam | Area | Group Count | Group Participants |
+------+-------+-------+------+-------------+--------------------+
| 7:30 | Jeff | Chose | LA | 2 | 4 |
| | | | | | |
+------+-------+-------+------+-------------+--------------------+
BONUS: If you can convert 3:30 to 3.5
SQL DEMO
WITH cte as (
SELECT fname, lname, Area,
COUNT(DISTINCT id) as "Group Count",
COUNT(id) as "Group Participants",
SUM(DISTINCT "time"::time) as "Time"
FROM Table1
GROUP BY fname, lname, Area, id
)
SELECT fname, lname, Area,
SUM("Group Count") as "Group Count",
SUM("Group Participants") as "Group Participants",
SUM("Time"::time) as "Time"
FROM cte
GROUP BY fname, lname, Area;
OUTPUT

postgresql condition column name = data

I have three tables.
table a
| uid | name | number |
|-----+---------+--------|
| 1 | table | 1 |
| 2 | chair | 2 |
table b
| uid | name | number |
|-----+---------+--------|
| 1 | john | 1 |
| 2 | billy | 0 |
| 3 | bob | 2 |
| 4 | sally | 1 |
table c
| uid | table a | john | billy | bob | sally |
|-----+---------+--------+--------+-------|-------|
| 1 | table | T | | | T |
| 2 | chair | | | C | |
What I need to be able to do is look at the column names in table c, find the corresponding row entry in table b and if the numbers are the same as the numbers from table a, then set the table c value to T. Otherwise set it to C. This needs to be triggered whenever either table a or table b are updated.
How can I write an update the table using if or case statement.
Thanks.

Merge multiple tables with a common column name

I am trying to merge multiple tables that have a common column name which need not have the same values across the tables. For ex,
-tmp1-
id dat
1 234
2 432
3 412
-tmp2-
id nom
1 jim
2
3 ryan
4 jack
-tmp3-
id pin
1 gi23
2 x4ed
3 yit42
8 hiu11
If above are the input, the output needs to be,
id dat nom pin
1 234 jim gi23
2 432 x4ed
3 412 ryan yit42
4 jack
8 hiu11
Thanks in advance.
postgresql 8.2.15 on greenplum from R(pass-through queries)
use FULL JOIN ... USING (id) syntax.
please see example: http://sqlfiddle.com/#!12/3aff2/1
this is how diffrent join types work (provided that tab1.row3 meets joining condition with tab2.row1, and tab1.row3 meets tab2.row2):
| tab1 | | tab2 | | JOIN | | LEFT JOIN | | RIGHT JOIN | | FULL JOIN |
-------- -------- ------------------------- ------------------------- ------------------------- -------------------------
| row1 | | tab1.row1 | | tab1.row1 |
| row2 | | tab1.row2 | | tab1.row2 |
| row3 | | row1 | | tab1.row3 | tab2.row1 | | tab1.row3 | tab2.row1 | | tab1.row3 | tab2.row1 | | tab1.row3 | tab2.row1 |
| row4 | | row2 | | tab1.row4 | tab2.row2 | | tab1.row4 | tab2.row2 | | tab1.row4 | tab2.row2 | | tab1.row4 | tab2.row2 |
| row3 | | tab2.row3 | | tab2.row3 |
| row4 | | tab2.row4 | | tab2.row4 |