SQL inner join if not found omit condition - sql

SQL inner join if not found omit condition
Suppose I have a SQL query like:
SELECT A.* FROM Table_A A
INNER JOIN Table_B B ON A.Field1 = B.Field1 AND A.Field2 = B.Field2
WHERE A.Field3 > 10
What I'd like to achieve is, we first inner join by Field1/Field2, if no data found only join by Field1.
What's the proper way to this?
Table A:
Id Field1 Field2 Field3
1 a b 12
2 a c 13
3 e f 14
2 d c 15
Table B:
Id Field1 Field2
1 a b
2 e g
Result should be:
Id Field1 Field2 Field3
1 a b 12
3 e f 14

First part of the union is your original. Second part joins only on the first set of fields in cases where there is no match for both sets of fields.
SELECT * FROM Table_A A
INNER JOIN Table_B B ON A.Field1 = B.Field1 AND A.Field2 = B.Field2
WHERE A.Field3 > 10
UNION
SELECT * FROM Table_A A
INNER JOIN Table_B B ON A.Field1 = B.Field1
WHERE A.Field3 > 10
AND NOT EXISTS
(SELECT 1 FROM TABLE_B B2
WHERE A.Field1 = B2.Field1 AND A.Field2 = B2.Field2);

You can join on the same table twice, one with inner join and one with left join and put the conditional logic on the left join.
select distinct t1.*
from table1 t1
left join table2 t2 on t1.f2 = t2.f2
inner join table2 t3 on t1.f1 = t3.f1

You can use CASE in INNER JOIN. Just check this :
declare #a table (col1 int, col2 int, col3 int)
declare #b table (col1 int, col2 int, col3 int)
Insert into #a values(1,1,11),(2,2,15),(3,4,20),(4,5,9)
Insert into #b values(1,1,5),(2,2,2),(3,3,20),(4,5,20)
select A.* from #a A inner join #b B on
(CASE
WHEN A.col2 = B.col2 then 1
WHEN A.col2 <> B.col2 then 1
ELSE 1
END) = 1 and A.col1 = B.col1
where A.col3 > 10

You could try the following query:
SELECT ta.*
FROM #Table_A ta
INNER JOIN #Table_B tb ON ta.Field1 = tb.Field1
WHERE ta.Field3 > 10
AND
(
ta.Field2 = tb.Field2
OR
NOT EXISTS (
SELECT 1 FROM #Table_A ta2
INNER JOIN #Table_B tb2 ON ta2.Field1 = tb2.Field1 AND ta2.Field2 = tb2.Field2
WHERE ta2.Field1 = ta.Field1
)
)
Demo link: http://rextester.com/DKRG30176

;With Tab1(Id,Field1, Field2, Field3)
AS
(
SELECT 1,'a','b',12 Union all
SELECT 2,'a','c',13 Union all
SELECT 3,'e','f',14 Union all
SELECT 2,'d','c',15
)
,Tab2 (Id, Field1, Field2)
AS
(
SELECT 1,'a','b' Union ALL
SELECT 2,'e','g'
)
SELECT Id,Field1, Field2, Field3 From Tab1
EXCEPT
SELECT Id
,Field1
,Field2
,Field3
FROM (
SELECT I.Id
,i.Field1
,i.Field2
,i.Field3
,COUNT(i.Id) OVER (
PARTITION BY i.Id ,i.Field1, i.Field2 ORDER BY i.Id
) Seq
FROM Tab1 i
LEFT JOIN Tab2 o ON i.Id = o.Id
WHERE i.Field1 !=o.Field1 AND i.Field2 !=o.Field2
) Dt
WHERE Dt.Seq = 1 AND Dt.Field3 > 10
OutPut
Id Field1 Field2 Field3
---------------------------
1 a b 12
3 e f 14

Related

Fill a select with null when join isn't possible

I'm trying to do a select in n tables and show a few columns of each, but sometimes I can't match some columns and instead of getting a line with "null" the entire line is omitted.
For example:
table_a
id
...
1
2
3
table_b
id
name
...
1
a1
...
2
b2
...
3
c3
...
table_c
name
...
a1
...
And then I do the following select:
select
a.id,
c.name
from
table_a a,
table_b b,
table_c
where
( 1 = 1 )
and a.id = b.id
and b.name = c.name
I'm geting:
id
name
...
1
a1
...
I'm looking for:
id
name
...
1
a1
...
2
null
...
3
null
...
How do I do that? I checked a few answers around including this one but I didn't get how to solve it.
You can use an OUTER JOIN:
SELECT a.id,
c.name
FROM table_a a
LEFT OUTER JOIN table_b b
ON (a.id = b.id)
LEFT OUTER JOIN table_c c
ON (b.name = c.name)
or, depending on precedence of the joins:
SELECT a.id,
c.name
FROM table_a a
LEFT OUTER JOIN (
table_b b
INNER JOIN table_c c
ON (b.name = c.name)
)
ON (a.id = b.id)
Which, for the sample data:
CREATE TABLE table_a (id) AS
SELECT 1 FROM DUAL UNION ALL
SELECT 2 FROM DUAL UNION ALL
SELECT 3 FROM DUAL;
CREATE TABLE table_b (id, name) AS
SELECT 1, 'a1' FROM DUAL UNION ALL
SELECT 2, 'b1' FROM DUAL UNION ALL
SELECT 3, 'c1' FROM DUAL;
CREATE TABLE table_c (name) AS
SELECT 'a1' FROM DUAL;
Would both output:
ID
NAME
1
a1
2
null
3
null
fiddle
You should use a left join, not sure on oracle specifically but it would look something like:
select
a.id,
c.name
from
table_a a
LEFT JOIN table_b b ON (a.id = b.id)
LEFT JOIN table_c c ON (b.name = c.name)

Display the unmatched record from top table

Table 1
Col1
Col2
Date
A
B
02/25/2020
A
B
02/25/2020
A
B
03/20/2020
A
C
02/21/2020
select *
from Table1
where Date between 2020-02-20 and 2020-02-27
Table 2
Col1
Col2
Date
A
B
03/20/2020
D
E
03/20/2020
Need to compare the Table 1 to Table 2 and if col1 and col 2 values are same that records should not display from the Table 1
So the output shpuld be from Table1
Col1
Col2
Date
A
C
03/20/2020
Use an outer join:
select a.*
from Table1 a
left join Table2 b on a.col1 = b.col1
and a.col2 = b.col2
where Date between '2020-02-20' and '2020-02-27'
and b.col1 is null
whose where clause filters for rows that do not have a join.
Selecting the rows from Table1 which does not exist in Table2 based on Col1 and Col2.
SELECT * FROM Table1 T1
WHERE NOT EXISTS (
SELECT 1 FROM Table2 T2
WHERE T1.col1 = T2.col1
AND T1.col2 = T2.col2
)
AND T1.Date between '2020-02-20' and '2020-02-27'

Equally divide a field into 2

How can I equally divide the 'col' field of table 't2' with a,b,c,d as records into 2 equal fields : Col1 (a,b) & Col2 (c,d)?
Table:t2
Col
A
B
C
D
Output:
Col1 Col2
A C
B D
this is what i have tried:
SELECT a.col1, "" as col2
FROM (SELECT Top 50 Percent Col as Col1 From t2 order by Col ASc) as a
Union all
SELECT "", b.col1
FROM (SELECT top 50 Percent Col as Col1 From t2 order by Col Desc) as b
Output from above:
col1 col2
a
b
d
c
I'm only able to reach so far (in Ms access). Any help is much appreciated.
Create table 't2'
Create Table t2(Col Char)
Insert Values
INSERT INTO t2 ([Col]) VALUES ("a")
INSERT INTO t2 ([Col]) VALUES ("b")
INSERT INTO t2 ([Col]) VALUES ("c")
INSERT INTO t2 ([Col]) VALUES ("d")
Yes, you can use a crosstab if you have a sequential ID:
TRANSFORM
First(T.Col) AS Col
SELECT
([ID]+1)\2 AS DualID
FROM
(SELECT ID, [ID] Mod 2 AS ColID, [Col]
FROM YourTable) AS T
GROUP BY
([ID]+1)\2
PIVOT
T.ColID;
SELECT A1.COL1 & "-" & B1.COL1 AS PAIRS
FROM
(SELECT TOP 50 PERCENT A.Col AS COL1 FROM t2 AS A ORDER BY A.Col ASC) AS A1
INNER JOIN
(SELECT TOP 50 PERCENT B.Col AS COL1 FROM t2 AS B ORDER BY B.Col DESC) AS B1
ON A1.COL1 <> B1.COL1
WHERE (SELECT COUNT(*) FROM t2 AS C WHERE C.Col < A1.COL1) = (SELECT
COUNT(*) FROM t2 AS D WHERE D.Col > B1.COL1)

SQL Select from two tables with Prio

SELECT
t.id,
a.name
FROM table1 a, table2 t
WHERE a.id = t.id
What I actually get:
id | name
1 | Foo
1 | Bar
2 | Bar
I want the following results:
If Foo exists I want foo as result.
If Foo does not exists then Bar
So that prio 1 is foo, and prio 2 is bar.
id | name
1 | Foo
2 | Bar
Simplest way seems to be:
SELECT
t.id, a.name
FROM table1 a, table2 t
WHERE
(a.id = t.id and a.name = 'Foo')
OR
(a.id = t.id and a.name = 'Bar'
and t.id not in (SELECT id from table1 x where x.name ='Foo')
)
http://sqlfiddle.com/#!9/cb2c86/1
Simply use the following by using suggested ANSI JOIN syntax :
SELECT t.id, max(a.name) name
FROM table1 a JOIN table2 t on ( a.id = t.id )
GROUP BY t.id;
SQL Fiddle Demo
You don't actually need a join for this query:
SELECT a.id, a.name
FROM table1 a
WHERE a.name = 'Foo'
UNION ALL
SELECT a.id, a.name
FROM table1 a
WHERE a.name = 'Bar' AND
NOT EXISTS (SELECT 1 FROM table1 aa WHERE aa.id = a.id AND aa.name = 'Foo');
You can use ranking function if your DBMS support
select t.*
from (SELECT t.id, a.name,
row_number() over (partition by t.id
order by (case when a.name = 'Foo' then 0
when a.name = 'Bar' then 1
else 2
end)) Seq
FROM table1 a
inner join table2 t on a.id = t.id
) t
where Seq = 1;

MS Access - alternative to performing a "full join" for columns with same name

I have this problem using access: I am using the RIGHT + LEFT outer joins to overcome the fact that ACCESS does not support the FULL JOIN.
SELECT *
FROM T1 RIGHT OUTER JOIN T2
ON T1.xxx = T2.xxx
UNION
SELECT *
FROM T1 LEFT OUTER JOIN T2
ON T1.xxx = T2.xxx
on these tables:
T1:
ID1 | xxx | fieldA
a 1 X
b 2 Y
c 3 Z
T2:
ID2 | xxx | fieldB
d 2 K
e 3 J
f 4 H
AS a result I obtain a table with this structure
T1.xxx | T2.xxx | fieldA | fieldB | ID1 | ID2
1 X a
2 2 Y K b d
3 3 Z J c e
4 H f
xxx is not primary key but has the same name and numerical type (integer)
I saw from many other places that this should work by collapsing the two tables! Here it does not (the elements on the same rows, when non blank, are of course the same)
MY EXPECTATION
FINAL TABLE:
xxx | ID1 | ID2 |fieldA | fieldB
1 a X
2 b d Y K
3 c e Z J
4 f H
It seems that there are different set of column values for both of these 2 tables, you could be having t1.xxx and t2.xxx which have the same values, but other columns dont, the union in this case wouldn't combine these 2 records
Try something like
SELECT T1.xxx
FROM T1 RIGHT OUTER JOIN T2
ON T1.xxx = T2.xxx
UNION
SELECT T2.xxx
FROM T1 LEFT OUTER JOIN T2
ON T1.xxx = T2.xxx
Something like this should give you all the xxx values from table 1 and table 2, ignoring duplicate values for xxx.
The most likely explanation for the behavior you observe is that the rows being returned that are not identical, they are not exact duplicates.
The UNION operator will remove duplicate rows, but it doesn't do anything to "collapse tables" other than that.
To get the specified result set (in the updated question), here's one SQL pattern that would return the result. (I don't know if Access supports this, but this would work in MySQL, SQL Server, Oracle, etc.)
SELECT i.xxx
, v1.ID AS ID1
, v2.ID AS ID2
, v1.fieldA AS fieldA
, v2.fieldB AS fieldB
FROM (
SELECT t1.xxx AS xxx
FROM T1 t1
UNION
SELECT t2.xxx
FROM T2 t2
) i
LEFT
JOIN T1 v1
ON v1.xxx = i.xxx
LEFT
JOIN T2 v2
ON v2.xxx = i.xxx
(NOTE: if xxx is not guaranteed to be unique in each table, then this query could generate duplicate rows.)
MY SOLUTION (absolutely not elegant):
SELECT [QUERY1].XX, ID1, ID2, fieldA, fieldB
FROM (T2 RIGHT JOIN [QUERY1] ON T2.xxx = [QUERY1].XX) LEFT JOIN T1 ON [QUERY1].XX = T1.XX;
where QUERY1 is the following:
(SELECT CInt(NZ(T1.xxx,T2.xxx)) as XX
FROM T1 RIGHT OUTER JOIN T2
ON T1.xxx = T2.xxx
UNION
SELECT CInt(NZ(T1.xxx,T2.xxx)) as XX
FROM T1 LEFT OUTER JOIN T2
ON T1.xxx = T2.xxx)
UNION (SELECT CInt(NZ(T2.xxx,T1.xxx)) as xx1
FROM T1 RIGHT OUTER JOIN T2
ON T1.xxx = T2.xxx
UNION
SELECT CInt(NZ(T2.xxx,T1.xxx)) as xx1
FROM T1 LEFT OUTER JOIN T2
ON T1.xxx = T2.xxx);
notice that xx1 is not used, and not even shown in the table
TRY THIS ONE: I have tried and get both result sets.
DECLARE #T1 TABLE
(
ID1 VARCHAR(2) ,XXX INT, FIELDA VARCHAR(2)
)
DECLARE #T2 TABLE
(
ID2 VARCHAR(2) ,XXX INT, FIELDB VARCHAR(2)
)
INSERT INTO #T1 VALUES
('a', 1, 'X'),
('b', 2, 'Y'),
('c', 3, 'Z')
INSERT INTO #T2 VALUES
('d', 2, 'k'),
('e', 3, 'j'),
('f', 4, 'h')
SELECT
ISNULL(CONVERT(VARCHAR(1),T1.xxx),' ') AS [T1.xxx] ,
ISNULL(CONVERT(VARCHAR(1),T2.xxx),'') AS [T2.xxx] ,
ISNULL(fieldA,'') AS [fieldA],
ISNULL(fieldB,'') AS [fieldB] ,
ISNULL(ID1,'') AS [ID1] ,
ISNULL(ID2,'') AS [ID2]
FROM
(
SELECT XXX as XXX1 FROM #T1
UNION
SELECT XXX as XXX1 FROM #T2
)T LEFT OUTER JOIN
#T1 T1 ON T.XXX1 = T1.XXX
LEFT OUTER JOIN
#T2 T2 ON T.XXX1 = T2.XXX
----------------------RESULT------------------
T1.xxx T2.xxx ID1 ID2 fieldA fieldB
1 a X
2 2 b d Y k
3 3 c e Z j
4 f h
SELECT
ISNULL(CONVERT(VARCHAR(1),T.xxx1),' ') AS [xxx] ,
ISNULL(ID1,'') AS [ID1] ,
ISNULL(ID2,'') AS [ID2],
ISNULL(fieldA,'') AS [fieldA],
ISNULL(fieldB,'') AS [fieldB]
FROM
(
SELECT XXX as XXX1 FROM #T1
UNION
SELECT XXX as XXX1 FROM #T2
)T LEFT OUTER JOIN
#T1 T1 ON T.XXX1 = T1.XXX
LEFT OUTER JOIN
#T2 T2 ON T.XXX1 = T2.XXX
----------------------RESULT------------------
xxx ID1 ID2 fieldA fieldB
1 a X
2 b d Y k
3 c e Z j
4 f h