PostgreSQL: How do I join same table multiple times and take data? - sql

The table I have is this:
C1
C2
userid
1
50
100
2
40
101
3
30
102
4
20
103
5
10
104
I need the userid and count() userid WHERE (Condition satisfied)
by input
userid IN (100,101,102,103,104,105)
The condition is :
C1 > (input userid's C1) and C2 < (input userid's C2)
I need it like this :
userid
Count
100
4
101
3
102
2
103
1

Join and aggregate as the following:
SELECT D.userid, COUNT(*) cnt
FROM table_name T JOIN table_name D
ON T.C1 > D.C1 AND T.C2 < D.C2
WHERE D.userid IN (100,101,102,103,104,105)
GROUP BY D.userid
ORDER BY D.userid
See a demo.

Related

How to find most frequent code(varchar) from a table

I would like to find most frequent code within CodeID which is in same code_group from a table.
For example, from original table
ID CodeID Name Code Code_group
1 1 A 101 0
2 1 A 102 0
3 1 B 102 0
4 2 C 201 0
5 2 C 201 0
6 2 D 202 0
7 2 E 202 0
8 3 F 101 1
9 3 G 103 1
10 3 G 104 1
11 3 G 104 1
I want output like the below.
ID CodeID Name Code Code_group Selected_code
1 1 A 101 0 102
2 1 A 102 0 102
3 1 B 102 0 102
4 2 C 201 0 NULL
5 2 C 201 0 NULL
6 2 D 202 0 NULL
7 2 E 202 0 NULL
8 3 F 101 1 104
9 3 G 103 1 104
10 3 H 104 1 104
11 3 H 104 1 104
Even though code of 8th ID is same in CodeID: 1,it is not in the same Code_group.
So For CodeID: 1, Selected_code would be 102.
it must be counted within exactly same Code_group.
=======================================
I have tried it like the below. I should not use ID for this one.
From TableA
with m as
(
select
CodeID,
Name,
Code,
Code_group,
cnt,
Selected_code = ROW_NUMBER() over (partition by Code_group order by cnt desc)
from( select CodeID, Name, Code,Code_group
,count(*) over (partition by Code,CodeID) as cnt from tableA
group by CodeID, Name, Code, Code_group,
) as t
group by CodeID,
Name,
Code,
Code_group, cnt
)
select a.CodeID,
a.Name,
a.Code,
a.Code_group, b.Code as Selected_code, cnt
from(select
CodeID,
Name,
Code,
Code_group,Selected_code,
cnt
from m) as a left outer join
(select CodeID,
Name,
Code,
Code_group,Selected_code,
cnt
from m where selected_Code=1) as b on a.CodeID = b.CodeID and a.Code_Group = b.Code_Group
order by a.CodeID, a.Code_Group
The problem of this is
With statment makes my table distinct. It shows only one row if there is exactly same data such as ID 1,2.
Also, I cannot make NULL if there is exactly same frequencies.
What should I add to get my desired output?
Or is there any better approach for this?
CTE cte find the highest frequency code by Code_group and CodeID using dense_rank()
CTE selected check for any Code with same frequency and exclude them.
Final query just select from the original table and LEFT JOIN the selected
with
cte as
(
select Code_group, CodeID, Code
from
(
select Code_group, CodeID, Code,
r = dense_rank() over (partition by Code_Group, CodeID
order by count(*) desc)
from tableA
group by Code_group, CodeID, Code
) c
where c.r = 1
),
selected as
(
select Code_group, CodeID, Code
from
(
select Code_group, CodeID, Code,
cnt = count(*) over (partition by Code_group, CodeID)
from cte
) s
where s.cnt = 1
)
select a.*,
Selected_Code = s.Code
from tableA a
left join selected s on a.Code_Group = s.Code_Group
and a.CodeID = s.CodeID;
db<>fiddle demo

How to fetch rows by comparing to multiple records at same time in oracle sql

ba_no account ba_no key_id key_id child_id expiration_date sysdate
x-------------------x ------------------- ------------------------------------------------
100 1 100 23 23 1001 28-apr-20 sysdate
100 1 101 24 23 1002 28-apr-21 sysdate
101 2 102 25 23 1003 28-apr-20 sysdate
102 3 24 2000 28-apr-20 sysdate
24 2052 28-apr-20 sysdate
25 5201 28-apr-20 sysdate
A B C
I have 3 tables I want to fetch all records from table A whose all childs(child_id) in table C are expired (expiration_date<sydate) by taking join in such a way that ba_no is common in A & B and key_id is common in B & C.
You can use not exists:
select a.*
from a
where not exists (select 1
from b join
c
on b.key_id = c.key_id
where b.ba_no = a.ba_no and
c.expiration_date >= trunc(sysdate)
);
Note that this uses trunc(sysdate) because sysdate has a time component.
One option would be comparing distinctly counted child_id versus number of expired records in order to determine key_id values within the subquery, and then use these value to match the join of A and B tables to get the related values of table A :
SELECT A.*
FROM A
JOIN B
ON B.ba_no = A.ba_no
JOIN
(
SELECT C.key_id
FROM B
JOIN C
ON C.key_id = B.key_id
GROUP BY C.key_id
HAVING COUNT(DISTINCT C.child_id) =
SUM(CASE WHEN C.expiration_date < TRUNC(sysdate) THEN 1 ELSE 0 END)) BC
ON BC.key_id = B.key_id
Demo

Full outer self join or something else

MID RID Name IsVisible
100 1 AA 1
100 2 AA 0
101 1 BB 1
101 2 BB 1
102 1 CC 0
102 2 CC 0
103 1 DD 0
103 2 DD 1
How can i select distinct MID where IsVisible=0 in all RID.
Expected result is 102 which is IsVisible=0 for all RID.
The question is a bit unclear, but perhaps this is what you want...?
Do a GROUP BY, check that both max and min IsVisible = 0.
select MID
from tablename
group by MID
having max(cast(IsVisible as int)) = 0
Use NOT EXISTS
select distinct t1.mid
from your_table t1
where not exists (
select 1
from your_table t2
where t1.mid = t2.mid and t2.isVisible != 0
)

Compare Values Between Two Tables

I Have two tables, Table_A and Table_B.
I want result like the table result below, can someone help me with the SQL query?
Table_A
------------------
ID ITEM_ID QTY
------------------
1 100 2
2 101 3
3 102 5
4 103 2
------------------
Table_B
------------------
ID ITEM_ID QTY
1 100 2
2 101 4
3 102 4
4 104 2
5 105 1
------------------
RESULT
------------------
ITEM_ID QTY
100 0
101 1
102 -1
103 -2
104 2
105 1
------------------
Thanks.
You need a full join to get values from either table
select
isnull(a.item_id,b.item_id) as item_id, isnull(b.qty, 0) - isnull(a.qty, 0) as qty
from
table_a a
full outer join table_b b on a.item_id = b.item_id
select item_id, sum(qty)
from (select item_id, qty
from table_b
union all
select item_id, -qty
from table_a) x
group by item_id
order by item_id
Used full outer join and some isnulls
SQL Fiddle Example
select isnull(b.item_id, a.item_id) as ItemID,
isnull(b.qty, 0) - isnull(a.qty,0)as Qty
from table_b b
full outer join table_a a on a.item_id = b.item_id
order by itemid

How do I return the sum for this query?

I have the following tables I need to find out the sum.
Table A
ID Name
1 Jason
2 Peter
3 Ravi
Table B
ID ID_SEC
1 11
1 12
1 13
2 21
2 22
2 23
3 31
3 32
3 33
Table C
ID_SEC Value Include_Ind
11 100 Y
12 200 Y
13 300 N
21 10 Y
22 20 N
23 30 N
31 1000 N
32 2000 N
33 3000 N
Output
ID Name Total Include_Ind_count [only count when Y]
1 Jason 600 2
2 Peter 60 1
3 Ravi 6000 0
Use:
SELECT a.id,
a.name,
SUM(c.value) AS total
FROM TABLE_A a
JOIN TABLE_B b ON b.id = a.id
JOIN TABLE_C c ON c.id_sec = b.id_sec
GROUP BY a.id, a.name
The trick to counting INCLUDE_IND only when the flag is set to 'Y' is to use CASE() to test its value:
SQL> select a.id
2 , a.name
3 , sum ( c.val) as total
4 , count( case when c.include_ind = 'Y' then 1
5 else null end ) as inc_ind_cnt
6 from a
7 join b on ( b.id = a.id )
8 join c on ( c.id_sec = b.id_sec )
9 group by a.name, a.id
10 order by a.id
11 /
ID NAME TOTAL INC_IND_CNT
---------- ---------- ---------- -----------
1 Jason 600 2
2 Peter 60 1
3 Ravi 6000 0
SQL>
The ORDER BY is necessary to guarantee sort order since Oracle changed the algorithm it uses for GROUP BY operations in 10g.
You can use inner Joins and SUM for getting the result -
Assuming you tableC.Value is int field. Else you need to cast it.
SELECT tabA.id, tabA.name, SUM(tabC.value)
FROM TABLE_A tabA
INNER JOIN TABLE_B tabB ON tabB.id = tabA.id
INNER JOIN TABLE_C tabc ON tabC.id_sec = tabB.id_sec
GROUP BY tabA.id, tabA.name