link between two tables - sql

I have two tables:
TableA which contains description of all products :
codeProduct description
1 ok
2 yes
TableB contains hierarchy between products only with codes :
level_1 level_2 level_3 level_4
1 2 23 75
1 2 53 85
How could I get a final table that contains for each level the description
level_1 description_1 level_2 description_2 level_3 description_3 level_4 description_4

You need use of tableA several time each time you need a value for a column in tableB
select b.level_1
, a1.description description_1
, b.level_2
, a2.description description_2
, b.level_3
, a3.description description_3
, b.level_4
, a4.description description_4
from TableB b
left join TableA a1 on a1.codeProduct = b.level_1
left join TableA a2 on a2.codeProduct = b.level_2
left join TableA a3 on a3.codeProduct = b.level_3
left join TableA a4 on a4.codeProduct = b.level_4
use left join if you not all matching value between the two tables or INNER JOIN if you have all the macthing values
select b.level_1
, a1.description description_1
, b.level_2
, a2.description description_2
, b.level_3
, a3.description description_3
, b.level_4
, a4.description description_4
from TableB b
INNER join TableA a1 on a1.codeProduct = b.level_1
INNER join TableA a2 on a2.codeProduct = b.level_2
INNER join TableA a3 on a3.codeProduct = b.level_3
INNER join TableA a4 on a4.codeProduct = b.level_4

Try this:
CREATE TABLE #TABLEA
(
CODEPRODUCT INT NOT NULL
, DESCRIPTION VARCHAR (100) NOT NULL
);
INSERT INTO #TABLEA VALUES (1, 'ok') ;
INSERT INTO #TABLEA VALUES (2, 'yes');
CREATE TABLE #TABLEB
(
LEVEL_1 INT NOT NULL
, LEVEL_2 INT NOT NULL
, LEVEL_3 INT NOT NULL
, LEVEL_4 INT NOT NULL
);
INSERT INTO #TABLEB VALUES(1, 2, 23, 75) , (1, 2, 53, 85);
SELECT #TABLEB.LEVEL_1
, TA_L1.DESCRIPTION AS DESCRIPTION1
, #TABLEB.LEVEL_2
, TA_L2.DESCRIPTION AS DESCRIPTION2
, #TABLEB.LEVEL_3
, TA_L3.DESCRIPTION AS DESCRIPTION3
, #TABLEB.LEVEL_4
, TA_L4.DESCRIPTION AS DESCRIPTION4
FROM #TABLEB
LEFT JOIN #TABLEA TA_L1
ON #TABLEB.LEVEL_1 = TA_L1.CODEPRODUCT
LEFT JOIN #TABLEA TA_L2
ON #TABLEB.LEVEL_2 = TA_L2.CODEPRODUCT
LEFT JOIN #TABLEA TA_L3
ON #TABLEB.LEVEL_3 = TA_L3.CODEPRODUCT
LEFT JOIN #TABLEA TA_L4
ON #TABLEB.LEVEL_4 = TA_L4.CODEPRODUCT;
Result:
LEVEL_1, DESCRIPTION1, LEVEL_2, DESCRIPTION2, LEVEL_3, DESCRIPTION3, LEVEL_4, DESCRIPTION4
1 ok 2 yes 23 NULL 75 NULL
1 ok 2 yes 53 NULL 85 NULL

Related

Mapeate values from a row that poins out several FK to the same table

Table 1
ID EXTERNALCODE Brand_T Brand_E Brand_C
1 569859 1 2 3
2 545479 4 2 5
Brands have the same Foreign Key to table 2, they are IDs of table 2.
Table 2
ID Brand_Code
1 eee
2 465656
3 456U99
4 4OREFUOREFJ9
5 r56
FINAL RESULT SHOULD BE:
ID EXTERNALCODE Brand_Code
1 569859 eee
1 569859 465656
1 569859 456U99
2 545479 4OREFUOREFJ9
2 545479 465656
2 545479 r56
What I have tried:
Select
Table1.Id
,Table1.EXTERNALCODE
,Table2.Brand_Code as Brand_Code
,T2_E.Brand_Code as Brand_Code
,T2_C.Brand_Code as Brand_Code
FROM
Table2 Left join Table1 ON Table2.Id = Table1.Brand_T
Table2 Left join Table1 ON Table2.Id = Table1.Brand_E
Table2 Left join Table1 ON Table2.Id = TabLe1.Brand_C
But this query is giving many duplicates.
Since you can't fix the normalization issue you could query against your existing structures something like this.
declare #Table1 table
(
ID int
, EXTERNALCODE int
, Brand_T int
, Brand_E int
, Brand_C int
)
insert #Table1 values
(1, 569859, 1, 2, 3)
, (2, 545479, 4, 2, 5)
declare #Table2 table
(
ID int
, Brand_Code varchar(50)
)
insert #Table2 values
(1, 'eee')
, (2, '465656')
, (3, '456U99')
, (4, '4OREFUOREFJ9')
, (5, 'r56')
select t1.Id
, t1.EXTERNALCODE
, t2.Brand_Code
from #Table1 t1
join #Table2 t2 ON t2.ID in (t1.Brand_T, t1.Brand_E, t1.Brand_C)

Get exact match between two table

I have a issue that is hard to explain. I have two tables
table1: (this is something like shipping table)
ID ShippingId ProductId1 ProductId2
1 100 A A1
2 100 A A2
3 100 A A3
4 100 A A4
5 100 A A5
6 200 B B1
7 200 B B2
8 300 B A1
9 300 B A2
table2: (and this is about relation between ProductId1 and ProductId2)
ID ProductId1 ProductId2
1 A A1
2 A A2
3 A A3
4 A A4
5 A A5
6 B B1
7 B B2
In the case the shipment "100" includes all items of "A" so this should "true"
and the shipments "200" and "300" does not include all parts of their main products. So expected output should be like
ShippingId ProductId1 IsIncludeAll
100 A true
200 B false
300 A true
can you guys help me?
DECLARE #table1 AS TABLE
(
ShippingID INT,
ProductId1 INT,
ProductId2 INT
)
DECLARE #table2 AS TABLE
(
ProductId1 INT,
ProductId2 INT
)
INSERT INTO #table1 (ShippingId,ProductId1,ProductId2) VALUES (100,111, 1119)
INSERT INTO #table1 (ShippingId,ProductId1,ProductId2) VALUES (100,111, 1118)
INSERT INTO #table1 (ShippingId,ProductId1,ProductId2) VALUES (100,111, 1117)
INSERT INTO #table1 (ShippingId,ProductId1,ProductId2) VALUES (100,111, 1116)
INSERT INTO #table1 (ShippingId,ProductId1,ProductId2) VALUES (100,111, 1115)
INSERT INTO #table1 (ShippingId,ProductId1,ProductId2) VALUES (200,222, 2229)
INSERT INTO #table1 (ShippingId,ProductId1,ProductId2) VALUES (200,222, 2228)
INSERT INTO #table1 (ShippingId,ProductId1,ProductId2) VALUES (300,111, 1117)
INSERT INTO #table1 (ShippingId,ProductId1,ProductId2) VALUES (300,111, 1116)
INSERT INTO #table2 (ProductId1,ProductId2) VALUES ( 111, 1119)
INSERT INTO #table2 (ProductId1,ProductId2) VALUES ( 111, 1118)
INSERT INTO #table2 (ProductId1,ProductId2) VALUES ( 111, 1117)
INSERT INTO #table2 (ProductId1,ProductId2) VALUES ( 111, 1116)
INSERT INTO #table2 (ProductId1,ProductId2) VALUES ( 111, 1115)
INSERT INTO #table2 (ProductId1,ProductId2) VALUES ( 222, 2229)
INSERT INTO #table2 (ProductId1,ProductId2) VALUES ( 222, 2228)
ShippingId ProductId1 IsIncludeAll
100 A true
200 B false
300 A false
A total guess, as the sample DDL and DML don't match the sample data, but perhaps this?
SELECT S.ShippingID,
T2.ProductId1,
CASE COUNT(CASE WHEN T1.ProductId2 IS NULL THEN 1 END) WHEN 0 THEN 'true' ELSE 'false' END AS IsIncludeAll
FROM #table2 T2
CROSS APPLY (SELECT DISTINCT
sq.ShippingID,
sq.ProductId1
FROM #table1 sq
WHERE sq.ProductId1 = T2.ProductId1) S
LEFT JOIN #table1 T1 ON T2.ProductId1 = T2.ProductId1
AND T1.ProductId2 = T2.ProductId2
AND S.ShippingID = T1.ShippingID
GROUP BY S.ShippingID,
T2.ProductId1;
Little confused on your sample data and output. From my thought Check this query and output.
------Step 1. concatenate product1 and product2 with ShippingID wise,product1 wise order by ShippingID,ProductId1,ProductId2-------------------
declare #Shipping as table
(
ShippingID INT,
ProductId1 INT,
ProductDesc varchar(max)
)
insert #Shipping
SELECT Shipping.ShippingID,Shipping.ProductId1,
LEFT(Shipping.prod_desc,Len(Shipping.prod_desc)-1) As prod_desc
FROM
(
SELECT DISTINCT T2.ShippingID, T2.ProductId1,
(
SELECT cast(T1.ProductId1 as varchar(10))+'-' +cast(T1.ProductId2 as varchar(10))+ '|' AS [text()]
FROM dbo.table1 T1
WHERE T1.ShippingID = T2.ShippingID and T1.ProductId1=T2.ProductId1
ORDER BY T1.ShippingID,ProductId1,ProductId2
FOR XML PATH ('')
) prod_desc
FROM dbo.table1 T2
) Shipping
------Step 2. concatenate product1 and product2 with product1 wise order by ProductId1,ProductId2-------------------
declare #relation as table
(
ProductId1 INT,
ProductDesc varchar(max)
)
insert #relation
SELECT relation.ProductId1,LEFT(relation.prod_desc,Len(relation.prod_desc)-1) As prod_desc
FROM
(
SELECT DISTINCT T2.ProductId1,
(
SELECT cast(T1.ProductId1 as varchar(10))+'-' +cast(T1.ProductId2 as varchar(10))+ '|' AS [text()]
FROM dbo.table2 T1
WHERE T1.ProductId1=T2.ProductId1
ORDER BY ProductId1,ProductId2
FOR XML PATH ('')
) prod_desc
FROM dbo.table2 T2
) relation
------Step 1. use left join to match with concatinated string of every product1. if matches return True otherwise False-------------------
select a.ShippingID,a.ProductId1,case when b.ProductDesc is null then 'False' else 'True' end as IsIncludeAll
from #Shipping a
left join #relation b
on a.ProductId1=b.ProductId1 and a.ProductDesc=b.ProductDesc
-----Result-----------
------------+---------------+--------------
ShippingID | ProductId1 | IsIncludeAll
------------+---------------+--------------
100 | 111 | True
200 | 222 | True
300 | 111 | False

SQL Statement with 3 select statements

I am trying to combine the data of three tables but running into a minor issue.
Let's say we have 3 tables
Table A
ID | ID2 | ID3 | Name | Age
1 2x 4y John 23
2 7j Mike 27
3 1S1 6HH Steve 67
4 45 O8 Carol 56
Table B
| ID2 | ID3 | Price
2x 4y 23
7j 8uj 27
x4 Q6 56
Table C
|ID | Weight|
1 145
1 210
1 240
2 234
2 110
3 260
3 210
4 82
I want to get every record from table A of everyone who weighs 200 or more but they cannot be in table B. Table A and C are joined by ID. Table A and B are joined by either ID2 or ID3. ID2 and ID3 don't both have to necessarily be populated but at least 1 will. Either can be present or both and they will be unique. So expected result is
3 | 1S1 | 6HH | Steve| 67
Note that a person can have multiple weights but as long as at least one record is 200 or above they get pulled.
What I have so far
Select *
From tableA x
Where
x.id in (Select distinct y.id
From tableA y, tableC z
Where y.id = z.id
And z.weight >= '200'
And y.id not in (Select distinct h.id
From tableA h, tableB k
Where (h.id2 = k.id2 or h.id3 = k.id3)))
When I do this it seems to ignore the check on tableB and I get John, Mike and Steve. Any ideas? Sorry it's convoluted, this is what I have to work with. I am doing this in oracle by the way.
This sounds like exists and not exists. So a direct translation is:
select a.*
from tableA a
where exists (select 1 from tableC c where c.id = a.id and c.weight >= 200) and
not exists (select 1 from tableB b where b.id2 = a.id2 or b.id3 = a.id3);
Splitting the or into two separate subqueries can often improve performance:
select a.*
from tableA a
where exists (select 1 from tableC c where c.id = a.id and c.weight >= 200) and
not exists (select 1 from tableB b where b.id2 = a.id2) and
not exists (select 1 from tableB b where b.id3 = a.id3);
Here's what I came up with.
SELECT DISTINCT
A.ID,
A.ID2,
A.ID3,
A.Name,
A.Age
FROM
A
LEFT OUTER JOIN C ON C.ID = A.ID
LEFT OUTER JOIN B ON
B.ID2 = A.ID2
OR B.ID3 = A.ID3
WHERE
C.Weight >= 200
AND B.Price IS NULL
BELOW is test data
CREATE TABLE A
(
ID INT,
ID2 VARCHAR(3),
ID3 VARCHAR(3),
Name VARCHAR(10),
Age INT
);
INSERT INTO A VALUES (1, '2x', '4y', 'John', 23);
INSERT INTO A VALUES (2, '7j', NULL , 'Mike', 27);
INSERT INTO A VALUES (3, '1S1', '6HH', 'Steve', 67);
INSERT INTO A VALUES (4, '45', 'O8', 'Carol', 56);
CREATE TABLE B
(
ID2 VARCHAR(3),
ID3 VARCHAR(3),
Price INT
);
INSERT INTO B VALUES ('2x', '4y', 23);
INSERT INTO B VALUES ('7j', '8uj', 27);
INSERT INTO B VALUES ('x4', 'Q6', 56);
CREATE TABLE C
(
ID INT,
Weight INT
);
INSERT INTO C VALUES (1, 145);
INSERT INTO C VALUES (1, 210);
INSERT INTO C VALUES (1, 240);
INSERT INTO C VALUES (2, 234);
INSERT INTO C VALUES (2, 110);
INSERT INTO C VALUES (3, 260);
INSERT INTO C VALUES (3, 210);
INSERT INTO C VALUES (4, 82);
Select a.id, a.id2, a.id3
From table_a a
Left join table_c c on a.id = c.id
Where c.weight >=200
And not exists
(Select 1
From table_b b
Where a.id = b.id2
Or a.id = b.id3
);
I was beating to the answers, but I used INNER JOIN on tables a and c and a NOT EXISTS on table b.
--This first section is creating the test data
with Table_A (id, id2, id3, Name, age) as
(select 1, '2x', '4y', 'John', 23 from dual union all
select 2, '7j', null, 'Mike', 27 from dual union all
select 3, '1S1', '6HH', 'Steve', 67 from dual union all
select 4, '45', 'O8', 'Carol', 56 from dual),
Table_B(id2, id3, price) as
(select '2x', '4y', 23 from dual union all
select '7j', '8uj', 27 from dual union all
select 'x4', 'Q6', 56 from dual),
Table_C(id, weight) as
(select 1, 145 from dual union all
select 1, 210 from dual union all
select 1, 240 from dual union all
select 2, 234 from dual union all
select 2, 110 from dual union all
select 3, 260 from dual union all
select 3, 210 from dual union all
select 4, 82 from dual)
--Actual query starts here
select distinct a.*
from table_a a
--join to table c, include the weight filter
inner join table_c c on (a.id = c.id and c.weight >= 200)
where not exists -- The rest is the NOT EXISTS to exclude the values in table b
(select 1 from table_b b
where a.id2 = b.id2
or a.id3 = b.id3);

Full Outer Join on Incomplete Data (by id variable)

I have two tables (see example data below). I need to keep all of the ID values in table 1 and merge table 1 with table 2 by sequence. The tricky part is that I also have to retain the field value1 from table 1 and value2 from table 2.
table 1 :
ID sequence value1
-------------------------
p1 1 5
p1 2 10
p2 1 15
p2 2 20
table 2 :
sequence value2
-------------------------
1 10
2 20
3 30
4 40
I need the resulting table to appear like so:
ID sequence value1 value2
----------------------------------
p1 1 5 10
p1 2 10 20
p1 3 - 30
p1 4 - 40
p2 1 15 10
p2 2 20 20
p2 3 - 30
p2 4 - 40
I have tried the following sql code, but it doesn't merge the missing values from from value1 field in table 1 and merge it with the values2 field from table 2
select t1.ID, t2.sequence, t1.value1, t2.value2 from
t2 full outer join t1 on t2.sequence=t1.sequence
Any assistance you can provide is greatly appreciated.
You can try something like this:
select coalesce(t1.[id], t3.[id]),
, t2.[sequence]
, t1.[value]
, t2.[value]
from [tbl2] t2
left join [tbl1] t1 on t1.[sequence] = t2.[sequence]
left join (select distinct [id] from [tbl1]) t3 on t1.[id] is null
SQLFiddle
One way with CROSS JOIN and OUTER APPLY:
DECLARE #t1 TABLE(ID CHAR(2), S INT, V1 INT)
DECLARE #t2 TABLE(S INT, V2 INT)
INSERT INTO #t1 VALUES
('p1', 1, 5),
('p1', 2, 10),
('p2', 1, 15),
('p2', 2, 20)
INSERT INTO #t2 VALUES
(1, 10),
(2, 20),
(3, 30),
(4, 40)
SELECT c.ID, t2.S, ca.V1, t2.V2 FROM #t2 t2
CROSS JOIN (SELECT DISTINCT ID FROM #t1) c
OUTER APPLY(SELECT * FROM #t1 t1 WHERE c.ID = t1.ID AND t1.S = t2.S) ca
ORDER BY c.ID, t2.S
Output:
ID S V1 V2
p1 1 5 10
p1 2 10 20
p1 3 NULL 30
p1 4 NULL 40
p2 1 15 10
p2 2 20 20
p2 3 NULL 30
p2 4 NULL 40
Given this schema:
create table #table_1
(
ID varchar(8) not null ,
sequence int not null ,
value int not null ,
primary key clustered ( ID , sequence ) ,
unique nonclustered ( sequence , ID ) ,
)
create table #table_2
(
sequence int not null ,
value int not null ,
primary key clustered ( sequence ) ,
)
go
insert #table_1 values ( 'p1' , 1 , 5 )
insert #table_1 values ( 'p1' , 2 , 5 )
insert #table_1 values ( 'p2' , 1 , 15 )
insert #table_1 values ( 'p2' , 2 , 20 )
insert #table_2 values ( 1 , 10 )
insert #table_2 values ( 2 , 20 )
insert #table_2 values ( 3 , 30 )
insert #table_2 values ( 4 , 40 )
go
This should get you what you want:
select ID = map.ID ,
sequence = map.sequence ,
value1 = t1.value ,
value2 = t2.value
from ( select distinct
t1.ID ,
t2.sequence
from #table_1 t1
cross join #table_2 t2
) map
left join #table_1 t1 on t1.ID = map.ID
and t1.sequence = map.sequence
join #table_2 t2 on t2.sequence = map.sequence
order by map.ID ,
map.sequence
go
Producing:
ID sequence value1 value2
== ======== ====== ======
p1 1 5 10
p1 2 5 20
p1 3 - 30
p1 4 - 40
p2 1 15 10
p2 2 20 20
p2 3 - 30
p2 4 - 40

SQL OUTER JOIN: "partial NULL"-rows wanted

I'm looking for a way to archive the following:
Imagine Tables A, B:
A:
aID, aID2, avalue
=================
1 , 10 , 'abc'
2 , 20 , 'def'
3 , 30 , 'ghi'
4 , 40 , 'jkl'
B:
bID, bID2, bvalue
=================
1 , 10 , 'mno'
20 , 20 , 'pqr'
3 , 1 , 'stu'
Now look at the following SQL statement and results (I'm on Oracle 11, but should be the same for MSSQL):
SELECT A.*, B.* FROM A LEFT OUTER JOIN B ON (A.aID = B.bID)
aID, aID2, avalue, bID , bID2, bvalue
=====================================
1 , 10 , 'abc' , 1 , 10 , 'mno'
2 , 20 , 'def' , NULL, NULL, NULL
3 , 30 , 'ghi' , 3 , 1 , 'stu'
4 , 40 , 'jkl' , NULL, NULL, NULL
SELECT A.*, B.* FROM A LEFT OUTER JOIN B ON (A.aID = B.bID AND A.aID2 = B.bID2)
aID, aID2, avalue, bID , bID2, bvalue
=====================================
1 , 10 , 'abc' , 1 , 10 , 'mno'
2 , 20 , 'def' , NULL, NULL, NULL
3 , 30 , 'ghi' , NULL, NULL, NULL
4 , 40 , 'jkl' , NULL, NULL, NULL
Fine so far.
I'm looking for a statement (as easy as possible), that gets me the following:
MADE-UP-CODE: SELECT A.*, B.* FROM A LEFT OUTER JOIN B ON (A.aID = B.bID AND A.aID2 = B.bID2 KEEP MATCHING COLS)
aID, aID2, avalue, bID , bID2, bvalue
=====================================
1 , 10 , 'abc' , 1 , 10 , 'mno'
2 , 20 , 'def' , NULL, 20 , NULL (note 20)
3 , 30 , 'ghi' , 3 , NULL, NULL (note 3)
4 , 40 , 'jkl' , NULL, NULL, NULL
Is there a way to get this behavior (keep matching parts, NULL not matching parts of "ON" clause and all value columns) using only joins while not using self-joins over and over?
What way would you suggest if there is no keyworld like "KEEP MATCHING COLS"?
Subselect? Selfjoins?
Thanks,
Blama
Join on Id or Id2 and then selectively null out the results in the select clause.
Set up test tables and data:
set null 'NULL'
create table a (aId number
, aId2 number
, aValue varchar2(4));
insert into a values (1, 10, 'abc');
insert into a values (2, 20, 'def');
insert into a values (3, 30, 'ghi');
insert into a values (4, 40, 'jkl');
create table b (bId number
, bId2 number
, bValue varchar2(4));
insert into b values (1, 10, 'mno');
insert into b values (20, 20, 'pqr');
insert into b values (3, 1, 'stu');
commit;
Query:
select A.*
, case when A.aId = B.bId then B.bId end as bId
, case when A.aId2 = B.bID2 then B.bId2 end as bId2
, case when A.aId = B.bId
and A.aId2 = B.bId2 then bValue end as bValue
from A
left outer join B on A.aID = B.bId or A.aId2 = B.bId2;
Results:
AID AID2 AVAL BID BID2 BVAL
---------- ---------- ---- ---------- ---------- ----
1 10 abc 1 10 mno
2 20 def NULL 20 NULL
3 30 ghi 3 NULL NULL
4 40 jkl NULL NULL NULL
I don't think you are going to find an easy solution to this, here is something that works on your data set, but isn't pretty or efficient!
create table A ( aID int, aID2 int, avalue char(3) )
create table B ( bID int, bID2 int, bvalue char(3) )
insert into A VALUES (1 , 10 , 'abc')
insert into A VALUES (2 , 20 , 'def')
insert into A VALUES (3 , 30 , 'ghi')
insert into A VALUES (4 , 40 , 'jkl')
insert into B VALUES (1 , 10 , 'mno')
insert into B VALUES (20 , 20 , 'pqr')
insert into B VALUES (3 , 1 , 'stu')
select distinct
A.*,
COALESCE(B1.bID,B2.bID) as bID,
COALESCE(B1.bID2,B3.bID2) as BID2,
B1.bvalue
from A
left outer join
B B1
on
A.aID = B1.bID
AND
A.aID2 = B1.bID2
left outer join
B B2
on
A.aID = B2.bID
left outer join
B B3
on
A.aID2 = B3.bID2
aID, aID2, avalue, bID , bID2, bvalue
=====================================
1 , 10 , 'abc' , 1 , 10 , 'mno'
2 , 20 , 'def' , NULL, 20 , NULL
3 , 30 , 'ghi' , 3 , NULL, NULL
4 , 40 , 'jkl' , NULL, NULL, NULL
Not quite self joins, but no better, i'd be interested in seeing a better solution and also understanding the requirement.
Not sure why you can't use/don't want self joins, but here's a version:
SELECT a.aID,
a.aID2,
a.avalue,
b1.bID,
b2.bID2,
CASE WHEN b1.bID = b2.bID AND b1.bID2 = b2.bID2 THEN b1.bvalue ELSE NULL END as bvalue
FROM A a
LEFT OUTER JOIN B b1
ON (a.aID = b1.bID)
LEFT OUTER JOIN B b2
ON (a.aID2 = b2.bID2)
Results:
aID aID2 avalue bID bID2 bvalue
1 10 abc 1 10 mno
2 20 def NULL 20 NULL
3 30 ghi 3 NULL NULL
4 40 jkl NULL NULL NULL
To make this easier to write (and therefore maintain), I suggest you avoid outer join and instead union the four subsets you require e.g.
SELECT A.*, B.* FROM A INNER JOIN B ON (A.aID = B.bID AND A.aID2 = B.bID2)
UNION
SELECT A.*, NULL, NULL, NULL
FROM A
WHERE NOT EXISTS (
SELECT *
FROM B
WHERE (A.aID = B.bID)
)
AND NOT EXISTS (
SELECT *
FROM B
WHERE (A.aID2 = B.bID2)
)
UNION
SELECT A.*, B.bID, NULL, NULL
FROM A INNER JOIN B ON (A.aID = B.bID)
AND NOT EXISTS (
SELECT *
FROM B
WHERE (A.aID2 = B.bID2)
)
UNION
SELECT A.*, NULL, B.bID2, NULL
FROM A INNER JOIN B ON (A.aID2 = B.bID2)
WHERE NOT EXISTS (
SELECT *
FROM B
WHERE (A.aID = B.bID)
);
The advantage to this approach is that is uses relational operators join, semi difference and union, allowing those non-relational NULL values (which outer join is expressly designed to generate) to be easily replaced with actual default values.