How can I get grouped value by weight without subqueries? [duplicate] - sql

This question already has answers here:
Select first row in each GROUP BY group?
(20 answers)
Closed 8 years ago.
I have a table with fields:
id
category_id
property_id
Weight
How can I get list with {category_id, property_id} where property_id from the highest weight?
Example:
id | category_id | property_id | weight |
1 | 1 | 1 | 20 |
2 | 1 | 2 | 10 |
3 | 2 | 2 | 30 |
4 | 2 | 3 | 40 |
Right results after query:
category_id | property_id
1 | 1 (because 20 > 10)
2 | 3 (because 40 > 30)
It is simple issue, but I am searching easiest and right way, how I can do it with postgresql instruments without subqueries and temporary tables.

Use distinct on:
select distinct on (category_id) t.*
from tablewithfields t
order by category_id, weight desc;
EDIT:
You can do this with window functions, but the above is probably more efficient:
select t.*
from (select t.*, row_number() over (partition by category_id order by weight desc) as seqnum
from tablewithfields t
) t
where seqnum = 1;

Related

Getting all values from table after grouping by id [duplicate]

This question already has answers here:
Retrieving last record in each group from database - SQL Server 2005/2008
(2 answers)
Closed 2 years ago.
I have a table that contains items with three values Id, RevisionId and Data like this.
| Id | RevisionId | Data |
| 0 | 0 | Value1 |
| 0 | 1 | Value2 |
| 1 | 0 | Value1 |
| 2 | 0 | Value1 |
| 2 | 1 | Value2 |
| 2 | 3 | Value3 |
If I want only the Id with the highest RevisionId for each I can make an SQL statement like this.
SELECT Id, MAX(RevisionId) AS RevisionId FROM RevisionTable GROUP BY Id
But I don't know how to get the Data value connected to that max RevisionId for each Id.
You can use row_number():
select *
from (
select t.*, row_number() over(partition by id order by revisionid desc) rn
from mytable t
) t
where rn = 1
top(1) with ties also comes to mind:
select top (1) with ties t.*
from mytable t
order by row_number() over(partition by id order by revisionid desc) rn

Selecting the first row of group with additional group by columns

Say I have a table with the following results:
How is it possible for me to select such that I only want distinct parent_ids with the min result of object0_behaviour?
Expected output:
parent_id | id | object0_behaviour | type
------------------------------------------
1 | 1 | 5 | IP
2 | 3 | 5 | IP
3 | 5 | 7 | ID
4 | 6 | 7 | ID
5 | 8 | 5 | IP
6 | 18 | 7 | ID
7 | 10 | 7 | ID
8 | 9 | 5 | IP
I have tried:
SELECT parent_id, min(object0_behaviour) FROM table GROUP BY parent_id
It works, however if I wanted the other 2 additional columns, I am required to add into GROUP BY clause and things go back to square one.
I saw examples with R : Select the first row by group
Similar output from what I need, but I can't seem to convert it into SQL
You can try using row_number() window function
select * from
(
select *, row_number() over(partition by parent_id order by object0_behaviour) as rn
from tablename
)A where rn=1
select * from table
join (
SELECT parent_id, min(object0_behaviour) object0_behaviour
FROM table GROUP BY parent_id
) grouped
on grouped.parent_id = table.parent_id
and grouped.object0_behaviour = table.object0_behaviour

select top record and count from each group oracle? [duplicate]

This question already has answers here:
Fetch the rows which have the Max value for a column for each distinct value of another column
(35 answers)
Select First Row of Every Group in sql [duplicate]
(2 answers)
Return row with the max value of one column per group [duplicate]
(3 answers)
Oracle SQL query: Retrieve latest values per group based on time [duplicate]
(2 answers)
Closed 3 years ago.
Get top record and count?
PKid | QId | QNumber | EmailId | FirstName | LastName |
1 | 102 | A1022 | jsmith#test.com | John | Smith |
2 | 103 | A1021 | jsmith#test.com | John | smith |
3 | 104 | A1031 | jblack#test.com | Jack | Black |
4 | 105 | A1032 | jblack#test.com | Jack | black |
5 | 106 | A1023 | jsmith#test.com | John |
I want to fetch records group by name and order by occupation desc and count. Something like this-
S.no | QId | QNumber | EmailId | FirstName | LastName | Count
1 | 106 | A1023 | jsmith#test.com | John | | 3
2 | 105 | A1032 | jblack#test.com | Jack | black | 2
I tried something like this but no luck---
SELECT
ROW_NUMBER() OVER(
ORDER BY
COUNT(1) DESC
) AS S_NO,QId,
MAX(QNUMBER) AS QNUMBER,
EmailId,FirstName,LastName
COUNT(1)
FROM
TblEmp
GROUP BY
EmailId;
I would have done
ROW_NUMBER() OVER(PARTITION BY EmailId ORDER BY qnumber DESC) AS rown
and then wrapped it all in an outer query that has WHERE rown = 1. The outer query would also calculate the S_NO, not the inner query
Something like this:
SELECT
ROW_NUMBER() OVER(ORDER BY qnumber) AS S_NO,
ee.*
FROM
(
SELECT
ROW_NUMBER() OVER(PARTITION BY EmailId ORDER BY qnumber DESC) AS rown,
COUNT(*) OVER(PARTITION BY EmailId) AS count,
e.*
FROM
TblEmp e
) ee
WHERE ee.rown = 1
But i'm not really sure where your "order by count" fits in; to me it just looks like you're taking the latest (according to qnumber) record, taking a count of the other records, and reassigning some arbitrary incrementing number as s_no

SQL - Return records with highest version for each quotation ID

If I have a table with three columns like below
CREATE TABLE QUOTATIONS
(
ID INT NOT NULL,
VERSION INT NOT NULL,
PRICE FLOAT NOT NULL
);
In addition to this, lets say that the table consists of the follow records:
ID | VERSION | PRICE
----+-----------+--------
1 | 1 | 50
1 | 2 | 40
1 | 3 | 30
2 | 1 | 100
2 | 2 | 80
3 | 1 | 50
Is there any single SQL query that can be run and return the rows of all quotations with the highest version only?
The results should be like follow:
ID | VERSION | PRICE
----+-----------+--------
1 | 3 | 30
2 | 2 | 80
3 | 1 | 50
I like this method which uses no subqueries:
select top (1) with ties q.*
from quotations q
order by row_number() over (partition by id order by version desc);
Basically, the row_number() assigns "1" to the highest version for each id. The top (1) with ties returns all the 1s.
SELECT id,version,price
FROM tableName t
JOIN (SELECT id,MAX(version) AS version
FROM tableName
GROUP BY id) AS q1 ON q1.id = t.id AND q1.version = t.version

select top 1 with max 2 fields

I have this table :
+------+-------+------------------------------------+
| id | rev | class |
+------+-------+------------------------------------+
| 1 | 10 | 2 |
| 1 | 10 | 5 |
| 2 | 40 | 6 |
| 2 | 50 | 6 |
| 2 | 52 | 1 |
| 3 | 33 | 3 |
| 3 | 63 | 5 |
+------+-------+------------------------------------+
I only need the rows where rev AND then class columns have max value.
+------+-------+------------------------------------+
| id | rev | class |
+------+-------+------------------------------------+
| 1 | 10 | 5 |
| 2 | 52 | 1 |
| 3 | 63 | 5 |
+------+-------+------------------------------------+
Query cost is important for me.
Just the rows that satisfy the condition that it has both max values?
Here's an SQL Fiddle;
SELECT h.id, h.rev, h.class
FROM ( SELECT id,
MAX( rev ) rev,
MAX( class ) class
FROM Herp
GROUP BY id ) derp
INNER JOIN Herp h
ON h.rev = derp.rev
AND h.class = derp.class;
The fastest way might be to have an index on t(id, rev) and t(id, class) and then do:
select t.*
from table t
where not exists (select 1
from table t2
where t2.id = t.id and t2.rev > t.rev
) and
not exists (select 1
from table t2
where t2.id = t.id and t2.class > t.class
);
SQL Server is pretty smart in terms of optimization, so the aggregation approach might be just as good. However, in terms of performance, this is just a bunch of index lookups.
Here is a SQL 2012 example. Very straight forward with the implied table and the PARTITION function.
Basically, with each ID as a partition/group, sort the values of the other fields in a descending order assigning each one an incrementing RowId, then only take the first one.
select id, rev, [class]
from
(
SELECT id, rev, [class],
ROW_NUMBER() OVER(PARTITION BY id ORDER BY rev DESC, [class] desc) AS RowId
FROM sample
) t
where RowId = 1
Here is the SQL Fiddle
Keep in mind, this works with the criteria in the example dataset, and not the MAX of two fields as stated in the question's title.
I guess you mean: the max of rev and the max of class. If not, please clarify what to do when there is no row where both fields have the highest value.
select id
, max(rev)
, max(class)
from table
group
by id
If you mean total value of rev and class use this:
select id
, max
, rev
from table
where id in
( select id
, max(rev + class)
from table
group
by id
)