Full Outer Join on Incomplete Data (by id variable) - sql

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

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

I would like to update table using merge and my table source will use cross join

I have a Table1:
IdT1 : 11, 12, 13
IdT1Group : 30,30,30
Table2:
IdT2 : 1, 2, 3, 4
IdT1 : 11, 11, 12, 12
Detail : A, B, A, B
AND User Defined Table Type #T2:
IdT2 : 1, 2, 3
IdT1 : 11,11,11
Detail: A,B,C
I would like to Update Table2 to be:
IdT2 : 1,2,5, 3,4,6, 7,8,9
IdT1 : 11,11,11, 12,12,12, 13,13,13
Detail : A,B,C, A,B,C, A,B,C
So, I was Use Merge in StoredProcedure:
;WITH Table2
AS (SELECT Table2.* FROM Table2 INNER JOIN Table1 ON Table2.IdT1 = Table1.IdT1 AND IdT1Group = 30)
MERGE INTO Table2 AS tblTarget
USING (SELECT #T2.*, T1Item.IdT1 AS T1Id FROM #T2 CROSS JOIN Table1 where IdT1Group = 30)
AS tblSource
ON tblTarget.IdT1 = tblSource.T1Id And tblTarget.IdT2 = tblSource.IdT2
WHEN MATCHED THEN
UPDATE
SET Detail = tblSource.Detail
WHEN NOT MATCHED BY SOURCE THEN
DELETE
WHEN NOT MATCHED BY TARGET THEN
INSERT (IdItem, IdT2, Detail)
VALUES (tblSource.IdT1,
tblSource.IdT2, tblSource.Detail);
But after i tried my code, my table2 become:
IdT2 : 1,2,5, 6,7,8, 9,10,11
IdT1 : 11,11,11, 12,12,12, 13,13,13
Detail: A,B,C, A,B,C, A,B,C
This is what should it be:
IdT2 : 1,2,5, 3,4,6, 7,8,9
IdT1 : 11,11,11, 12,12,12, 13,13,13
Detail : A,B,C, A,B,C, A,B,C
I think the output should look like follows because one of the values get deleted. further i think you have a identity column or a incremental value in the Table2 for IdT2.
when you delete an item the increased value will not get deducted.
output
IdT2 IdT1 Detail
----------- ----------- -------
1 11 A
2 11 B
5 11 C
3 12 C
6 12 A
7 12 B
8 13 A
9 13 B
10 13 C
SQL statement (NOTE: Created # tables instead of physical tables to get this going)
create table #Table1
(
IdT1 int , IdT1Group int
)
insert into #Table1
select 11 IdT1,30 IdT1Group union all
select 12 IdT1,30 IdT1Group union all
select 13 IdT1,30 IdT1Group
create table #Table2
(
IdT2 int identity(1,1), IdT1 int , Detail varchar(100)
)
insert into #Table2
SELECT 11 IdT1 ,'A' Detail union all
SELECT 11 ,'B' union all
SELECT 12 ,'A' union all
SELECT 12 ,'B'
declare #T2 table
(
IdT2 int , IdT1 int , Detail varchar(100)
)
insert into #T2
SELECT 1 IdT2 , 11 IdT1 ,'A' Detail union all
SELECT 2 , 11 ,'B' union all
SELECT 3 , 12 ,'C'
MERGE INTO #Table2 AS tblTarget
USING (SELECT T2.*, T1Item.IdT1 AS T1Id FROM #T2 T2 CROSS JOIN #Table1 T1Item where IdT1Group = 30)
AS tblSource
ON tblTarget.IdT1 = tblSource.T1Id And tblTarget.IdT2 = tblSource.IdT2--tblTarget.IdT1 = tblSource.T1Id And tblTarget.IdT2 = tblSource.IdT2
WHEN MATCHED THEN
UPDATE
SET Detail = tblSource.Detail
WHEN NOT MATCHED BY SOURCE THEN
DELETE
WHEN NOT MATCHED BY TARGET THEN
INSERT (IdT1, Detail)
VALUES (tblSource.T1Id,
tblSource.Detail);
select * from #Table2
order by 2,1
drop table #Table1
drop table #Table2

TSQL - Fill missing records

Code:
CREATE TABLE #Temp
(
[ID1] INT
, [ID2] INT
, [ID3] INT
, [Val] BIT
, PRIMARY KEY CLUSTERED ( [ID1], [ID2], [ID3] )
) ;
INSERT INTO #Temp
SELECT 1
, 10
, 100
, 1
UNION ALL
SELECT 1
, 10
, 101
, 1
UNION ALL
SELECT 1
, 11
, 100
, 1
UNION ALL
SELECT 1
, 11
, 101
, 1
UNION ALL
SELECT 2
, 10
, 100
, 1 ;
CREATE TABLE #Temp_ID3
(
[ID3] INT
) ;
INSERT INTO #Temp_ID3
SELECT 100
UNION ALL
SELECT 101
UNION ALL
SELECT 102 ;
SELECT [ID1]
, [ID2]
, [ID3]
, [Val]
FROM #Temp ;
SELECT [ID3]
FROM #Temp_ID3 ;
DROP TABLE #Temp_ID3 ;
DROP TABLE #Temp ;
Output:
ID1 ID2 ID3 Val
1 10 100 1
1 10 101 1
1 11 100 1
1 11 101 1
2 10 100 1
Goal:
To find missing ID3 records - from #Temp_ID3 table - in #Temp table (ID1/ID2/ID3 combos for existing ID1/ID2 combos). For those missing records, Val should be False. Desired Output will make sense.
I can get distinct ID1/ID2 from #Temp, cross join with ID3 and create a dataset. Left join #Temp to this new dataset, and insert records that way, but looking for a more "simpler" way.
Here's the "complicated" way.
;WITH CTE AS
(
SELECT DISTINCT
[TT].[ID1]
, [TT].[ID2]
, [T3].[ID3]
FROM #Temp_ID3 AS [T3]
CROSS JOIN (
SELECT DISTINCT
[ID1]
, [ID2]
FROM #Temp
) AS [TT]
)
SELECT [C].[ID1]
, [C].[ID2]
, [C].[ID3]
, COALESCE ( [TT].[Val], 0 ) AS [Val]
FROM CTE AS [C]
LEFT JOIN #Temp AS [TT]
ON [C].[ID1] = [TT].[ID1]
AND [C].[ID2] = [TT].[ID2]
AND [C].[ID3] = [TT].[ID3]
ORDER BY [C].[ID1]
, [C].[ID2]
, [C].[ID3] ;
Desired Output:
ID1 ID2 ID3 Val
1 10 100 1
1 10 101 1
1 10 102 0 -- Filling Missing ID3 Record w/ default Val = 0
1 11 100 1
1 11 101 1
1 11 102 0 -- Filling Missing ID3 Record w/ default Val = 0
2 10 100 1
2 10 101 0 -- Filling Missing ID3 Record w/ default Val = 0
2 10 102 0 -- Filling Missing ID3 Record w/ default Val = 0
Use a cross join to generate the rows and then left join to fill in the values:
select t1.id1, t2.id2, t3.id3, coalesce(t.val, 0) as val
from (select distinct id1 from #temp) t1 cross join
(select distinct id2 from #temp) t2 cross join
(select distinct id3 from #temp) t3 left join
#temp t
on t.id1 = t1.id1 and t.id2 = t2.id2 and t.id3 = t3.id3;
You don't have to use subqueries to generate the ids, if one of the tables actually has them.
EDIT:
For the revised version in the comment, you can do something very similar:
select t12.id1, t12.id2, t3.id3, coalesce(t.val, 0) as val
from (select distinct id1, id2 from #temp) t12 cross join
#temp_id3 t3 left join
#temp t
on t.id1 = t12.id1 and t.id2 = t12.id2 and t.id3 = t3.id3;
As per example you want only cross join with self join
select distinct t.id1, t.id2, t3.id3, coalesce(t1.val, 0) as Val
from #Temp t cross join #Temp_ID3 t3
left join #temp t1
on t1.id1 = t.id1 and t1.id2 = t.id2 and t1.id3 = t3.id3;

Update table in Sql

Table tblProductStock:
ID Name Qyt
1 X 50
2 Y 40
3 Z 30
Table tblStockMinus:
Id Name Qty
1 X 10
1 X 20
2 Y 30
3 Z 20
I want to update tblProductStock so that it will have:
ID Name Qyt
1 X 20
2 Y 10
3 Z 10
I have tried to use the following SQL request, but it didn't work correctly:
UPDATE ProductStock_Show
SET Quantity = ProductStock_Show.Quantity - ProductStock_Show_Minus.Quantity
FROM ProductStock_Show JOIN ProductStock_Show_Minus
ON ProductStock_Show_Minus.ProductId=ProductStock_Show.ProductId
This will give you required result.
select t1.id, t1.qty-t2.qty as qty from tblProductStock as t1 inner join
(
select id, sum(qty) as qty from tblStockMinus group by id
) as t2 on t1.id=t2.id
You need to update this (but it depends in the RDBMS. This is for MS SQL Server)
Update t
set
t.qty=t3.qty from tblProductStock as t inner join
(
select t1.id, t1.qty-t2.qty as qty from tblProductStock as t1 inner join
(
select id, sum(qty) as qty from tblStockMinus group by id
) as t2 on t1.id=t2.id
) as t3 on t.id=t3.id
DECLARE #Table1 TABLE
( ID int, Name varchar(1), Qyt int)
;
INSERT INTO #Table1
( ID , Name , Qyt )
VALUES
(1, 'X', 50),
(2, 'Y', 40),
(3, 'Z', 30)
;
DECLARE #Table2 TABLE
( Id int, Name varchar(1), Qty int)
;
INSERT INTO #Table2
( Id , Name , Qty )
VALUES
(1, 'X', 10),
(1, 'X', 20),
(2, 'Y', 30),
(3, 'Z', 20)
;
UPDATE #Table1 SET QYT =
t.Qyt - s from (
select
t.id,
t.Name,
t.Qyt ,
SUM(tt.Qty)S
FROM #Table1 t
INNER JOIN #Table2 tt
ON t.Name = tt.Name
GROUP BY t.id,t.Name,t.Qyt)T
SELECT * from #Table1