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.
Related
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
I am adding a commission percent column to an existing query. However, the commission data sits in a table unrelated to the main table (A) used within the query. However, these two tables have common columns/values with Table B.
I have three tables, A, B and C below
Table A
Reference Value_Name Renewal_Code
1 A N
2 A R
3 B N
4 A R
4 A N
Table B
Reference Value_Name Prod_Code
1 A 0016
2 A 0027
4 A 0032
4 A 0032
Table C
A_Prod_Code A_Tans_Code **Commission_Percent**
0016 Renewal 5
0027 Renewal 5
0032 New 10
0032 Renewal 5
I need to get the Commission_Percent from Table C relating to the corresponding Renewal_Code from Table A. This is the same as A_Tans_Code from Table C except that Table C spells out Renewal or New and Table A only uses R or N.
I have been able to pull through the Commission_Percent column into the output by using Table B for common values, but all values show as NULL.
I have also tried using a decode statement in order to link the Renewal_code/A_Trans_Code columns from Tables A and C.
(
SELECT
distinct c.commision_percent
FROM
TableA a
JOIN TableB b ON a.reference = b.reference
AND b.value_name = 'A'
JOIN TableC c ON b.prod_code = c.a_prod_code
AND b.value_name = 'A'
JOIN TableC c ON a.renewal_code = decode(c.a_trans_code, 'Rewnal','R','New','N')
) Commission_Percent
I need the correct commission_percent for Renewal and New business to come through for each reference. So far, I am only getting NULLs as I am having a hard time linking Tables A and C's Renewal_code and A_prod_code columns.
Any help is greatly appreciated!
This creates reproducible testing by cleaning up temp tables and re-inserting the data.
And could be a model for other solutions.
The SQL 'Select...' joins to a single TableC that has two parts to the ON condition-- prod_code and renewal_code (instead of two joins). Just remove the "a.*," to use it in your sql. (the decode function was changed to use a subscript of the first char of the A_Trans_Code).
IF OBJECT_ID('tempdb..#TableA') IS NOT NULL DROP TABLE #TableA
GO
CREATE TABLE #TableA
( Reference INTEGER
, Value_Name VARCHAR(10)
, Renewal_Code VARCHAR(10) )
INSERT INTO #TableA VALUES( 1, 'A', 'N' );
INSERT INTO #TableA VALUES( 2, 'A', 'R' );
INSERT INTO #TableA VALUES( 3, 'B', 'N' );
INSERT INTO #TableA VALUES( 4, 'A', 'R' );
INSERT INTO #TableA VALUES( 4, 'A', 'N' );
IF OBJECT_ID('tempdb..#TableB') IS NOT NULL DROP TABLE #TableB
GO
CREATE TABLE #TableB
( Reference INTEGER
, Value_Name VARCHAR(10)
, Prod_Code VARCHAR(10) )
INSERT INTO #TableB VALUES( 1, 'A', '0016' );
INSERT INTO #TableB VALUES( 2, 'A', '0027' );
INSERT INTO #TableB VALUES( 4, 'A', '0032' );
INSERT INTO #TableB VALUES( 4, 'A', '0032' );
IF OBJECT_ID('tempdb..#TableC') IS NOT NULL DROP TABLE #TableC
GO
CREATE TABLE #TableC
( Prod_Code VARCHAR(10)
, A_Trans_Code VARCHAR(10)
, Commission_Percent INTEGER )
INSERT INTO #TableC VALUES( '0016', 'Renewal', 5 );
INSERT INTO #TableC VALUES( '0027', 'Renewal', 5 );
INSERT INTO #TableC VALUES( '0032', 'New', 10 );
INSERT INTO #TableC VALUES( '0032', 'Renewal', 5 );
SELECT distinct a.*, c.commission_percent
FROM #TableA a
JOIN #TableB b ON a.reference = b.reference
AND a.value_name = b.value_name
JOIN #TableC c ON b.prod_code = c.prod_code
AND a.renewal_code = SUBSTRING(c.a_trans_code,1,1)
Results are--
Reference Value_Name Renewal_Code commission_percent
2 A R 5
4 A N 10
4 A R 5
Code to put in your sql
( SELECT distinct c.commission_percent
FROM TableA a
JOIN TableB b ON a.reference = b.reference
AND a.value_name = b.value_name
JOIN TableC c ON b.prod_code = c.prod_code
AND a.renewal_code = SUBSTRING(c.a_trans_code,1,1)
) Commission_Percent
WITH table_a AS (
SELECT 1 AS reference, 'A' AS value_name, 'N' AS renewal_code FROM DUAL UNION ALL
SELECT 2 AS reference, 'A' AS value_name, 'R' AS renewal_code FROM DUAL UNION ALL
SELECT 3 AS reference, 'B' AS value_name, 'N' AS renewal_code FROM DUAL UNION ALL
SELECT 4 AS reference, 'A' AS value_name, 'R' AS renewal_code FROM DUAL UNION ALL
SELECT 4 AS reference, 'A' AS value_name, 'N' AS renewal_code FROM DUAL
),
table_b AS (
SELECT 1 AS reference, 'A' AS value_name, '0016' AS prod_code FROM DUAL UNION ALL
SELECT 2 AS reference, 'A' AS value_name, '0027' AS prod_code FROM DUAL UNION ALL
/* SELECT 4 AS reference, 'A' AS value_name, '0032' AS prod_code FROM DUAL UNION ALL duplicate row excluded */
SELECT 4 AS reference, 'A' AS value_name, '0032' AS prod_code FROM DUAL
),
table_c AS (
SELECT '0016' AS a_prod_code, 'Renewal' AS a_tans_code, 5 AS commission_percent FROM DUAL UNION ALL
SELECT '0027' AS a_prod_code, 'Renewal' AS a_tans_code, 5 AS commission_percent FROM DUAL UNION ALL
SELECT '0032' AS a_prod_code, 'New' AS a_tans_code, 10 AS commission_percent FROM DUAL UNION ALL
SELECT '0032' AS a_prod_code, 'Renewal' AS a_tans_code, 5 AS commission_percent FROM DUAL
)
SELECT a.reference AS ref_a,
a.value_name AS value_name_a,
b.reference AS ref_b,
b.value_name AS value_name_b,
a.renewal_code,
b.prod_code,
c.commission_percent
FROM table_a a
LEFT OUTER JOIN table_b b
ON a.value_name = b.value_name
AND a.reference = b.reference
LEFT OUTER JOIN table_c c
ON SUBSTR(c.a_tans_code, 1, 1) = a.renewal_code
AND c.a_prod_code = b.prod_code
;
The common table expression (CTE) is just to create the same values you posted (CTE is the part using the WITH construct).
Results:
REF_A VALUE_NAME_A REF_B VALUE_NAME_B RENEWAL_CODE PROD_CODE COMMISSION_PERCENT
---------- --------------- ---------- --------------- --------------- ---------- --------------------
2 A 2 A R 0027 5
4 A 4 A N 0032 10
4 A 4 A R 0032 5
1 A 1 A N 0016
3 B N
You may have to check the values in the rows you posted that do not result in a join. This also assumes there are no codes:code_name relationships that violate the rule of first letter of code name = code.
I have a table like by following..
ID CustId CustName Status
1 a1 A NULL
2 a1 A NULL
3 a2 B NULL
4 a3 B NULL
5 a4 C NULL
6 a4 C NULL
7 a5 D NULL
8 a6 E NULL
I want to update the status = 2 when custid occurs 2nd time and I need output following like this...
ID CustId CustName Status
1 a1 A 1
2 a1 A 2
3 a2 B 1
4 a3 B 1
5 a4 C 1
6 a4 C 2
7 a4 D 2
8 a6 E 1
Now I am using the following query to update the status
update #tablename
set status= 2
where Custid in
(
select * from
(
select Custid
from #tablename
group by Custid
having count(*)> 1
) a
)
but the above query is updating the status=2 when count(custid)>1
I don't want to update first row..
CREATE TABLE #UserCompany
([ID] int, [CustId] varchar(2), [CustName] varchar(1), [Status] int)
;
INSERT INTO #UserCompany
([ID], [CustId], [CustName], [Status])
VALUES
(1, 'a1', 'A', null),
(2, 'a1', 'A', null),
(3, 'a2', 'B', null),
(4, 'a3', 'B', null),
(5, 'a4', 'C', null),
(6, 'a4', 'C', null),
(7, 'a4', 'D', null),
(8, 'a6', 'E', null)
;
select *,row_number() over (partition by [CustId] order by [ID]) as rn from #UserCompany
with cte as
(
select *,row_number() over (partition by [CustId] order by [ID]) as rn from #UserCompany)
update cte
set [Status]=case when rn > 1 then 2 else 1 end
or
UPDATE b
SET b.[Status] = a.[Status]
FROM #UserCompany a
INNER JOIN (select *,row_number() over (partition by [CustId] order by [ID]) as rn from #UserCompany) b
ON a.id = b.id
Intro
Easiest way to solve this would be with a subquery.
So for every row, you generate a subquery returning only one value.
This subquery will basically count the number of records ( for that customer id), that have an ID >= the current customer id.
Code
UPDATE UserCompany
SET
UserCompany.status = temp.status
FROM usercompany AS u
INNER JOIN
( SELECT ID,
CustID,
CustName,
(SELECT count(*)
FROM UserCompany t
WHERE t.custId = u.custId
AND t.ID <= u.id ) AS status
FROM UserCompany u ) AS TEMP ON temp.ID = u.ID;
select * from UserCompany;
Update 1: Only update records where previous same cust instance-count >= 2
UPDATE UserCompany
SET
UserCompany.status = temp.status
FROM usercompany AS u
INNER JOIN
( SELECT ID,
CustID,
CustName,
(SELECT count(*)
FROM UserCompany t
WHERE t.custId = u.custId
AND t.ID <= u.id ) AS status
FROM UserCompany u ) AS TEMP ON temp.ID = u.ID AND TEMP.STATUS >=2;
select * from UserCompany;
Update 2: Same as Update 1, but set 2 instead of actual count
(same as above but inserts 2 instead of real count)
UPDATE UserCompany
SET
UserCompany.status = temp.insert_status
FROM usercompany AS u
INNER JOIN
( SELECT ID,
CustID,
CustName,
2 as insert_status,
(SELECT count(*)
FROM UserCompany t
WHERE t.custId = u.custId
AND t.ID <= u.id ) AS status
FROM UserCompany u ) AS TEMP ON temp.ID = u.ID AND TEMP.STATUS >=2;
select * from UserCompany;
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);
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