Join two tables, get all results from first table - sql

So I have two tables. Let's say this is the structure of the tables:
TABLE A | TABLE B |
-----------------------------------------|
ID | div | ID | date | val |
-----------------------------------------|
A | a | A | d1 | 22 |
B | b | B | d2 | 10 |
C | c | C | d3 | 9 |
F | l | F | d1 | 10 |
What I want is to have this result:
row 1: A, a, null, null
row 2: B, b, d2, 10
row 3: C, c, null, null
row 4: F, l, d1, 10
It's a left JOIN but I want to retrieve only the values that have val = 10.
I am using SQLite. I have tried many answers from different threads without any success.

You are looking for left join:
select a.*, b.date, b.val
from a left join
b
on a.id = b.id and b.val = 10
order by a.id;

Related

Find the difference for results from two select

I have two tables:
table_1:
A | B | C
z | x | 12
z | c | 13
z | c | 10
a | s | 14
a | d | 11
table_2:
A | B | C
z | c | 10
z | x | 15
z | x | 11
a | d | 14
a | s | 12
I want to:
- group the tables by A and B
- and find the difference for SUM of C for AB.
I started with:
SELECT A, B, SUM(C) from table_1 GROUP BY A, B;
SELECT A, B, SUM(C) from table_2 GROUP BY A, B;
but I don't know how to JOIN them with adding additional column that is equal
to table_1.sum(C) - table_2.sum(c)
Expected result like:
A | B | sum1 | sum2 | diff
z | x | 12 | 26 | -14
z | c | 23 | 10 | 13
a | s | 14 | 12 | 2
a | d | 11 | 14 | -3
Use join with subquery
select X.A,X.B, sum1, sum2, sum1-sum2 as diff from
(
SELECT A, B, SUM(C) sum1
from table_1 GROUP BY A, B
)X inner join
(
SELECT A, B, SUM(C) sum2
from table_2 GROUP BY A, B
)Y on X.A=Y.A and X.B=Y.B
What do you want to happen when the groups are not the same in the two tables? inner join can be dangerous because groups will disappear.
If you want to keep all groups, then one method is union all/group by:
select a, b, sum(c1) as sum1, sum(c2) as sum2,
(sum(c2) - sum(c1)) as diff
from ((select a, b, c as c1, 0 as c2
from table_1
) union all
(select a, b, 0 as c1, c as c2
from table_2
)
) t
group by a, b

How to access TABLE C from TABLE A with meantiming values from TABLE B

We have table A, B and C
A
+----+-----+
| id | b_1 |
+----+-----+
| 1 | 51 |
| 2 | 52 |
| 3 | 53 |
| 4 | 54 |
+----+-----+
B
+----+-----+
| id | c_1 |
+----+-----+
| 51 | 71 |
| 52 | 72 |
| 53 | 73 |
| 54 | 74 |
+----+-----+
C
+----+--------+
| id | locked |
+----+--------+
| 71 | 1 |
| 72 | 0 |
| 73 | 0 |
| 74 | 1 |
+----+--------+
Now I want to do something like this:
SELECT * FROM WHERE (SELECT locked FROM C WHERE id = (SELECT c_1 FROM B WHERE id = b_1)) = 0
So the result of this pseudo code should be all the values of table A with the value locked = 0 in table C. But for this I have to jump over B and get the id pairs.
How can I do this?
You can use INNER JOINs between those tables :
select a.*
from tableA a
join tableB b on b.id = a.b_1
join tableC c on c.id = b.c_1
where c.locked = 0;
id b_1
2 52
3 53
which returns only the column values of TableA.
Demo
Here's what you need.
SELECT *
FROM A
INNER JOIN B ON (B.id = A.b_1)
INNER JOIN C ON (C.id = B.c_1)
WHERE
c.locked=0
You should use a JOIN
SELECT *
FROM A
JOIN B ON (B.A_id = A.A_id)
JOIN C ON (C.A_id = A.A_id)
I used A, B, C, to refer to the tables and table_id to refer to the FK you need to select.
This is just an example you need to adapt that to your case.
Using JOIN should do the thing :
select *
from A
join B on b.id = a.b_1
join C on c.id = b.c_1
where c.locked = '0'
https://dbfiddle.uk/?rdbms=oracle_18&fiddle=6ef50499b7bfed71f7ec9626ad196cba
Use
select A.*
if you just want table A elements.

select query joining two tables on a range

I have two tables:
Table A with columns
name | tag | price | ref
and Table B with columns:
id | time | min_ref | max_ref
I want to make the following query, take all columns from table A and columns id and time from Table B, combining rows in such a way that particular row from A is merged with a row from B if value ref from A is in the range (min_ref, max_ref). Example:
A
name | tag | price | ref
A | aaa | 78 | 456
B | bbb | 19 | 123
C | ccc | 5 | 789
B
id | time | min_ref | max_ref
0 | 26-01-2019 | 100 | 150
1 | 27-01-2019 | 450 | 525
2 | 25-01-2019 | 785 | 800
the query should return:
name | tag | price | ref | id | time
A | aaa | 78 | 456 | 1 | 27-01-2019
B | bbb | 19 | 123 | 0 | 26-01-2019
C | ccc | 5 | 789 | 2 | 25-01-2019
The notation (min_ref, max_ref) for ranges signifies exclusive bounds. Would be [min_ref, max_ref] for inclusive.
So:
select a.*, b.id, b.time
from a
join b on a.ref > b.min_ref
and a.ref < b.max_ref;
The BETWEEN predicate treats all bounds as inclusive.
I think this is just a join:
select a.*, b.id, b.time
from a join
b
on a.ref between b.min_ref and b.max_ref;
You want a JOIN which combines rows from the two tables with an appropriate criteria. For instance:
SELECT a.name, a.tag, a.price, a.ref, b.id, bi.time
FROM a
INNER JOIN b ON b.min_ref <= a.ref AND b.max_ref >= a.ref
The INNER JOIN finds matching rows from the two tables, ON a specified criteria. In this case, the criteria is that a.ref is between b.min_ref and b.max_ref.
You can also use the sql BETWEEN operator to simplify the conditionals:
SELECT ...
FROM a
INNER JOIN b ON a.ref BETWEEN b.min_ref AND b.max_ref

Access SQL: Self join without cross duplicates

Table:
Bag | Weight
------------
A | 2
B | 2
C | 3
I want to know which bags have similar weights; normally I would self-join on the Weight column; but I don't want cross duplications; that is if I have A-B, I don't want B-A.
Query:
SELECT lhs.bag, rhs.bag
FROM myTable AS lhs INNER JOIN myTable AS rhs ON lhs.weight = rhs.weight;
Result:
lhs.bag | rhs.bag
-----------------
A | A
A | B
B | B
B | A
C | C
I don't want the row B|A in the results, because similarly it has been in A|B.
Expected Table:
lhs.bag | rhs.bag
-----------------
A | A
A | B
B | B
C | C
Extend the join condition
SELECT lhs.bag, rhs.bag
FROM myTable AS lhs
INNER JOIN myTable AS rhs ON lhs.weight = rhs.weight AND
lhs.bag <= rhs.bag;

Join table 1 to either column 1 or 2 from table 2 without duplicates

[MS SQL 2008]
I have tables (all columns are string names):
A: two columns relating some datafield to an owning entity
B: three columns defining a hierarchy of entities
I need to create a singe table of the whole hierarchy (including all rows not existing in both tables), but the key column in table A (shown as Acol2) can be in either column 1 or 2 of table B...
A: B:
Acol1 | Acol2 Bcol1 | Bcol2 | Bcol3
-------+------ --------+-------+------
A | B B | X | Y
C | D Q | X | Y
E | F H | D | Z
G | H W | V | U
The output should be
Hierarchy:
Acol1 | Bcol1 | Bcol2 | Bcol3
-------+-------+-------+------
A | B | X | Y
Null | Q | X | Y
C | Null | D | Z
G | H | D | Z
E | Null | Null | Null
Null | W | V | U
Logic (also added to original):
If A has no record in B, show A with all Null
If A has record in Bcol1, show A with full row B
If A has record in Bcol2, show A with Null, Bcol2, Bcol3
If B has no record in A, show B with Null for Acol1
I have tried all sorts of UNIONs of two separate JOINs, but can't seem to get rid of extraneous rows...
B LEFT JOIN A ON Acol2=Bcol1 UNION B LEFT JOIN A ON Acol2=Bcol2;
gives duplicate rows, as the second part of the union has to set Bcol1 to NULL
(perhaps one solution is a way to remove this duplicate NULL row?)
B INNER JOIN A ON Acol2=Bcol1 UNION B INNER JOIN A ON Acol2=Bcol2;
Obviously removes all the rows from A and B that have no shared keys
(solution as to easy way to regain just those rows?)
Any idea appreciated!
To play:
[SQL removed - see fiddle in reply comments]
SELECT
Table1.ACol1,
CASE WHEN Table1.ACol1 = Table2.BCol1 THEN Table2.BCol1 ELSE NULL END AS BCol1
Table2.BCol2,
Table2.BCol3
FROM
Table1
FULL OUTER JOIN
Table2
ON Table1.ACol2 IN (Table2.BCol1, Table2.BCol2)
When you say no duplicates, this is only possible if ACol2 only ever appears in one field of one row in Table2. If it appears in multiple places, you'll get duplication.
- If that's possible, how would you want to chose which record from Table2?
Also, in general, however, this is a SQL-Anti-Pattern.
This is because the join would prefer an index on Table2. But, since you never know which field you're joining on, no single index will ever satsify the join condition.
EDIT:
What would make this significantly faster is to create a normalised TableB...
B_ID | B_Col | B_Val
------+-------+-------
1 | 1 | B
1 | 2 | X
1 | 3 | Y
2 | 1 | Q
2 | 2 | X
2 | 3 | Y
3 | 1 | H
3 | 2 | D
3 | 3 | Z
4 | 1 | W
4 | 2 | V
4 | 3 | U
Then index that table with (B_ID) and on (B_Val)...
Then include the B_ID field in the non_normalised table...
ID | Bcol1 | Bcol2 | Bcol3
------+-------+-------+-------
1 | B | X | Y
2 | Q | X | Y
3 | H | D | Z
4 | W | V | U
Then use the following query...
SELECT
Table1.ACol1,
CASE WHEN Table1.ACol1 = Table2.BCol1 THEN Table2.BCol1 ELSE NULL END AS BCol1
Table2.BCol2,
Table2.BCol3
FROM
(
Table1
LEFT JOIN
Table2Normalised
ON Table2Normalised.B_Val = Table1.ACol2
AND Table2Normalised.B_Col IN (1,2)
)
FULL OUTER JOIN
Table2
ON Table2Normalised.B_ID = Table2.ID
EDIT:
Without changing the schema, and instead having one index on BCol1 and a second index on Bcol2...
SELECT ACol1, BCol1, BCol2, BCol3 FROM Table1 a INNER JOIN Table2 b ON a.ACol2 = b.BCol1
UNION ALL
SELECT ACol1, NULL, BCol2, BCol3 FROM Table1 a INNER JOIN Table2 b ON a.ACol2 = b.BCol2
UNION ALL
SELECT ACol1, NULL, NULL, NULL FROM Table1 a WHERE NOT EXISTS (SELECT * FROM Table2 WHERE BCol1 = a.ACol2)
AND NOT EXISTS (SELECT * FROM Table2 WHERE BCol2 = a.ACol2)
UNION ALL
SELECT NULL, BCol1, BCol2, BCol3 FROM Table2 b WHERE NOT EXISTS (SELECT * FROM Table1 WHERE ACol2 = b.BCol1)
AND NOT EXISTS (SELECT * FROM Table1 WHERE ACol2 = b.BCol2)
But that's pretty messy...