How to combine max and count in one query - postgresql

I have a simple question about 'max' and 'count' functions.
I read some posts already but they don't satisfy me or i cannot understand them well enough to use them
I tried to refer to this
Here is my query:
select wojewodztwo, count(*) as liczba from wojewodztwa
inner join powiaty on wojewodztwa.klwoj = powiaty.klwoj
inner join gminy on powiaty.klpow = gminy.klpow
inner join miejscowosci on gminy.klgm = miejscowosci.klgm
where miejscowosc = 'Nowy Dwór'
group by wojewodztwo order by count(*) desc
And the result of this query looks like this
Now i want to get only max value rows as the answer. I don't want to use Limit 2 I thought of doing something like max(count) but it seems that aggregate functions cannot be stacked on one of eachother

Using a windowed function and a CTE will be quicker and more elegant:
WITH
T AS
(
SELECT wojewodztwo, COUNT(*) as liczba, MAX(COUNT(*)) OVER() AS MAX_liczba
FROM wojewodztwa
INNER JOIN powiaty
ON wojewodztwa.klwoj = powiaty.klwoj
INNER JOIN gminy
ON powiaty.klpow = gminy.klpow
INNER JOIN miejscowosci
ON gminy.klgm = miejscowosci.klgm
WHERE miejscowosc = 'Nowy Dwór'
GROUP BY wojewodztwo
)
SELECT wojewodztwo, liczba
FROM T
WHERE liczba = MAX_liczba;

It sounds like you want to put FETCH FIRST 1 ROW WITH TIES at the end of your query. This WITH TIES feature was introduced in v13.
Before that, I think you would need to wrap another query using window functions around your existing query (or do it on the client side). To use the window function, you would actually have to wrap it in two layers of select, as you can't use window functions in a where clause, so you need to define it on one level and use it on the outer level.
So it would look something like this:
select wojewodztwo, liczba from (
select wojewodztwo, liczba, max(liczba) over () as _max from (
select wojewodztwo, count(*) as liczba from wojewodztwa
inner join powiaty on wojewodztwa.klwoj = powiaty.klwoj
inner join gminy on powiaty.klpow = gminy.klpow
inner join miejscowosci on gminy.klgm = miejscowosci.klgm
where miejscowosc = 'Nowy Dwór'
group by wojewodztwo
) f
) ff where _max=liczba

Related

Selecting single rows that have max value for each unique name in different column

I need to find a unique set of province, district (accordingly 'wojewodztwo', 'powiat')
for max value in column called 'liczba'
So basically i need to find district with the biggest value for each unique province
My data base looks like this
And I used this command
select
wojewodztwo,
powiat,
count(typmsc) as liczba
from
wojewodztwa
inner join powiaty
on wojewodztwa.klwoj = powiaty.klwoj
inner join gminy
on powiaty.klpow = gminy.klpow
inner join miejscowosci
on gminy.klgm = miejscowosci.klgm
inner join typymsc
on miejscowosci.kltm = typymsc.kltm
where
typmsc = 'miasto'
group by
wojewodztwo,
powiat
To obtain table that looks like this
I tried to obtain the result by using this query above and making it a temporary (temp) table so i can work on it that way but i couldn't come up with a solution
I want my result to look something like this
The result should have 16 rows of each unique province name (thats how many provinces my country have)
I managed to do it
I used this query
select distinct on(wojewodztwo) wojewodztwo, powiat, liczba from(
select wojewodztwo, powiat, count(typmsc) as liczba from wojewodztwa
inner join powiaty on wojewodztwa.klwoj = powiaty.klwoj
inner join gminy on powiaty.klpow = gminy.klpow
inner join miejscowosci on gminy.klgm = miejscowosci.klgm
inner join typymsc on miejscowosci.kltm = typymsc.kltm
where typmsc = 'miasto'
group by wojewodztwo,powiat
) as temp
order by wojewodztwo,liczba desc
And here is the output i got

Strange Behaviour on Postgresql query

We created a view in Postgres and I am getting strange result.
View Name: event_puchase_product_overview
When I try to get records with *, I get the correct result. but when I try to get specific fields, I get wrong values.
I hope the screens attached here can explain the problem well.
select *
from event_purchase_product_overview
where id = 15065;
select id, departure_id
from event_puchase_product_overview
where id = 15065;
VIEW definition:
CREATE OR REPLACE VIEW public.event_puchase_product_overview AS
SELECT row_number() OVER () AS id,
e.id AS departure_id,
e.type AS event_type,
e.name,
p.id AS product_id,
pc.name AS product_type,
product_date.attribute AS option,
p.upcomming_date AS supply_date,
pr.date_end AS bid_deadline,
CASE
WHEN (pt.categ_id IN ( SELECT unnest(tt.category_ids) AS unnest
FROM ( SELECT string_to_array(btrim(ir_config_parameter.value, '[]'::text), ', '::text)::integer[] AS category_ids
FROM ir_config_parameter
WHERE ir_config_parameter.key::text = 'trip_product_flight.product_category_hotel'::text) tt)) THEN e.maximum_rooms
WHEN (pt.categ_id IN ( SELECT unnest(tt.category_ids) AS unnest
FROM ( SELECT string_to_array(btrim(ir_config_parameter.value, '[]'::text), ', '::text)::integer[] AS category_ids
FROM ir_config_parameter
WHERE ir_config_parameter.key::text = 'trip_product_flight.product_category_flight'::text) tt)) THEN e.maximum_seats
WHEN (pt.categ_id IN ( SELECT unnest(tt.category_ids) AS unnest
FROM ( SELECT string_to_array(btrim(ir_config_parameter.value, '[]'::text), ', '::text)::integer[] AS category_ids
FROM ir_config_parameter
WHERE ir_config_parameter.key::text = 'trip_product_flight.product_category_bike'::text) tt)) THEN e.maximum_bikes
ELSE e.maximum_seats
END AS departure_qty,
CASE
WHEN now()::date > pr.date_end AND po.state::text = 'draft'::text THEN true
ELSE false
END AS is_deadline,
pl.product_qty::integer AS purchased_qty,
pl.comments,
pl.price_unit AS unit_price,
rp.id AS supplier,
po.id AS po_ref,
po.state AS po_state,
po.date_order AS po_date,
po.user_id AS operator,
pl.po_state_line AS line_status
FROM event_event e
LEFT JOIN product_product p ON p.related_departure = e.id
LEFT JOIN product_template pt ON pt.id = p.product_tmpl_id
LEFT JOIN product_category pc ON pc.id = pt.categ_id
LEFT JOIN purchase_order_line pl ON pl.product_id = p.id
LEFT JOIN purchase_order po ON po.id = pl.order_id
LEFT JOIN purchase_order_purchase_requisition_rel prr ON prr.purchase_order_id = po.id
LEFT JOIN purchase_requisition pr ON pr.id = prr.purchase_requisition_id
LEFT JOIN res_partner rp ON rp.id = po.partner_id
LEFT JOIN ( SELECT p_1.id AS product_id,
pav.name AS attribute
FROM product_product p_1
LEFT JOIN product_attribute_value_product_product_rel pa ON pa.prod_id = p_1.id
LEFT JOIN product_attribute_value pav ON pav.id = pa.att_id
LEFT JOIN product_attribute pat ON pat.id = pav.attribute_id
WHERE pat.name::text <> ALL (ARRAY['Date'::character varying, 'Departure'::character varying]::text[])) product_date ON product_date.product_id = p.id
WHERE (p.id IN ( SELECT DISTINCT mrp_bom_line.product_id
FROM mrp_bom_line)) AND p.active
ORDER BY e.id, pt.categ_id, p.id;
If I add new event_event or new product_product I'll get a new definition of row_number in my view, then the column ID of my view is not stable.
at least you can't use row_number as Id of the view,
If you insist to use row_number, you can use the Order By "creation DATE" by this way all new records will be as last lines in the view and this will not change the correspondency between ID (row_number) and other columns.
Hope that helps !
Very likely the execution plan of your query depends on the columns you select. Compare the execution plans!
Your id is generated using the row_number window function. Now window functions are executed before the ORDER BY clause, so the order will depend on the execution plan and hence on the columns you select.
Using row_number without an explicit ordering doesn't make any sense.
To fix that, don't use
row_number() OVER ()
but
row_number() OVER (ORDER BY e.id, pt.categ_id, p.id)
so that you have a reliable ordering.
In addition, you should omit the ORDER BY clause at the end.

How to do outer join with inline view (select in from clause) in Postgresql

I have a query similar to this simplified example:
select u.id, sq.score
from usr as u,
(select user_id, score FROM score WHERE bar = ?) as sq
where u.id = sq.user_id
I would like the join (u.id = sq.user_id) to be an outer join. I can't figure out how to use JOIN in the from clause with a 'select' like this.
I know I could do this example without having to use a select in the from clause but thats not what I need in my application.
Something like this:
select u.id, sq.score
from usr as u
left join ( -- or right/full join as per your needs
select user_id, score FROM score WHERE bar = ?
) as sq
on u.id = sq.user_id

Get maximum value of an aggregate function

I want to only return the row where the count(object) is the highest, so I have written this query
select klantnr, count(objectnaam)
from klanten inner join deelnames using(klantnr)
inner join reizen using(reisnr)
inner join bezoeken using(reisnr)
where objectnaam = 'Maan'
group by klantnr
Now, I can't do
select max(count(objectnaam))
How would I go about solving this problem?
I have tried by using a subquery which is equally invalid
select max(select count(objectnaam) from ....)
I think I need a subquery in the from, so I have rewritten the query like this which I think is closer to the actual answer but still not right, as now it returns the maximum value of all rows.
select klantnr, max(c)
FROM(
select klantnr, count(objectnaam) as c
from klanten inner join deelnames using(klantnr)
inner join reizen using(reisnr)
inner join bezoeken using(reisnr)
where objectnaam = 'Maan'
group by klantnr) as F
group by klantnr
thanks for any help you can give me!
You do not provide the structure of tables, so probably you have to modify the following query. However it works just for PostgreSQL 9.x+
WITH t AS (
SELECT klantnr, COUNT(objectnaam) AS c
FROM klanten
WHERE objectnaam = 'Maan'
GROUP BY klantnr
ORDER BY c DESC
LIMIT 1
)
SELECT * FROM t
INNER JOIN deelnames USING(klantnr)
INNER JOIN reizen USING(reisnr)
INNER JOIN bezoeken USING(reisnr);
see http://www.postgresql.org/docs/9.3/static/queries-with.html how to use WITH QUERIES.
I have found a simpeler solution:
select klantnr,count (klantnr)
from bezoeken natural join deelnames
where objectnaam ='Maan'
group by klantnr
order by count desc
limit 1

T-SQL Subquery on Latest Date with InnerJoin

I want to do a similiar thing like this guy:
T-SQL Subquery Max(Date) and Joins
I have to do this with an n:m relation.
So the layout is:
tbl_Opportunity
tbl_Opportunity_tbl_OpportunityData
tbl_OpportunityData
So as you see there is an intersection table which connects opportunity with opportunitydata.
For every opportunity there are multiple opportunity datas. In my view i only want a list with all opportunites and the data from the latest opportunity datas.
I tried something like this:
SELECT
dbo.tbl_Opportunity.Id, dbo.tbl_Opportunity.Subject,
dbo.tbl_User.UserName AS Responsible, dbo.tbl_Contact.Name AS Customer,
dbo.tbl_Opportunity.CreationDate, dbo.tbl_Opportunity.ActionDate AS [Planned Closure],
dbo.tbl_OpportunityData.Volume,
dbo.tbl_OpportunityData.ChangeDate, dbo.tbl_OpportunityData.Chance
FROM
dbo.tbl_Opportunity
INNER JOIN
dbo.tbl_User ON dbo.tbl_Opportunity.Creator = dbo.tbl_User.Id
INNER JOIN
dbo.tbl_Contact ON dbo.tbl_Opportunity.Customer = dbo.tbl_Contact.Id
INNER JOIN
dbo.tbl_Opprtnty_tbl_OpprtnityData ON dbo.tbl_Opportunity.Id = dbo.tbl_Opprtnty_tbl_OpprtnityData.Id
INNER JOIN
dbo.tbl_OpportunityData ON dbo.tbl_Opprtnty_tbl_OpprtnityData.Id2 = dbo.tbl_OpportunityData.Id
The problem is my view now includes a row for every opportunity data, since I don't know how to filter that I only want the latest data.
Can you help me? is my problem description clear enough?
thank you in advance :-)
best wishes,
laurin
; WITH Base AS (
SELECT dbo.tbl_Opportunity.Id, dbo.tbl_Opportunity.Subject, dbo.tbl_User.UserName AS Responsible, dbo.tbl_Contact.Name AS Customer,
dbo.tbl_Opportunity.CreationDate, dbo.tbl_Opportunity.ActionDate AS [Planned Closure], dbo.tbl_OpportunityData.Volume,
dbo.tbl_OpportunityData.ChangeDate, dbo.tbl_OpportunityData.Chance
FROM dbo.tbl_Opportunity INNER JOIN
dbo.tbl_User ON dbo.tbl_Opportunity.Creator = dbo.tbl_User.Id INNER JOIN
dbo.tbl_Contact ON dbo.tbl_Opportunity.Customer = dbo.tbl_Contact.Id INNER JOIN
dbo.tbl_Opprtnty_tbl_OpprtnityData ON dbo.tbl_Opportunity.Id = dbo.tbl_Opprtnty_tbl_OpprtnityData.Id INNER JOIN
dbo.tbl_OpportunityData ON dbo.tbl_Opprtnty_tbl_OpprtnityData.Id2 = dbo.tbl_OpportunityData.Id
)
, OrderedByDate AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY Id ORDER BY ChangeDate DESC) RN FROM Base
)
SELECT * FROM OrderedByDate WHERE RN = 1
To make it more readable I'm using CTE (the WITH part). In the end the real "trick" is doing a ROW_NUMBER() partitioning the data by tbl_Opportunity.Id and ordering the partitions by ChangeDate DESC (and I call it RN). Clearly the maximum date in each partition will be RN = 1 and then we filter it by RN.
Without using CTE it will be something like this:
SELECT * FROM (
SELECT dbo.tbl_Opportunity.Id, dbo.tbl_Opportunity.Subject, dbo.tbl_User.UserName AS Responsible, dbo.tbl_Contact.Name AS Customer,
dbo.tbl_Opportunity.CreationDate, dbo.tbl_Opportunity.ActionDate AS [Planned Closure], dbo.tbl_OpportunityData.Volume,
dbo.tbl_OpportunityData.ChangeDate, dbo.tbl_OpportunityData.Chance,
ROW_NUMBER() OVER (PARTITION BY dbo.tbl_Opportunity.Id ORDER BY dbo.tbl_OpportunityData.ChangeDate DESC) RN
FROM dbo.tbl_Opportunity INNER JOIN
dbo.tbl_User ON dbo.tbl_Opportunity.Creator = dbo.tbl_User.Id INNER JOIN
dbo.tbl_Contact ON dbo.tbl_Opportunity.Customer = dbo.tbl_Contact.Id INNER JOIN
dbo.tbl_Opprtnty_tbl_OpprtnityData ON dbo.tbl_Opportunity.Id = dbo.tbl_Opprtnty_tbl_OpprtnityData.Id INNER JOIN
dbo.tbl_OpportunityData ON dbo.tbl_Opprtnty_tbl_OpprtnityData.Id2 = dbo.tbl_OpportunityData.Id
) AS Base WHERE RN = 1
The statement can be simplified for one more step further:
SELECT TOP 1 WITH TIES
dbo.tbl_Opportunity.Id, dbo.tbl_Opportunity.Subject, dbo.tbl_User.UserName AS Responsible,
dbo.tbl_Contact.Name AS Customer, dbo.tbl_Opportunity.CreationDate,
dbo.tbl_Opportunity.ActionDate AS [Planned Closure], dbo.tbl_OpportunityData.Volume,
dbo.tbl_OpportunityData.ChangeDate, dbo.tbl_OpportunityData.Chance
FROM
dbo.tbl_Opportunity INNER JOIN
dbo.tbl_User ON dbo.tbl_Opportunity.Creator = dbo.tbl_User.Id INNER JOIN
dbo.tbl_Contact ON dbo.tbl_Opportunity.Customer = dbo.tbl_Contact.Id INNER JOIN
dbo.tbl_Opprtnty_tbl_OpprtnityData ON dbo.tbl_Opportunity.Id = dbo.tbl_Opprtnty_tbl_OpprtnityData.Id INNER JOIN
dbo.tbl_OpportunityData ON dbo.tbl_Opprtnty_tbl_OpprtnityData.Id2 = dbo.tbl_OpportunityData.Id
ORDER BY
ROW_NUMBER() OVER (PARTITION BY dbo.tbl_Opportunity.Id ORDER BY dbo.tbl_OpportunityData.ChangeDate DESC);