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
Related
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
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} |
I have these records returned from a query
+---------+--------------+-----------+----------+
| Country | other fields | sales | date |
+---------+--------------+-----------+----------+
| US | 1 | $100.00 | 01/01/21 |
| CA | 1 | $100.00 | 01/01/21 |
| UK | 1 | $100.00 | 01/01/21 |
| FR | 1 | $100.00 | 01/01/21 |
| US | 1 | $200.00 | 01/02/21 |
| CA | 1 | $200.00 | 01/02/21 |
| UK | 1 | $200.00 | 01/02/21 |
| FR | 1 | $200.00 | 01/02/21 |
And I want to show the sales variation from one month to previous, like this:
| Country | 01/02/21 | 01/01/21 | Var% |
| US | $200.00 | $100.00 | 100% |
| CA | $200.00 | $100.00 | 100% |
| FR | $200.00 | $100.00 | 100% |
+---------+--------------+-----------+----------+
How could be done with a Postgres query?
if you always comparing two month only :
select country
, sum(sales) filter (where date ='01/01/21') month1
, sum(sales) filter (where date ='01/02/21') month2
, ((sum(sales) filter (where date ='01/02/21') /sum(sales) filter (where date ='01/01/21')) - 1) * 100 var
from tablename
where date in ('01/01/21' , '01/02/21')
group by country
you also can look at crosstab from tablefunc extension which basically does the same as above query.
CREATE EXTENSION IF NOT EXISTS tablefunc;
select * ,("01/02/21" /"01/01/21") - 1) * 100 var
from(
select * from crosstab ('select Country,date , sales from tablename')
as ct(country varchar(2),"01/01/21" money , "01/02/21" money)
) t
for more info about crosstab , see tablefunc
but if you want to show date in rows instead of columns, you can easily generalize it for all the dates :
select *
, ((sales / LAG(sales,1,1) over (partition by country order by date)) -1)* 100 var
from
country
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;
I've got some records on my database that have a 'createdAt' timestamp.
What I'm trying to get out of postgresql is those records grouped by 'createdAt'
So far I've got this query:
SELECT date_trunc('day', "updatedAt") FROM goal GROUP BY 1
Which gives me:
+---+------------+-------------+
| date_trunc |
+---+------------+-------------+
| Sep 20 00:00:00 |
+---+------------+-------------+
Which are the days where the records got created.
My question is: Is there any way to generate something like:
| Sep 20 00:00:00 |
| id | name | gender | state | age |
|----|-------------|--------|-------|-----|
| 1 | John Kenedy | male | NY | 32 |
| |
| Sep 24 00:00:00 |
| |
| id | name | gender | state | age |
|----|-------------|--------|-------|-----|
| 1 | John Kenedy | male | NY | 32 |
| 2 | John De | male | NY | 32 |
That means group by date_trunc and select all the columns of those rows?
Thanks a lot!
Please try SELECT date_trunc('day', "updatedAt"), name, gender, state, age FROM goal GROUP BY 1,2,3. It will not provide as the structure, you expect, but will "group by date_trunc and select all the columns ".