Select record according to column value - sql

I have a table as shown below, and I want to select u_id with type, but if there are more records for u_id then I want to get record that has best type, or if it's not there then good and so on, best>good>worst so far. I am only able to get first row for u_id that is returned.
u_id type
1 best
2 good
3 worst
2 best

You can prioritize this with row_number and select one row per u_id.
select u_id,type
from (
select u_id,type,
row_number() over(partition by u_id order by case when type='best' then 1
when type='good' then 2
when type='worst' then 3
else 4 end) as rn
from tablename
) t
where rn=1

with type (n, type) as (values
(1, 'best'),(2,'good'),(3,'worst')
)
select distinct on (u_id) u_id, type
from t inner join type using (type)
order by u_id, n

Both the other answers are really good. This is a variant on the distinct on version that doesn't require a join:
select distinct on (u_id) u_id, type
from t
order by u_id, array_position(array[('best'), ('good'), ('worst')], type)

Related

Finding top count of a value in a table using SQL

I'm looking for a way to find the top count value of a column by SQL.
If for example this is my data
id type
----------
1 A
1 B
1 A
2 C
2 D
2 D
I would like the result to be:
1 A
2 D
I'm looking for a way to do it without groping by the column I count (type in the example)
Thanks
Statistically, this is called the "mode". You can calculate it using window functions:
select id, type, cnt
from (select id, type, count(*) as cnt,
row_number() over (partition by id order by count(*) desc) as seqnum
from t
group by id, type
) t
where seqnum = 1;
If there are ties, then an arbitrary value is chosen from among the ties.
You are looking for the statistic mode (the most often ocurring value):
select id, stats_mode(type)
from mytable
group by id
order by id;
Not all DBMS support this however. Check your docs, wheher this function or a similar one is available in your DBMS.
Just GROUP BY id, type and keep the rows with the maximum counter:
select id, type
from tablename
group by id, type
having count(*) = (
select count(*) from tablename group by id, type order by count(*) desc limit 1
)
See the demo
Or
select id, type
from tablename
group by id, type
having count(*) = (
select max(t.counter) from (select count(*) counter from tablename group by id, type) t
)
See the demo

Select distinct rows based on two columns with additional columns

I have a table such as this
Blog
Id ColumnId DateCreated Type
1 1 2018-01-01 1
1 1 2018-01-02 2
1 1 2018-02-01 3
I need to select all unique rows based on the combination of Id and ColumnId. Then it needs to grab me the latest date and largest Type. I can't seem to figure this out.
I started of with just getting distinct values like this:
SELECT Id, ColumnId
FROM Blog
GROUP BY Id, ColumnId
Then I figured if I maybe joined it on itself I can pull out the rest, but I'm having no luck how to accomplish this
SELECT *
FROM ( SELECT Id, ColumnId
FROM Blog
GROUP BY Id, ColumnId) A
INNER JOIN Blog B ON A.Id = B.Id AND A.ColumnId = B.ColumnId
But that just gives me back all 3 rows.
In my live example the Id column is not int, but uniqueidentifier. For sake of simplicity I made it int in my example.
Expected Result Sample:
Id ColumnId DateCreated Type
1 1 2018-02-01 3
Have you tried using MAX?
SELECT Id, ColumnId, MAX(DateCreated), MAX([Type])
FROM Blog
GROUP BY Id, ColumnId
Use row_number():
select b.*
from (select b.*,
row_number() over (partition by id, columnid order by date desc, type desc) as seqnum
from blog b
) b
where seqnum = 1;
This grabs the largest type on the latest date, which is how I interpret "it needs to grab me the latest date and largest Type."
seems you need the last
you could use an inner join on the max date
select * from blog
inner join (
select id, columnId, max(DateCreated) as max_date
from blog
group by id, columnId
) t on t.id = blog.id, t.columnId = blog.columnId and t.max_date = blog.DateCreated
Maybe is not the best solution, but you could try to use a subselect in your query.
Something like this
SELECT DISTINCT Id, ColumnId, (SELECT MAX(Type) FROM blog) AS type
FROM Blog

How to get max value and using group by clause

I have a query like this:
select transactions_id,
time_stamp,
clock
from times
group by transactions_id
having sum(distinct type) = 1
now, I would like to get max value depending on id.
I used below queries but not worked:
select max(id),
transactions_id,
time_stamp,
clock
from times
group by transactions_id
having sum(distinct type) = 1
or
select transactions_id,
time_stamp,
clock
from times
group by transactions_id
having sum(distinct type) = 1
and max(id)
for example:
I have three conditions:
type must be 1
group by transactions_id
max id
You can find aggregates in one query and join its result with the table to get the relevant rows.
select *
from times t1
join (
select transactions_id,
max(id) as id
from times
where type = 1
group by transactions_id
) t2 using (transactions_id, id);
If I understand correctly, you can use the ANSI standard row_number() function:
select t.*
from (select t.*,
row_number() over (partition by transactions_id order by id desc) as seqnum
from times t
) t
where seqnum = 1;
I am not sure what having sum(distinct type) = 1. That condition is not explained in the question.

Return two rows from SQL table with a difference in values [duplicate]

This question already has answers here:
How to request a random row in SQL?
(30 answers)
Closed 6 years ago.
iam trying to return 2 rows from table that have a difference in values, not being an SQL wise man i am stuck any help would be appreciated :-)
TABLE A:
NAME DATA
Oscar HOME1
Jens HOME2
Will HOME1
Jeremy HOME2
Al HOME1
Result, should be 2 random rows with a difference in DATA value
NAME DATA
Oscar HOME1
Jeremy HOME2
Anyone?
Easy way to have random data.
;with tblA as (
select name,data,
row_number() over(partition by data order by newid()) rn
from A
)
select name,data
from tblA
where rn = 1
Couuld be you need
select * from my_table a
inner join my_table b on a.data !=b.data
where a.data in ( SELECT data FROM my_table ORDER BY RAND() LIMIT 1);
For your code
SELECT *
FROM [dbo].[ComputerState] as a
INNER JOIN [dbo].[ComputerState] as b ON a.ServiceName != b.ServiceName
WHERE a.ServiceName IN (
SELECT top 1 [ServiceName] FROM [dbo].[ComputerState]
);
If the question is really this simple, you can use an aggregate such as MAX() or MIN() to grab one row for each different DATA:
SELECT MAX(NAME), DATA
FROM TABLE_A
GROUP BY DATA
Of course, if any other variables are introduced to the requirements, this may no longer work.
;WITH cteA AS (
SELECT
name
,data
,ROW_NUMBER() OVER (PARTITION BY data ORDER BY NEWID()) as DataRowNumber
,ROW_NUMBER() OVER (PARTITION BY 1 ORDER BY NEWID()) as RandomRowNumber
FROM
A
)
SELECT *
FROM
cteA
WHERe
DataRowNumber = 1
AND RandomRowNumber <= 2
This Expands on #AlexKudryashev 's answer a little.
;with tblA as (
select name,data,
row_number() over(partition by data order by newid()) rn
from A
)
select name,data
from tblA
where rn = 1
The only issue with what he had Is that the number of Rows where rn = 1 will be depended on the COUNT(DISTINCT data) so it could lead to more than 2 results. To fix one could add a SELECT TOP 2 clause but it might not be fully random as results at that point as it will be dependent on the ordinal results of how SQL optimizes the query which is likely to be consistent. To get truly random add a second random row number and limit the results to the top 2 of those.

Select independent distinct with one query

I need to select distinct values from multiple columns in an h2 database so I can have a list of suggestions for the user based on what is in the database. In other words, I need something like
SELECT DISTINCT a FROM table
SELECT DISTINCT b FROM table
SELECT DISTINCT c FROM table
in one query. In-case I am not clear enough, I want a query that given this table (columns ID, thing, other, stuff)
0 a 5 p
1 b 5 p
2 a 6 p
3 c 5 p
would result in something like this
a 5 p
b 6 -
c - -
where '-' is an empty entry.
This is a bit complicated, but you can do it as follows:
select max(thing) as thing, max(other) as other, max(stuff) as stuff
from ((select row_number() over (order by id) as seqnum, thing, NULL as other, NULL as stuff
from (select thing, min(id) as id from t group by thing
) t
) union all
(select row_number() over (order by id) as seqnum, NULL, other, NULL
from (select other, min(id) as id from t group by other
) t
) union all
(select row_number() over (order by id) as seqnum, NULL, NULL, stuff
from (select stuff, min(id) as id from t group by stuff
) t
)
) t
group by seqnum
What this does is assign a sequence number to each distinct value in each column. It then combines these together into a single row for each sequence number. The combination uses the union all/group by approach. An alternative formulation uses full outer join.
This version uses the id column to keep the values in the same order as they appear in the original data.
In H2 (which was not originally on the question), you can use the rownum() function instead (documented here). You may not be able to specify the ordering however.