SELECT Distinct with condition of other column value - sql

I have the schema built at this SQL Fiddle if you want to try out.
I have the following data
AutoID Apartment Flag Description
====== ========= ==== ===========
1 1 NO Device 1
2 1 NO Device 2
3 1 NO Device 3
4 2 NO Device 4
5 2 NO Device 5
6 3 NO Device 6
7 3 NO Device 7
8 3 YES Device 8
9 3 NO Device 9
I'm trying to get the data with the following rule
Only select distinct Apartment value
IF Flag is YES then select that item for the distinct value
So if I run the SQL statement I would end up with
AutoID Apartment Flag Description
====== ========= ==== ===========
1 1 NO Device 1
4 2 NO Device 4
8 3 YES Device 8
I've been trying to play around with OVER() and PARTITION BY with little luck. Any help or guidance is greatly appreciated.

;WITH CTE AS
(
SELECT *,
RN = ROW_NUMBER() OVER(PARTITION BY Apartment
ORDER BY CASE WHEN [Flag] = 'YES' THEN 1 ELSE 2 END,
[AutoID])
FROM TableA
)
SELECT *
FROM CTE
WHERE RN = 1
Here is the modified sqlfiddle

First step - assign order numbers in each group with the same apartment number
Second step - select only the first one
select AutoID, Apartment, Flag, Description from (
select AutoID, Apartment, Flag, Description, row_number() over (partition by apartment order by Flag desc) rnum
from table1)
where rnum = 1

Related

Merge Multiple Rows to One Row having Same value swapped between 2 columns In SQL Server

I am working on an API-based simple chat module. I am trying to get chat conversations for a particular user but due to 2 columns having the same value swapped between each other is causing my data to be duplicated.
I want to merge rows having the same values swapped between 2 columns and the merged row should be based on the latest entry inserted in the database.
The data looks like this :
Id To From Message ConversationTime
1 1 2 hello 11:00AM
2 3 1 hi 12:00PM
3 1 3 how are you? 12:15PM
4 3 1 I am fine. 12:30PM
5 4 5 Hi! 04:30PM
6 5 4 Hello 04:35PM
7 1 5 Hola! 06:30PM
So for example if user with Id 1 My result needs to look like this:
Id To From Message ConversationTime
1 1 2 hello 11:00AM
4 3 1 I am fine. 12:30PM
7 1 5 Hola! 06:30PM
If Id is 5 then result would be like this:
Id To From Message ConversationTime
6 5 4 Hello 04:35PM
7 1 5 Hola! 06:30PM
My result set looks like this:
Id To From Message ConversationTime
1 1 2 hello 11:00AM
3 1 3 how are you? 12:15PM
4 3 1 I am fine. 12:30PM
7 1 5 Hola! 06:30PM
Any help would be grateful. Thanks in advance!
The idea is the same as the linked duplicate Get top 1 row of each group ; just use a CASE expression to get the ID of the other user:
DECLARE #ID int = 1;
WITH RNs AS(
SELECT ID,
[To], --TO is a reserved keyword and should not be used for object names
[From], --FROM is a reserved keyword and should not be used for object names
Message,
ConversationTime, --I assume this is a time
ROW_NUMBER() OVER (PARTITION BY CASE [To] WHEN #ID THEN [From] ELSE [To] END ORDER BY ConversationTime DESC) AS RN --TO and FROM are reserved keywords and should not be used for object names
FROM dbo.YourTable
WHERE #ID IN ([To],[From])) --TO and FROM are reserved keywords and should not be used for object names
SELECT ID,
[To], --TO is a reserved keyword and should not be used for object names
[From], --FROM is a reserved keyword and should not be used for object names
Message,
ConversationTime --I assume this is a time
FROM RN
WHERE RN = 1;
SQL Server allows you to do this without a case expressions by unpivoting the data and then using window functions:
select t.*
from (select t.*,
row_number() over (partition by v.user_other order by t.conversationTime desc) as seqnum
from t cross apply
(values (t.to, t.from), (t.from, to.to)
) v(user, user_other)
where v.user = 1
) t
where seqnum = 1;

How to COUNT in a specific column after GROUP BY

I'm stuck with how to write SQL statements, so I would appreciate it if you could teach me.
Current status
items table
id
session_id
item_id
competition_id
1
1
2
1
2
1
3
1
2
1
2
1
2
1
2
1
2
1
5
2
3
1
7
2
4
1
4
2
5
1
5
2
want to
grouping by competition_id,
Count the same numbers in item_id,Extract the most common numbers and their numbers.
For example
If competition_id is 1,item_id → 2 ,and the number is 3
If competition_id is 2,item_id → 5 ,and the number is 2
If competition_id is 3,・・・
If competition_id is 4,・・・
environment
macOS BigSur
ruby 2.7.0
Rails 6.1.1
sqlite
In statistics, what you are asking for is the mode, the most common value.
You can use aggregation and row_number():
select ct.*
from (select competition_id, item_id, count(*) as cnt,
row_number() over (partition by competition_id order by count(*) desc) as seqnum
from t
group by competition_id, item_id
) ci
where seqnum = 1;
In the event that there are ties, this returns only one of the values, arbitrarily. If you want all modes when there are ties use rank() instead of row_number().

Display Correct Row based on Candy Number

Goal:
If a person has two candy number, number 1 should always display first. No need to display candy number 2.
If a person does not have number 1, it should display number 2 instead.
Display all data
(int)(int) (nvarchar) (int)
Id fId Name Candy Number
---------------------------------
1 12 Kimn 1
2 12 Kimn 2
3 19 Lisa 1
4 15 John 2
5 16 Maria 2
6 16 Maria 1
7 17 Mao 2
Requested result:
Id fId Name Candy Number
---------------------------------
1 12 Kimn 1
3 19 Lisa 1
4 15 John 2
6 16 Maria 1
7 17 Mao 2
Problem:
It doesn't work so well for me to display it.
Tried using case and end in where statement but the code didn't fit to the purpose.
Any idea?
select *
from
table
where
candynumber =
CASE WHEN b.MatchType = 1
THEN 1
ELSE 2
END
Thank you!
This can be using row_number() window function:
select Id, fId, Name, Candy_Number from (
select your_table.*, row_number() over(partition by fId order by Candy_Number) as rn from your_table
) t
where rn = 1
order by id
This gives one row per fId, with lower Candy_Number.
You can try this :
SELECT candyWrapper.ID,
candyWrapper.FID,
outerHardCandy.Name,
outerHardCandy.Number
FROM (SELECT innerSoftCandy.Name,
CASE
WHEN (SUM(innerSoftCandy.Number) = 3) OR (SUM(innerSoftCandy.Number) = 1) THEN 1
WHEN (SUM(innerSoftCandy.Number) = 2) THEN 2
END AS Number
FROM Candy innerSoftCandy
GROUP BY innerSoftCandy.Name
) outerHardCandy
INNER JOIN Candy candyWrapper ON (outerHardCandy.Name = candyWrapper.Name AND outerHardCandy.Number = candyWrapper.Number)
ORDER BY candyWrapper.ID
You can see this here -> http://rextester.com/BBD89608

SQL query to take top elements of ordered list on Apache Hive

I have the table below in an SQL database.
user rating
1 10
1 7
1 6
1 2
2 8
2 3
2 2
2 2
I would like to keep only the best two ratings by user to get:
user rating
1 10
1 7
2 8
2 3
What would be the SQL query to do that? I am not sure how to do it.
It will work
;with cte as
(select user,rating, row_number() over (partition by user order by rating desc) maxval
from yourtable)
select user,rating
from cte
where maxval in (1,2)

How to select a random row when 2 rows have an equal property

I have a table containing items in a priority order as such:
id priority
1 1
2 2
3 3
4 8
5 3
6 4
Currently I retrieve items (SQL Server) in priority order, although a random item when there are matching priorities using the following query:
select item
from table
order by priority, newid()
This will return
id priority
1 1
2 2
3 3
5 3
6 4
4 8
or
id priority
1 1
2 2
5 3
3 3
6 4
4 8
So it's approximately 50/50 traffic
I now have a requirement to only retrieve one row of the rows when there are two matching priorities, for example..
id priority
1 1
2 2
3 3
6 4
4 8
or
id priority
1 1
2 2
5 3
6 4
4 8
You can use ROW_NUMBER, presuming SQL-Server (because of NEWID):
WITH CTE AS
(
SELECT t.*, RN = ROW_NUMBER() OVER (PARTITION BY Priority
ORDER BY ID)
FROM dbo.table t
)
SELECT * FROM CTE WHERE RN = 1
If these are all columns you could also use this sql:
SELECT MIN(t.ID) AS ID, t.Priority
FROM dbo.table t
GROUP BY t.priority
Update "No, I need to be able to get a random row when two (or more) priorities match"
Then i have misunderstood your requirement. You can use ORDER BY NEWID:
WITH CTE AS
(
SELECT t.*, RN = ROW_NUMBER() OVER (PARTITION BY Priority
ORDER BY NEWID())
FROM dbo.table t
)
SELECT * FROM CTE WHERE RN = 1