Cross tab function in Postgres for a complex sql statement - postgresql

I'm having the following select:
SELECT t.groupid,
yk.short_name AS kind,
yg.short_name,
COALESCE(p.price, 0::numeric) AS price,
p.changed_by_username,
p.changed_date,
p.market_id
FROM prices p
RIGHT JOIN ( SELECT pos.supply_item_output_group_id AS groupid,
pos.credit_item_output_kind_id AS kindid
FROM optimization_standards pos
UNION
SELECT pos2.output_group_id,
pos2.output_kind_id
FROM optimization_standards pos2) t ON p.output_kind_id = t.kindid AND p.output_group_id = t.groupid
JOIN output_kinds yk ON yk.output_kind_id = p.output_kind_id
JOIN output_group yg ON yg.output_group_id = p.output_group_id
GROUP BY t.groupid, yk.short_name, yg.short_name, p.price, p.changed_by_username, p.changed_date, p.market_id
ORDER BY t.groupid;
that produces the following result:
groupid
kind
short_name
price
changed_by_username
changed_date
market_id
1001
Prime
shrt_1001
1.3777
1
1001
Prime
shrt_1001
1.3777
2
1001
Filata
shrt_1001
2.3123
1
1001
Filata
shrt_1001
2.3123
2
And I want to use crosstab function in order to produce a result like the following:
groupid kind short_name
price_market_us
changed_by_username_us
changed_date_us
price_market_eu
changed_by_username_eu
changed_date_eu
1001 - Prime - shrt_1001
1.3777
1.3777
1001 - Filata -shrt_1001
2.3123
2.3123
Basically I want to group the data based on markets and create the pivot table by joining data from the markets.
Will it be possible taking into consideration that I don't have a surogate key just a composite key (groupid and kindid). Should I transform the price table into a new one that has the information needed based on merging rows based in market. How the merge could be done? Should I create a view instead of using crosstab.
I new to cross_tab function and my use case seems a little complex for cross_tab.
Thank you in advance for your help,

Related

Postgres 13 join from another table on JSONB array of String

I have a table with JSONB column. In this column we store identifiers of another table as json array of strings. How can I join the tables
Table Customer:
CustomerID
Name
Campaigns (JSONB)
1
John
[ "rxuatoak", "vsnxcvdsl", "jkiasokd" ]
2
Mick
[ "jdywmsks", "nxbsvwios", "jkiasokd" ]
Table Campaign:
CampaignID
Identifier
CampaignName
1
rxuatoak
Alpha
2
vsnxcvdsl
Bravo
3
jkiasokd
Charlie
4
jdywmsks
Delta
5
nxbsvwios
Echo
Result something like:
CustomerID
Name
CampaignNames
1
John
Alpha, Bravo, Charlie
2
Mick
Delta, Echo, Charlie
I tried many ways, and could only find online help with json objects inside the jsonb column. My jsonb column has simple array of strings.
Using POSTGRES 13
You can apply a JOIN operation between the two tables on condition that an identifier is found within a campaign (using ? operator). Then apply aggregation with STRING_AGG, with respect to the "CustomerID" and "Name"
SELECT customer.CustomerID,
customer.Name_,
STRING_AGG(campaign.CampaignName, ',') AS CampaignNames
FROM customer
INNER JOIN campaign
ON customer.Campaigns ? campaign.Identifier
GROUP BY customer.CustomerID,
customer.Name_
Check the demo here.

Calculating correlation coefficient using PostgreSQL with data from same table?

I would like to expand existing question.
I have 3 tables:
Rivers' names and id - Let's name it river
Rivers' id and Hydrols' ids - Let's name it id
Hydrols' ids, volume and date - Let's name it data
I know how to select data from this 3 tables:
SELECT DISTINCT river.name, AVG(data.volume)
FROM data
INNER JOIN id
ON id.id_hydrol = data.id_hydrol
INNER JOIN river
ON river.id_river = id.id_river
AND river.name = 'NAME_1'
GROUP BY river.name
ORDER BY AVG(data.volume) DESC
What do i have to write instead of ? mark ?
How can i compare volume of 2 rivers with different names and date has to be the same?
How i put 2 different requests in corr() function?

Postgres query for report

I'm trying to solve this problem:
I have a query/view that will join ~10 tables to extract some fields for a report (if any). The query doesn't use any grouping function, only joins and cut off some unuseful data.
I have to take this one big view, get the group for the first index, take the max of a date in the second column and take all the information from other fields referring the record of the max value.
I cannot be able to to this in postgres.
As a pseudo code I can give this:
select 1
, max(2)
, 3 referred to the record from max(2)
, 4 referred to the record from max(2)
, ...
, 20 referred to the record from max(2)
from (ViewWithAllJoins) a
group by 1
For privacy and business problem I had to obfuscate some informations, 1/2/3/4... are the name of the column from the view "ViewWithAllJoins", I hope that the problem is still understandable and resolvable!
I've tryied with WINDOW command as reported in Convert keep dense_rank from Oracle query into postgres but I cannot be able to use the group by that I need. Other tryes that I've done was about the dense_rank like shown in Dense_rank first Oracle to Postgresql convert but I can't do any assumption on the order of the data in any of the other fields in exception of 1 and 2, so I can't use any of the aggregate function on them.
Any ideas? Possibly without adding too much subqueryes.
Thank you!
EDIT:
As suggested I'll add some synthetic data to better understand the problem and what I want.
Start:
ID DATE COLUMN1 COLUMN2 COLUMN3
=====================================================================
88888888;"2016-04-02 09:00:00";"aaaaaaaaaaa";"TEXT89" ; 999999999
88888888;"2018-08-21 09:00:00";"a" ;"TEXT1" ; 988888888
88888888;"2017-11-09 09:00:00";"zzzz" ;"TEXT80000" ; 850580582
75858585;"2017-01-31 09:00:00";"~~~~~~~~~~~";"TEXT10" ; 101010101
75858585;"2018-04-02 09:00:00";"eeeeeeeeeee";"TEXT1000" ; 111111111
99999999;"2016-04-02 09:00:00";"8d2ecafd866";"TEXT808911"; 777777777
What I want:
ID DATE COLUMN1 COLUMN2 COLUMN3
===================================================================
88888888;"2018-08-21 09:00:00";"a" ;"TEXT1" ; 988888888
75858585;"2018-04-02 09:00:00";"eeeeeeeeeee";"TEXT1000" ; 111111111
99999999;"2016-04-02 09:00:00";"8d2ecafd866";"TEXT808911"; 777777777
So the group by id, the max of the date and the other fields related to the row of the max date.
-- So you have duplicate records per ID, and for every ID you want to select the record with the most recent date ?
Use NOT EXISTS:
SELECT id,zdate,column1,column2,column3 -- , ...
FROM queryview t
WHERE NOT EXISTS (
SELECT *
FROM queryview x
WHERE x.id=t.id
AND x.zdate > t.zdate
);
Or, use row_number() over a window, and pick only the row with the final date:
SELECT id,zdate,column1,column2,column3 -- , ...
FROM ( SELECT *
, row_number() OVER(PARTITION BY id, ORDER BY zdate DESC) AS rn
FROM queryview
) q
WHERE q.rn = 1
;

Can I calculate the sum of a calculated field in the same query?

I need to tally the total number of characters entered by students for all posts in a given Moodle course (as well as the total number of posts per student). I started simple with a query that looks at just one student and one course at a time, and produces a new column with the character_length of the forum message. It works fine, but I have to tally the column manually and I'm only working with one student and course at a time. My query:
SELECT character_length(mdl_forum_posts.message) AS CHARS
FROM mdl_forum_posts, mdl_forum_discussions
WHERE mdl_forum_posts.userid = 1120
AND mdl_forum_posts.discussion = mdl_forum_discussions.id
AND mdl_forum_discussions.course = 181
Can I:
a) tally the CHARS column and just get the total for all posts in a single query
or
b) (even better) do this for a list of student/course combinations in one query?
Any information greatly appreciated. This table is postgres, though ultimately I have to generate this code in a query-builder that will work for other RDBMSs as well.
SELECT character_length(string_agg(mdl_forum_posts.message)) AS CHARS
FROM mdl_forum_posts, mdl_forum_discussions
WHERE mdl_forum_posts.userid = 1120
AND mdl_forum_posts.discussion = mdl_forum_discussions.id
AND mdl_forum_discussions.course = 181
GROUP BY mdl_forum_posts.message;
SELECT p.userid
,d.course
,SUM(character_length(p.message)) AS char_total
,COUNT(p.message) AS post_count
FROM mdl_forum_posts p
JOIN mdl_forum_discussions d ON (d.id = p.discussion)
GROUP BY p.userid, d.course
ORDER BY p.userid, d.course
;
select
d.id, p.user_id,
count(*) as total_posts,
sum(character_length(p.message)) as chars
from
mdl_forum_posts p
inner join
mdl_forum_discussions d on p.discussion = d.id
group by rollup (d.id, p.user_id)

how to get grouped query data from the resultset?

I want to get grouped data from a table in sqlite. For example, the table is like below:
Name Group Price
a 1 10
b 1 9
c 1 10
d 2 11
e 2 10
f 3 12
g 3 10
h 1 11
Now I want get all data grouped by the Group column, each group in one array, namely
array1 = {{a,1,10},{b,1,9},{c,1,10},{h,1,11}};
array2 = {{d,2,11},{e,2,10}};
array3 = {{f,3,12},{g,3,10}}.
Because i need these 2 dimension arrays to populate the grouped table view. the sql statement maybe NSString *sql = #"SELECT * FROM table GROUP BY Group"; But I wonder how to get the data from the resultset. I am using the FMDB.
Any help is appreciated.
Get the data from sql with a normal SELECT statement, ordered by group and name:
SELECT * FROM table ORDER BY group, name;
Then in code, build your arrays, switching to fill the next array when the group id changes.
Let me clear about GroupBy. You can group data but that time its require group function on other columns.
e.g. Table has list of students in which there are gender group mean Male & Female group so we can group this table by Gender which will return two set . Now we need to perform some operation on result column.
e.g. Maximum marks or Average marks of each group
In your case you want to group but what kind of operation you require on price column ?.
e.g. below query will return group with max price.
SELECT Group,MAX(Price) AS MaxPriceByEachGroup FROM TABLE GROUP BY(group)