I have a table with the following format:
User | Entity | ID
123 AB 1
123 AB 2
543 BC 3
098 CB 4
543 BC 5
543 ZG 6
etc...
I want to get a result set that only returns the User/Entity pairs and their ID for the greatest ID, so this result for example:
User | Entity | ID
123 AB 2
098 CB 4
543 BC 5
543 ZG 6
Is there any way to do this in SQL?
Try to use group by with max function
select user, Entity, max(id) as id
from table
group by user, Entity
You can also use CTE and Partition By
Like this:
;WITH CTE as
(
SELECT
Users,Entity,
ROW_NUMBER() OVER(PARTITION BY Entity ORDER BY ID DESC) AS Row,
Id
FROM Item
)
SELECT Users, Entity, Id From CTE Where Row = 1
Note that we used Order By ID DESC as we need highest ID. You can delete DESC if you want the smallest ID.
SQLFiddle: http://sqlfiddle.com/#!3/1dcb9/4
Related
I have the following table:
In Table_1, (ID, Name) pairs can repeat and have any combination
Table_1:
ID
Name
Value1
Value2
1
John
34
45
1
John
15
78
2
Randy
67
12
2
Randy
40
46
1
Randy
23
85
2
Holmes
10
100
I want to find all information for all unique pairs. So the output should be:
ID
Name
Value1
Value2
1
John
34
45
2
Randy
67
12
1
Randy
23
85
2
Holmes
10
100
When I do SELECT DISTINCT(ID, Name) I get the unique pairs correctly. But how do I add value1, value2 columns to this. Because adding value1, value2 causes the pairs to repeat.
You may use DISTINCT ON here:
SELECT DISTINCT ON (ID, Name) *
FROM yourTable
ORDER BY ID, Name;
Demo
This will arbitrarily return one record from each (ID, Name) combination. Note that if you wanted to choose which of the duplicate pair (or more) records gets retained, you could add another level to the ORDER BY clause. For example, to choose the duplicate record with the highest Value2 value, you could use:
SELECT DISTINCT ON (ID, Name) *
FROM yourTable
ORDER BY ID, Name, Value2 DESC;
try row_number and partition by.
SELECT *
FROM (
select *,
row_number() over(partition by Name order by Name desc) rn
from Table_1) as a
where rn = 1;
I have a table that looks something like this:
customer_id
data
1
123
1
456
2
789
2
101
2
121
2
123
3
123
4
456
What I would like to do is perform a SELECT combined with a LIMIT X to get X number of records as well as any other records that have the same customer_id
Example query: SELECT customer_id, data FROM table ORDER BY customer_id LIMIT 3;
This query returns:
customer_id
data
1
123
1
456
2
789
I'd like a query that will look at the last customer_id value and return all remaining records that match beyond the LIMIT specified. Is it possible to do this in a single operation?
Desired output:
customer_id
data
1
123
1
456
2
789
2
101
2
121
2
123
In Postgres 13 can use with ties:
select t.*
from t
order by customer_id
fetch first 3 rows with ties;
In earlier versions you can use in:
select t.*
from t
where t.customer_id in (select t2.customer_id
from t t2
order by t2.customer_id
limit 3
);
You can use corelated subquery with count as follows:
Select t.*
From t
Where 3 >= (select count(distinct customer_id)
From t tt
where t.customer_id >= tt.customer_id)
I have the following table
User A | User B | Value
-------+--------+------
1 | 2 | 60
3 | 1 | 10
4 | 5 | 50
3 | 5 | 50
5 | 1 | 80
2 | 3 | 10
I want group together records where either user a = x or user b = x, in order to find averages.
e.g. User 1 appears in the table 3 times, once as 'User A' and twice as 'User B'. So I would want to carry out my AVG() function using those three rows.
I need the highest and lowest average values. Such a query would break down the above table into the following groups:
User | Avg Value
-----+-----
1 | 50
2 | 35
3 | 23.33
4 | 50
5 | 60
and then return
Highest Avg | Lowest Avg
------------+-----------
60 | 23.33
I know that GROUP BY collects together records where a column has the same value. I want to collect together records where either one of two columns has the same value. I have searched through many solutions but can't seem to find one that meets my problem.
A portable option uses union all:
select usr, avg(value) avg_value
from (
select usera usr, value from mytable
union all select userb, value from mytable
) t
group by usr
This gives you the first resultset. Then, you can add another level of aggregataion to get the maximum and minimum average:
select min(avg_value) min_avg_value, max(avg_value) max_avg_value
from (
select usr, avg(value) avg_value
from (
select usera usr, value from mytable
union all select userb, value from mytable
) t
group by usr
) t
In databases that support lateral joins and values(), this is most convinently (and efficiently) expressed as follows:
select min(avg_value) min_avg_value, max(avg_value) max_avg_value
from (
select usr, avg(value) avg_value
from mytable t
cross join lateral (values (usera, value), (userb, value)) as x(usr, value)
group by usr
) t
This would work in Postgres for example. In SQL Server, you would just replace cross join lateral with cross apply.
You can unpivot using union all and then aggregation:
select user, avg(value)
from ((select usera as user, value) union all
(select userb as user, value)
) u
group by user;
You can get the extremes with another level of aggregation:
select min(avg_value), max(avg_value)
from (select user, avg(value) as avg_value
from ((select usera as user, value) union all
(select userb as user, value)
) u
group by user
) ua
I have table with data like this
id group order value
-------------------------
1 1 1 23
2 1 2 34
3 2 1 234
4 2 2 77
5 2 3 102
I want to insert into table so I have one row per group, with the value showing a string of comma-separated values orders based on the order.
id group value
----------------
1 1 23,34
2 2 234,77,102
How do I do this? I'm using Postgres 9.3
Postgres supports string_agg():
select row_number() over () as id, "group", string_agg(value, ',' order by "order")
from t
group by "group";
I would look at PostgreSQL's string_agg aggregate function.
I have that stores data in the usual way .
Id | Name | Number
----+------+-------
1 A 101
2 B 102
3 A 103
4 A 105
5 C 104
6 B 106
7 C 108
and so on.
Now I want to convert this table to something similar to column store.
For example all the facility should be ordered and grouped by the name.
Also if a new record arrives with the same the same Name, if should by assigned an ID, which is in the range assigned for that name group.
Just to elaborate. If 'A' has a ID range from 1 to 20 and currently in the table there are 5 ids, so when a new record arrives with Name A, it should be assigned the ID = 6.
Name goes with other names. Every time a ID is populates, the NextID in metatable has to incremented by 1.
As of now I have created a meta table which stores the Min, max ID along with next ID for each name group.
MetaTable
Name MinID MaxId NextID
---------------------------
A 1 30 6
B 31 60 45
C 61 100 78
And using case statements to populate the data in the mail Table. But its very inefficient and the query is long running.
Note: The Number column does not matter.
What could be a more efficient and faster way to achieve this?
SELECT Name,
MIN( ID ),
MAX( ID ),
COUNT(*) OVER ( PARTITION BY Name ) + 1 AS NextID
FROM YourTable
GROUP BY Name;