'How to get values to dense table with columns of categories using PostgreSQL (crosstab)?
I have this toy example which gives me sparse table of values separated in their different categories. I would want to have dense matrix, where all columns are individually ordered.
drop table if exists temp_table;
create temp table temp_table(
rowid int
, category text
, score int
);
insert into temp_table values (0, 'cat1', 10);
insert into temp_table values (1, 'cat2', 21);
insert into temp_table values (2, 'cat3', 32);
insert into temp_table values (3, 'cat2', 23);
insert into temp_table values (4, 'cat2', 24);
insert into temp_table values (5, 'cat3', 35);
insert into temp_table values (6, 'cat1', 16);
insert into temp_table values (7, 'cat1', 17);
insert into temp_table values (8, 'cat2', 28);
insert into temp_table values (9, 'cat2', 29);
Which gives this temporary table:
| rowid | category | score |
|---|---|---|
| 0 | cat1 | 10 |
| 1 | cat2 | 21 |
| 2 | cat3 | 32 |
| 3 | cat2 | 23 |
| 4 | cat2 | 24 |
| 5 | cat3 | 35 |
| 6 | cat1 | 16 |
| 7 | cat1 | 17 |
| 8 | cat2 | 28 |
| 9 | cat2 | 29 |
Then ordering score values to different columns based on their category:
select "cat1", "cat2", "cat3"
from crosstab(
$$ select rowid, category, score from temp_table $$ -- as source_sql
, $$ select distinct category from temp_table order by category $$ -- as category_sql
) as (rowid int, "cat1" int, "cat2" int, "cat3" int)
That outputs:
| cat1 | cat2 | cat3 |
|---|---|---|
| 10 | ||
| 21 | ||
| 32 | ||
| 23 | ||
| 24 | ||
| 35 | ||
| 16 | ||
| 17 | ||
| 28 | ||
| 29 |
But I would want the result of the query to be dense, like:
| cat1 | cat2 | cat3 |
|---|---|---|
| 10 | 21 | 32 |
| 16 | 23 | 35 |
| 17 | 24 | |
| 28 | ||
| 29 |
Maybe PostgreSQL's crosstab is not even right tool to do this, but that comes to my mind first as it produces that sparse table close to the result I would need.
Solution 1:[1]
with cte as (
select category, score, row_number() over (
partition by category order by score
) as r
from temp_table
)
select
sum(score) filter (where category = 'cat1') as cat1,
sum(score) filter (where category = 'cat2') as cat2,
sum(score) filter (where category = 'cat3') as cat3
from cte
group by r
order by r
;
If the number of columns is known and it is reasonably small, FILTER might be a better option than CROSSTAB, which requires an extension.
Solution 2:[2]
You can use this API call - https://developers.docusign.com/docs/esign-rest-api/reference/envelopes/envelopecustomfields/create/
So, you may need 3 API calls:
- Create envelope in "draft" status.
- Add custom fields.
- Send it.
There may be a way to do this with fewer API calls, but I don't know how.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Vesa Karjalainen |
| Solution 2 | Inbar Gazit |
