How to find number duplicate values by associated id per value - sql

I have a messaging system with database tables like below. UID is the users id, and sid is the store id that is sending the message.
UID SID Content
1 10 "blah"
1 11 ...
2 10 ...
3 12 ...
3 12 ...
3 10 ...
I want to group users with the number of messages they have received per store. So the output will be
UID NumUniqueSIDs
1 1 (corresponds to uid = 1, sid = 10)
1 1 (corresponds to uid = 1, sid = 11)
2 1 (corresponds to UID = 2, sid = 10)
3 2 (corresponds to UID = 3, sid = 12)
3 1 (corresponds to UID = 3, sid = 10)
I have been unable to come up with a query that accomplishes this. Does anyone know how this can be done?

The following query produces the correct results:
SELECT uid, count(sid) as NumUniqueSIDs from Messages group by uid, sid

Related

IF NOT EXISTS in Oracle

I am new in Oracle, need some help to SQL Server's IF NOT EXISTS equivalent in Oracle.
I need to find the max RoleID from Role table based on entity number if a particular role does not exists. I have created below query but its failing (it should return null if an entity has that particular role and should return 1 if an entity has no role, its returning 1 in both cases) if an entity does not have any role.
Code:-
SELECT NVL(MAX(role_id), 0) + 1 AS RoleID from roles WHERE entity_no = '000001'
AND
NOT EXISTS (
SELECT 1
FROM roles
WHERE entity_no = '000001' AND name = 'Survey'
)
I need 1 as RoleID if an entity does not have any role(s) but it should return null for the entity having that particular role('Survey') else return max RoleID with increment, TIA.
Would this do? Read comments within code.
entity_no = 00001 has Survey, so query should return NULL
entity_no = 00002 doesn't have Survey, so query should return 1
SQL> with
2 roles (role_id, entity_no, name) as
3 -- sample data
4 (select 1, '00001', 'Survey' from dual union all
5 select 2, '00002', 'xxx' from dual
6 ),
7 temp as
8 -- does ENITITY_NO has role for NAME = Survey? If so, CNT = 1; else, CNT = 0
9 (select entity_no,
10 sum(case when name = 'Survey' then 1 else 0 end) cnt
11 from roles
12 group by entity_no
13 )
14 -- finally, check CNT value and return the result
15 select case when t.cnt = 0 then 1 else null end as role_id
16 from roles r join temp t on t.entity_no = r.entity_no
17 where r.entity_no = '&par_entity_no';
Enter value for par_entity_no: 00001
ROLE_ID
----------
SQL> /
Enter value for par_entity_no: 00002
ROLE_ID
----------
1
SQL>

How do I select just mutual rows in SQL?

I have a table with a source_id and destination_id and a message and I want to group messages together. There can only be one message between a given source_id and destination_id, but I only want rows that have a mutual response for a given ID (say id 1). In the following examples, I want rows #1, #2, #4 and #5 because there is a mutual response between id 1 and 2 and between id 1 and id 4 (id 1 sent a message to id 2 and id 2 sent a message to id 1, similarly, id 1 sent a message to id 4 and id 4 sent a message to id 1). I don't want id 3 because it has no mutual response.
How do I select this in SQL? (I'm using PostgreSQL btw)
Example:
table messages
# source_id destination_id message
1 1 2 hello
2 2 1 hi
3 1 3 bye
4 1 4 thanks
5 4 1 okay
6 3 5 blablabla
7 5 3 hooray
Preferably, I want my select to return these 4 rows:
1 1 2 hello
2 2 1 hi
3 1 4 thanks
4 4 1 okay
Thanks in advance :)
You seem to be describing exists:
select m.*
from messages m
where exists (select 1
from messages m2
where m2.source_id = m.destination_id and
m2.source_id = m.destination_id
);
In your example, this would also return rows 6 and 7, because those seem to follow the rule you specified.
If you want 1 to be one of the ids, then include a filter for that:
select m.*
from messages m
where 1 in (m.source_id, m.destination_id) and
exists (select 1
from messages m2
where m2.source_id = m.destination_id and
m2.source_id = m.destination_id
);
Do a self join:
select m1.*
from messages m1
join messages m2
on m1.source_id = m2.destination_id
and m2.source_id = m1.destination_id
where 1 in (m1.source_id, m2.source_id)

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

How to select id when same id has multiple rows but I am looking for id which are missing a particular value

I have this table my_table_c with the below values
SELECT * FROM my_table_c
ID GROUP_ID GROUP_VALUE
1 2 1
3 3 2
3 4 1
5 4 1
5 2 1
2 2 2
2 3 2
2 4 1
I am looking for this output where I get only the ID which do not have group_id 2. Additionally, I don't want to get the ID where group_id 2 is absent but other group ids are present.
If group_id 2 is absent, that's my target id.
So with the values shown in table above, I just expect ID = 3 to be returned as other ids 1, 5 and 2 each have rows where group_id = 2.
Can anyone please help with a query to fetch this result.
You could get all the id's that have group_id = 2 and use NOT IN
select *
from my_table_c
where id not in (select id from my_table_c where group_id = 2)
Another way but using NOT EXISTS
select *
from my_table_c mtcA
where not exists (select *
from my_table_c mtcB
where mtcA.id = mtcB.id and mtcB.group_ID = 2)

SQL Update query

Can i use several WHEN conditions in UPDATE clause to update a single column.
I want to update table TABLE having columns ID and NAME:
Is below query correct?
UPDATE TABLE
SET id = CASE id
WHEN id IN (2, 3, 4) THEN 1
WHEN id= 5 THEN 8
WHEN id IN(9, 7) THEN 6
WHERE name = 'abc'
Yes, that is allowed, but remove ID after CASE. And, you need to END your case.
UPDATE TABLE
SET ID = CASE
when ID in (2,3,4)
then 1
when ID = 5
then 8
when ID in (9,7)
then 6
END
where NAME = 'abc'
There are two alternate syntaxes for CASE. As above, and the other is where you want to compare a single value against others, like this:
UPDATE TABLE
SET ID = CASE ID
when 2
then 1
when 5
then 8
when 7
then 6
END
where NAME = 'abc'
Case comes in two versions:
version 1:
Case Id
When 2 Then 1
When 3 Then 1
When 4 Then 1
When 5 Then 8
When 7 Then 6
When 9 Then 6
End
version 2:
Case
When Id in (2,3,4) Then 1
When Id = 5 Then 8
When Id in (9,7) Then 6
End
Both of above are equivilent