How to find correlated values in Oracle? - sql

Say you have a table such as:
id foreign_key status
------------------------
1 1 new
2 1 incative
3 1 approved
4 2 new
5 2 new
6 2 approved
7 3 new
8 3 approved
9 4 approved
How to find records where the for a given foreign_key there is only one record in status new and the other are approved, like in case of foreign_key 3?

select foreign_key from table
group by foreign_key
having
abs(1 - count(case status when 'new' then 1 end)) +
abs(count(1) - 1 - count(case status when 'approved' then 1 end)) = 0

Something like this
Select *
from
(
Select foreign_key
from table
where status = 'new'
group by foreign_key
having count(1) = 1
) new_st
inner join
(
Select foreign_key
from table
where status = 'approved'
group by foreign_key
having count(1) = (select count(1)-1 from table t1 where t1.foreign_key =foreign_key)
) app_st
on new_st.foreign_key = app_st.foreign_key

SELECT *
FROM (SELECT id, foreign_key, status,
COUNT (DECODE (status, 'new', 1))
OVER (PARTITION BY foreign_key)
new_count,
COUNT (DECODE (status, 'approved', 1))
OVER (PARTITION BY foreign_key)
approved_count,
COUNT (status) OVER (PARTITION BY foreign_key) total_count
FROM mytable)
WHERE new_count = 1 AND new_count + approved_count = total_count;
I have used 3 different counts. One to count new, one to count approved and one to count all status. Finally select only those records where new_count = 1 and new_count + approved_count is equal to total_count.
Demo here.
EDIT: Can add approved_count > 0 condition to make sure that there is atleast one approved status.

Related

SQL: return rows with only the earliest date for each id but only if it satisfies condition

I would like to get list of unique id that have 'condition=1' before 'condition=2'.
id
date
condition1
condition2
1
2022/02
1
0
1
2022/04
0
1
1
2022/05
0
0
2
2021/09
0
1
2
2022/01
1
0
3
2022/02
1
0
3
2022/05
0
1
In this case it would be 1 and 3.
SELECT id, MIN(date) FROM TABLE GROUP BY id
I know that i can do something like this to get first dates for id but i just cant figure out what to do for my problem
We can GROUP BY id and build two conditional MIN dates using CASE WHEN.
In the HAVING clause we say that the minimum date with condition 1 must appear before the minimum date with condition 2.
SELECT id
FROM yourtable
GROUP BY id
HAVING MIN(CASE WHEN condition1 = 1 THEN date END) <
MIN(CASE WHEN condition2 = 1 THEN date END)
ORDER BY id;
Try out here: db<>fiddle
Something like:
SELECT DISTINCT Id
FROM
(SELECT id, MIN(date)
FROM TheTable
WHERE Condition1 = 1
GROUP BY Id) c1
INNER JOIN
(SELECT Id, MIN(date)
FROM TheTable
WHERE Condition2 = 1
GROUP BY Id) c2
ON c1.Id=C2.Id AND c1.Date < c2.Date

How to merge two query results joining same date

let's say there's a table have data like below
id
status
date
1
4
2022-05
2
3
2022-06
I want find count of id of each month by their status. Something like this below
date
count(status1) = 4
count(status2) =3
2022-05
1
null
2022-06
null
1
I tried doing
-- select distinct (not working)
select date, status1, status2 from
(select date, count(id) as "status1" from myTable
where status = 4 group by date) as myTable1
join
(select date, count(id) as "status2" from myTable
where status = 3 group by date) as myTable2
on myTable1.date = myTable2.date;
-- group by (not working)
but it does duplicate the data needed.
and I am using SQL Server.
select d.date,
sum
(
case
when d.status=4 then 1
else 0
end
)count_status_4,
sum
(
case
when d.status=5 then 1
else 0
end
)count_status_5
from your_table as d
group by d.date

SQL - How to find out that a status field has no record with a value equal to 3

I have a table that can look like this:
user_id
status
1
3
1
5
2
3
2
1
3
5
table has user_id, and status column,
the status column is integer has 1,2,3,4,5 state, each user can has one than one record
but only can has one record that status is 3.
How to find out that a status field has no record with a value equal to 3
Please help!
Thanks
Rob
You could use an aggregation approach:
SELECT user_id
FROM yourTable
GROUP BY user_id
HAVING COUNT(CASE WHEN status = 3 THEN 1 END) = 0;
Using exists logic we can try:
SELECT DISTINCT user_id
FROM yourTable t1
WHERE NOT EXISTS (
SELECT 1
FROM yourTable t2
WHERE t2.user_id = t1.user_id AND
t2.status = 3
);

Count Values from Table for each type

I have the following table
UserId [nvarchar(128)], Rating [varchar(170)] :values will be mostly 1,2,3 but can have exceptions
Rating contains 3 values [1,2, or 3]
I want to get a result something like
UserId Count(1's),Count(2's) Count(3's)
1. 1001 10 8 2
2. 1002 5 10 3
Is it possible in a single query
Do a GROUP BY UserId to count for each user-id. Use CASE to count 1's, 2's and 3's separately:
select UserId,
count(case when Rating = 1 then 1 end) as [Count(1's)],
count(case when Rating = 2 then 1 end) as [Count(2's)],
count(case when Rating = 3 then 1 end) as [Count(3's)]
from tablename
group by UserId
Use a CASE statement in each COUNT and then GROUP BY UserId.
SELECT UserId, COUNT(CASE WHEN value = '1' THEN 1 END) AS [Count(1's)], COUNT(CASE WHEN value = '2' THEN 1 END) AS [Count(2's)], COUNT(CASE WHEN value = '3' THEN 1 END) AS [Count(3's)]
FROM yourtable
GROUP BY UserId
Use PIVOT:
SELECT
UserId,
COALESCE([1],0) [Count(1's)],
COALESCE([2],0) [Count(2's)],
COALESCE([3],0) [Count(3's)]
FROM
ýour_table
PIVOT
(COUNT([Rating])
FOR Rating
in([1],[2],[3])
)AS p
ORDER BY
UserId

How to GROUP BY in SQL and then mark as 0,1

I need to GROUP BY item_id and check if user_id in any of those matches a variable. If so, I want it to = 1, if not 0.
for example, imagine table like this:
item_id, user_id
1 1
1 3
2 4
2 1
2 7
2 3
3 4
3 6
4 8
4 1
5 3
IF (user_id = 3,1,0) AS match,
Want my Query to come back as
item_id, match
1 1
2 1
3 0
4 0
5 1
Where "1" all occurrences of user_id 3 in an item_id group.
You need the right aggregation function:
select item_id,
max(case when user_id = 3 then 1 else 0 end) as hasmatch
from t
group by item_id
order by item_id
In MySQL, true is 1 and false is 0, so you can just do:
SELECT item_id, MAX(user_id = 3) AS has_match
FROM table
GROUP BY 1
You can even count the number of matches:
SELECT item_id, SUM(user_id = 3) AS matches
FROM table
GROUP BY 1
GROUP BY 1 is short for GROUP BY item_id, as item_id is the first select expression.
I would do it as follows:
SELECT
A.item_id, ISNULL(B.count, 0)
FROM
(SELECT DISTINCT item_id 'item_id' FROM myTable) AS A
LEFT JOIN
(
SELECT item_id, count(*) 'count'
FROM myTable WHERE user_id IN (3, 1, 0)
GROUP BY item_id
) AS B
ON A.item_id = B.item_id