How to get the number of occurrences in another table - sql

If I have TABLE_A:
A_ID B_ID
1 6
2 6
3 7
4 7
5 7
and TABLE_B:
B_ID B_NAME
6 B1
7 B2
8 B3
9 B4
How can I find the number of occurrences of B_ID in TABLE_A? Something like this:
select B_ID, B_NAME, total_count from TABLE_B
Where "total_count" is the number of times B_ID is found in TABLE_A so that the result would be:
B_ID B_NAME total_count
6 B1 2
7 B2 3
8 B3 0
9 B4 0

Use group by, left join and count:
SELECT B.B_ID, B.B_NAME, COUNT(A.A_Id) As TotalCount
FROM TableB As B
LEFT JOIN TableA As A
ON B.B_ID = A.B_ID
GROUP BY B.B_ID, B.B_NAME
This is quite a basic query in SQL, and should produce the same result on most if not all relational databases.

Related

How to calculate rank with group by in sql?

Suppose if I have table1 as following
Category Brand Value
A A1 4
B B1 7
C C1 8
A A2 3
B B2 4
C C2 6
A A3 9
B B3 10
C C3 1
A A4 5
Now if I want to calculate rank for each brand but grouped by category how do I go about it?
Something like
Select rank() (over value)
from table
group by category
Expected output is this:
Category Brand Value Rank
A A3 9 1
A A4 5 2
A A1 4 3
A A2 3 4
B B3 10 1
B B1 7 2
B B2 4 3
C C1 8 1
C C2 6 2
C C3 1 3
Maybe you are looking for something like this.
See this official documentation on DENSE_RANK for more details
select brand, category, dense_rank() over(partition by category order by value desc) as dr
from table
You may add a PARTITION BY clause to your RANK() call, specifying the category as the partition.
SELECT RANK() OVER (PARTITION BY category ORDER BY value) rnk
FROM yourTable
ORDER BY category, rnk;

Nested group by with conditional query

I have 3 tables:
table: a
id name
2 A
3 B
table: b
id a b
3 2 Asd Ter Gsdt
4 2 Gsd Gsdt Gsda
5 2 Asd Gsd
6 3 Uty Kggs
7 3 Tyud Hffddf
table: c
id a b
6 3 d
7 3 a
8 3 g
9 3 h
10 4 j
11 5 y
12 5 s
13 6 d
14 6 h
expected output:
a b c d
A 2019-04-06 3 a
B 2019-04-06 6 b
I am unsure how to proceed from this, how?
This query do the job, but there is always a question about speed and performance.
select a.name,
(select c_date from c
join b on (c.b_id = b.id)
where b.a = a.id order by c_date desc limit 1) last_c_date,
popular.b_id,
(select photos->0 from b where id = popular.b_id) photo
from a
join (
select distinct on (a)
b.id b_id, a from b
join c on (b.id = c.b_id)
group by b.id, a
order by a, count(*) desc, b.id
) popular on (popular.a = a.id)
order by a.name
If there will be 2 equaly popular b objects in a region, query takes this with smaller id.
If it will be no b object with entries in c than subquery for photo can be surrounded with coalesce (but now it should work too with null value).

How to get rows having uncommon values in two tables in SQL?

Suppose I have a table a with columns A1,A2,A3,A4 and table b with columns B1,B2,B3,B4.
I want to find a records which are having different values in column A1,A2 and B1,B2
Ex.
A1 A2 A3 A4 B1 B2 B3 B4
12 10 10 12 12 10 10 12
14 14 10 12 15 10 10 12
15 10 10 10 15 10 10 10
IT SHOULD RETURN
14 14 10 10
I tried:
SELECT A1,A2
FROM A
EXCEPT
SELECT B1,B2
FROM B;
However, it returned on A1,A2 columns instead of all columns
use left join
select a.* from tableA a
left join tbaleB b
on a.A1=b.B1 and a.A2=b.B2 and a.A3=b.B3 and a.A4=b.B4
where b.B1 is null
You can try below using left join
select * from tableA
left join tableB on A1=B1 and A2=B2
where B1 is null and B2 is null
I would use not exists:
select a.*
from a
where not exists (select 1
from b
where a.a1 = b.b1 and a.a2 = b.b2
);

SQL apply different where condition (filter) for each group in table

i have following SQL table A in my database:
index, group, foo
1 A 2
2 A 2
3 A 0
4 A 1
5 B 2
6 B 1
7 C 1
There are few more groups and I need to write a query based on this filter table B. For each group in table A it's index should be equal or greater than index_egt from table B for the same group.
If the group is not listed in table B, the group won't be filtered.
index_egt, group
3 A
5 B
Expected result:
index, group, foo
3 A 0
4 A 1
5 B 2
6 B 1
7 C 1
Try this, the A.index>=B.index_egt will handle cases where the group is listed in TableB and the B.index_egt IS NULL will handle cases where the group is not listed:
SELECT
A.index,
A.group,
A.foo
FROM TableA AS A
LEFT JOIN TableB AS B ON A.group=B.group
WHERE A.index>=B.index_egt
OR B.index_egt IS NULL
select
a.*
from
A a
left join
B b ON b.group = a.group
where
a.index >= b.index_egt OR b.index_egt IS NULL
I always like this trick with coalesce
SELECT a.*
FROM a_table_with_no_name a
LEFT JOIN b_table_with_no_name b ON b.group = a.group
WHERE a.index >= COALESCE(b.index_egt,a.index)

SQL nested sums with multiple joins and group by

I'm not very familiar with SQLs. I'm using oracle. I met a question with over summing fields.
Here are the example tables:
A:
A_ID
A_NAME
B:
B_ID
A_ID
B_NAME
B_QTY
C:
C_ID
B_ID
C_QTY
So the data structure is like A -> *B -> *C
I need to get the total quantities of Bs and Cs grouped by B_NAME and A_ID. For example:
A:
A_ID A_NAME
1 A1
B:
B_ID A_ID B_NAME B_QTY
1 1 B1 20
2 1 B1 5
3 1 B1 5
4 1 B2 5
C:
C_ID B_ID C_QTY
1 1 3
2 1 4
4 2 2
5 2 1
6 3 1
7 4 1
The expected result is:
A_ID A_NAME B_NAME B_QTY C_QTY
1 A1 B1 30 11
1 A1 B2 5 1
The 30 of B_QTY in the 1st line is result of 20 + 5 + 5.
The 11 of C_QTY in the 1st line is result of 3 + 4 + 2 + 1 + 1.
Here is my sql:
select a.A_ID,
a.A_NAME,
b.B_NAME
sum(b.B_QTY),
sum(c.C_QTY)
from A a left outer join B b on b.A_ID = a.A_ID
left outer join C c on c.B_ID = b.B_ID
group by a.A_ID
order by a.A_ID, b.B_NAME
where a.XXXX = XXXXX;
So the problem is:
Since the B mapps to multiple Cs, the B_QTY will be summed multiple times. I'm not very familiar with SQL so I don't know if there is any simple way to distict the summing based on some fields (which is B_ID in my example). Thank you!
This can also be done like this:
WITH b2 AS
(SELECT b.*, sum(b.b_qty) over (partition BY b.a_id, b.b_name) b_qty_s
FROM b)
SELECT a.a_id, a.a_name, b2.b_name, b2.b_qty_s, sum(c.c_qty) c_qty_s
FROM a JOIN b2 ON a.a_id = b2.a_id
JOIN c ON b2.b_id = c.b_id
GROUP BY a.a_id,a.a_name, b2.b_name, b2.b_qty_s
Here is a sqlfiddle demo
You can also do like this:
SELECT DISTINCT A_ID,A_NAME,B_NAME,B_SUM,SUM(C_QTY) OVER(PARTITION BY A_NAME,B_NAME) C_SUM
FROM (
SELECT A.A_ID,A_NAME,B_NAME,B_ID,SUM(B_QTY) OVER(PARTITION BY A_NAME,B_NAME) B_SUM
FROM A JOIN B
ON A.A_ID=B.A_ID) T1
JOIN C
ON T1.B_ID=C.B_ID
I created an SQL fiddle for this problem. The trick is that the B_QTY was appearing in your results more than once. Summing on it was giving an artificially high value. So instead, run a sub select to use the B_NAME only once! Great question! :^D
A.B.Cade's answer is cool, but this solution will work for many databases. I've used this technique before with SQL Server, Oracle, and Informix.
Data/Schema:
create table a (A_ID int, A_NAME char(10));
create table b (B_ID int, A_ID int, B_NAME char(10), B_QTY int);
create table c (C_ID int, B_ID int, C_QTY int);
-- One dude
insert into a values (1,'Xiezi');
-- 2 orders? of 4 and 3
insert into b values (1,1,'B1',20);
insert into b values (2,1,'B1',5);
insert into b values (3,1,'B1',5);
insert into b values (4,1,'B2',5);
-- 2 order with 2 lines each.
insert into c values (1,1,3);
insert into c values (2,1,4);
insert into c values (4,2,2);
insert into c values (5,2,1);
insert into c values (6,3,1);
insert into c values (7,4,1);
SQL (The answer):
select a.A_ID,
a.A_NAME,
b.B_NAME,
(select sum(b2.B_QTY) from b b2 where b2.B_NAME = b.B_NAME)
as sum_b_qty,
sum(c.C_QTY)
from a left outer join b on b.A_ID = a.A_ID
left outer join c on c.B_ID = b.B_ID
group by a.A_ID,
a.A_NAME,
b.B_NAME
order by a.A_ID
;
Output:
A_ID A_NAME B_NAME SUM_B_QTY SUM(C.C_QTY)
1 Xiezi B1 30 11
1 Xiezi B2 5 1