Left join with a select dependent on rows value - sql

I have a table, tableA
Foo bar matcher
a b 456
c d 123
e f 789
…
And I have another very large table, tableB
Count matcher
1 123
2 456
2 123
...
From tableB I want to find details for a specific matcher
count matcher
1 123
2 123
But I just want to use the row with the maximum count
count matcher
2 123
Then I wish to left join tableB onto tableA
foo bar matcher count
a b 456 10
c d 123 2
e f 789 5
...
How do I do this?

select a.Foo, a.bar, b.matcher, max(b.Count) Count
from tableB b
left join tableA a
on a.matcher = b.matcher
group by a.Foo, a.bar, b.matcher

Related

Unique coverage between a pair of values in SQL

I want to get a distinct list of Item_IDs per vendor pair, e.g. (A,B), (A,C), (B,C)
I have a table like this:
Item_ID | vendor
123 A
123 B
133 B
456 C
I want to list ALL of the distinct Item_IDs between each pair of vendors, like below. Essentially, I want to know all of the Item_IDs which are "covered" (or present) between a pair of vendors.
Vendor1 | Vendor 2 | Item_ID
A B 123
A B 133
A C 123
A C 456
B C 123
B C 133
B C 456
I have tried using a self join, to get 2 vendors side by side, but struggling on how to list out the Item_IDs per pair.
Here is what I have so far:
select
distinct a.vendor as vendor1, b.vendor as vendor2
from table a
join table b on a.vendor != b.vendor
and a.vendor >= b.vendor -- to remove duplicate combinations
The following query works in SQL Server 2019 but I don't have the chance of testing it in Azure.
You can do:
with
v as (select distinct vendor as vendor from t)
select
a.vendor as vendor1,
b.vendor as vendor2,
x.item_id
from v a
join v b on b.vendor > a.vendor
cross apply (
select distinct item_id
from t
where t.vendor = a.vendor or t.vendor = b.vendor
) x
order by a.vendor, b.vendor
Result:
vendor1 vendor2 item_id
-------- -------- -------
A B 123
A B 133
A C 123
A C 456
B C 123
B C 133
B C 456
See running example at db<>fiddle.

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)

Using multiple joins (e.g left join)

I would like to know what's the logic for multiple joins (for example below)
SELECT * FROM B returns 100 rows
SELECT B.* FROM B LEFT JOIN C ON B.ID = C.ID returns 120 rows
As I know using left join will returns any matching data from the left table which is B if data are found for both table. But how come when using left join, it returns more data than table B itself?
What am I do wrong or misunderstood here? Any guidance are very appreciated. Thanks in advance.
Let be table B:
id
----
1
2
3
Let be table C
id name
------------
1 John
2 Mary
2 Anne
3 Stef
Any id from b is matched with ids from c, then id=2 will be matched twice. So a left join on id will return 4 rows even if base table B has 3 rows.
Now look at a more evil example:
Table B
id
----
1
2
2
3
4
table C
id name
------------
1 John
2 Mary
2 Anne
3 Stef
Every id from b is matched with ids from c, then first id=2 will be matched twice and second id=2 will be matched twice so the result of
select b.id, c.name
from b left join c on (b.id = c.id)
will be
id name
------------
1 John
2 Mary
2 Mary
2 Anne
2 Anne
3 Stef
4 (null)
The id=4 is not matched but appears in the result because is a left join.
Look at the following example :
B = {1,2}
C = {(1,a),(1,b),(1,c),(1,d),(1,e)}
The result of B left join C will be :
1 | a
1 | b
1 | c
1 | d
1 | e
2 | null
The number of rows in the result is definitely larger than rows in B (2).
In general the number of rows in result of B left join C is bounded by B.size + C.size and not only by B.size as you think...
As per your query it do the join to B Table with C and B table is Left Table so it will display all the records of Left table in our case it is B and related from other Table in our Case it is C.

Sql Inner Join first record only if Exists Take Next one

This one is support hard for me. I can do inner join with first result only, but if exist I want take 2nd result.
THIS IS MY TABLE A
ID NAME VALUE
1 A 123
2 B 456
3 C 789
4 A 456
TABLE B
BID BNAME BVALUE
1 A ABC
2 A CDE
3 B 845
4 C 1234
MY SELECT SQL:
SELECT * FROM A
CROSS APPLY (
SELECT TOP 1 *
FROM B
WHERE A.Name = B.BName
) BB
It return
1 A 123 1 A ABC
2 B 456 3 B 845
3 C 789 4 C 1234
4 A 456 1 A ABC
Please help, I want this result:
1 A 123 1 A ABC
2 B 456 3 B 845
3 C 789 4 C 1234
4 A 456 2 A CDE
I accept tmp table and any kind of query :(
Following clarification in the comments that both tables will always have matching rows.
WITH A
AS (SELECT *,
ROW_NUMBER() OVER (PARTITION BY NAME ORDER BY ID) AS RN
FROM TableA),
B
AS (SELECT *,
ROW_NUMBER() OVER (PARTITION BY BNAME ORDER BY BID) AS RN
FROM TableB)
SELECT A.ID,
A.NAME,
A.VALUE,
B.BID,
B.BNAME,
B.BVALUE
FROM A
JOIN B
ON A.NAME = B.BNAME
AND A.RN = B.RN

T-SQL Select all from TableA and condition on TableB

TableA Columns: A_ID, NAME, SOURCE, TITLE, EVENTID
TableB Columns: B_ID, EVENTID, CODE, FIELD
How do I extract NAME, SOURCE, TITLE and FIELD or null (if there is CODE=x) ? Example should show it better. It's T-SQL on SQL Server Express.
Example:
TableA | TableB
-----------------------------------------------------------------------
A_ID, NAME, SOURCE, TITLE, EVENTID | B_ID, EVENTID, CODE, FIELD
-----------------------------------------------------------------------
1 john s1 x 100 | 1 100 5 textA
2 bruce s2 y 105 | 2 100 10 textB
3 bob s3 z 110 | 3 105 5 textC
| 4 110 5 textD
| 5 110 10 textE
There is no code 10 for EventId 105 so the result should be null. How do write a SELECT quesry that would give me such result:
[ john | s1 | x | textB ]
[ bruce | s2 | y | ]
[ bob | s3 | z | textE ]
It might be really easy but I can't figure it out.. Thanks in advance.
You need an OUTER JOIN between the tables
SELECT A.NAME,
A.SOURCE,
A.TITLE,
B.FIELD
FROM TableA A
LEFT JOIN TableB B
ON A.EVENTID = B.EVENTID
AND B.CODE = 10
The B.CODE = 10 condition needs to go in the JOIN not a WHERE clause to avoid effectively turning the query back into an INNER JOIN.
This can return multiple rows for a particular A value if there is more than one joining record but it is not clear from your question if this is possible in your data anyway (and if so which B.Field value should be used) and this may well be your desired behaviour.
This should do it
SELECT a.NAME, a.SOURCE, a.TITLE, b.FIELD
FROM TableA a
LEFT JOIN TableB b ON b.EventId = a.EventId
AND b.Code = 10