How to join 2 tables with inner and left outer join - sql-server

I have two tables in MSSQL with the same structure T1 & T2. Both tables can INNER JOIN on Id but T2 may not contain the AccountId associated with the Id as in T1.
.
T1 Id AccountId Name T2 Id AccountId Name
111 5555 John 111 5555 John
122 5555 David 133 5555 Sharon
133 5555 Sharon
Below is the code I tried but the result is not working?.
.
INSERT INTO T3
SELECT T1.Id,T1.AccountId,T1.Name
FROM T1
INNER JOIN T2 T2.Id = T1.id
LEFT OUTER JOIN T1.AccountId = T2.AccountId
WHERE AccountId = 5555
The expected result would be to insert values that are not in T1 into T3

You need where clause:
INSERT INTO T3(Id, AccountId, Name)
SELECT T1.Id, T1.AccountId, T1.Name
FROM T1 LEFT JOIN
T2
ON T2.Id = T1.id
WHERE T2.AccountId IS NOT NULL;
Notes:
Only one LEFT JOIN is necessary. I don't know what the INNER JOIN is for.
Every JOIN should be followed by an ON clause.
You should list the columns when doing an INSERT.
You need the WHERE to find non-matches.
This query could also be written using NOT EXISTS.

This should be what you're after:
CREATE TABLE #T1 (id int, AccountId int, [Name] varchar(6));
CREATE TABLE #T2 (id int, AccountId int, [Name] varchar(6));
CREATE TABLE #T3 (id int, AccountId int, [Name] varchar(6));
INSERT INTO #T1
VALUES (111,5555,'John '),
(122,5555,'David '),
(133,5555,'Sharon');
INSERT INTO #T2
VALUES (111,5555,'John '),
(133,5555,'Sharon');
INSERT INTO #T3 (id, AccountId, [Name])
SELECT T1.id,
T1.AccountId,
T1.[Name]
FROM #T1 T1
LEFT JOIN #T2 T2 ON T1.ID = T2.id
WHERE T2.id IS NULL;
SELECT *
FROM #t3;
DROP TABLE #T1;
DROP TABLE #T2;
DROP TABLE #T3;

Related

Select values from Three tables value not in another table MSSQL

I am using SQL Database. I am having three tables like T1,T2,T3. I want to get a column values from a table by excluding the values exists in another table.
SELECT T3 THEN
SELECT T2 NOT in T3 THEN
SELECT T1 NOT in T3 and T2
CREATE TABLE T1(CID INT,NAME VARCHAR(100),EMAIL VARCHAR(50), MOIBLE VARCHAR(20))
CREATE TABLE T2(CID INT,NAME VARCHAR(100),EMAIL VARCHAR(50), MOIBLE VARCHAR(20))
CREATE TABLE T3(CID INT,NAME VARCHAR(100),EMAIL VARCHAR(50), MOIBLE VARCHAR(20))
Insert value
INSERT INTO T1 VALUES (1,'TEST1','a#gmail','123456')
INSERT INTO T1 VALUES (2,'TEST2','b#gmail','123456')
INSERT INTO T1 VALUES (3,'TEST3','c#gmail','123456')
INSERT INTO T1 VALUES (4,'TEST4','d#gmail','123456')
INSERT INTO T2 VALUES (1,'TEST1','updateda#gmail','123456')
INSERT INTO T2 VALUES (2,'TEST2','updatedb#gmail','77777')
INSERT INTO T3 VALUES (1,'TEST1','updateda#gmail','999999')
Expected output
SELECT T3 and
SELECT T2 record NOT in T3 and
SELECT T1 record NOT in T3 and T2
cid Name email moible
1 TEST1 updateda#gmail 999999 From T3
2 TEST2 updatedb#gmail 77777 From T2
3 TEST3 c#gmail 123456 From T1
4 TEST4 d#gmail 123456 From T1
I have written query for this
SELECT * FROM T2 where cid not in ( SELECT cid from T3)
UNION
SELECT * FROM T3
Here How to include T1 table?
You can add anther 1 union cid not in T2 and T3
SELECT * from T1 where cid not in(SELECT cid FROM T2 where cid not in ( SELECT
cid from T3)
UNION
SELECT cid FROM T3)
UNION
SELECT * FROM T2 where cid not in ( SELECT cid from T3)
UNION
SELECT * FROM T3

How find rows in one table that share common ancestor in second table with a third table

Sorry for the convoluted title, hopefully what follows is clear. Suppose I have the following tables:
T1
ID
1001
1002
T2
ID|T1ID
20|1001
T3
ID|T1ID
30|1002
T4
T1ID|T5ID
1001|2003
1002|2004
T5
ID|ParentID
2001|2000
2002|2001
2003|2001
2004|2002
T2 and T3 have a connection such that, via T1 and T4, if they share a common ancestor in T5, they are connected. In the example above, 20 in T2 has a connection to 30 in T3 because in T5 (via T1 and T4), they have a common ParentID, i.e. ancestor (2001). How can I construct a query that returns all rows in T3 that has a connection to a given T2? That is, given ID 20 for T2, it returns
T3
30|1002
T3 30? I know how to use CTE to solve something much simpler like "given T5 2004, find all ancestors" (2002,2001,2000), but I don't know how to extend that to solve this more complex problem. Thanks.
[Edit]
Using Paul Fleming's answer here as a starting point, I think I've been able to construct a query that works. But I'm wondering if there's a simpler solution. Working example for sample data above:
CREATE TABLE #T1 (id INT);
CREATE TABLE #T2 (id INT, t1Id INT);
CREATE TABLE #T3 (id INT, t1Id INT);
CREATE TABLE #T4 (t1Id INT, t5Id INT);
CREATE TABLE #T5 (id INT, parentId INT);
-- insert some test data
INSERT INTO #T1 (id)
SELECT 1001 UNION ALL SELECT 1002
INSERT INTO #T2 (id, t1Id)
SELECT 20,1001
INSERT INTO #T3 (id, t1Id)
SELECT 30,1002
INSERT INTO #T4 (t1Id, t5Id)
SELECT 1001,2003 UNION ALL SELECT 1002,2004
INSERT INTO #T5 (id, parentid)
SELECT 2001,2000 UNION ALL SELECT 2002,2001 UNION ALL SELECT 2003,2001
UNION ALL SELECT 2004,2002
DECLARE #t5Id INT;
SELECT #t5Id = (SELECT t5.id from #T5 t5
inner join #T4 t4 on t4.t5Id=t5.id
inner join #T2 t2 on t2.t1Id=t4.t1Id
inner join #T1 t1 on t1.id=t2.t1Id
where t2.id=20);
-- build the CTE
WITH #results AS
(
SELECT id,
parentid
FROM #T5
WHERE id = #t5Id
UNION ALL
SELECT t.id,
t.parentid
FROM #T5 t
INNER JOIN #results r ON r.parentid = t.id
)
SELECT t3.* from #T3 t3
inner join
(SELECT t4.* from #T4 t4
inner join
(SELECT t5b.* FROM #t5 t5b
inner join
(SELECT t5.* FROM #T5 t5
inner join
(SELECT * FROM #results) as R1 on R1.parentId=t5.parentId) as R2 on t5b.parentId=R2.id) as R3 on R3.id=t4.t5Id) as R4 on t3.t1Id=R4.t1Id
Using your tables, this is clearer I think:
DECLARE #T2Id int = 20;
-- Tree returns all #T5 IDs with each of their ancestors
WITH Tree AS (
SELECT Id, ParentId
FROM #T5
UNION ALL
SELECT #T5.id, t.parentid
FROM Tree t
INNER JOIN #T5 ON #T5.parentId = t.id
)
SELECT *
FROM #T3
-- We don't mind if there are multiple common ancestors, we just want to find an example
WHERE EXISTS (
SELECT NULL
FROM #T4 AS t4a
INNER JOIN #T5 AS t5a ON t5a.id = t4a.t5Id
INNER JOIN Tree tr ON tr.id = t5a.id
INNER JOIN #T5 AS t5b ON t5b.parentId = tr.parentId
INNER JOIN #T4 AS t4b ON t4b.t5Id = t5b.id
INNER JOIN #T2 ON #t2.t1Id = t4b.t1Id
WHERE t4a.t1Id = #t3.t1Id
AND #t2.id = #T2Id
);

Query in SQL Server to combine tables

I need a query in SQL Server to combine tables like these:
TBL1
ID TITLE1
-----------
1 t1
2 t2
3 t3
TBL2
ID TITLE2
------------
100 c1
200 c2
Now I need tbl3 as a result:
TBL3
col1 col2
-----------
t1 c1
t1 c2
t2 c1
t2 c2
t3 c1
t3 c2
How can I get tbl3 without any key between these 2 tables?
You are looking for a cross join:
SELECT
t1.TITLE1 AS col1,
t2.TITLE2 AS col2
FROM TBL1 t1
CROSS JOIN TBL2 t2
ORDER BY
t1.TITLE1,
t2.TITLE2;
Demo
You can try this
CREATE TABLE #Table1
([ID] int, [TITLE1] varchar(2))
INSERT INTO #Table1
VALUES
(1, 't1'),
(2, 't2'),
(3, 't3')
CREATE TABLE #Table2
([ID] int, [TITLE2] varchar(2))
INSERT INTO #Table2
VALUES
(100, 'c1'),
(200, 'c2')
SELECT Title1 as col1, Title2 as col2
FROM #Table1
CROSS JOIN #Table2 order by Title1
DROP TABLE #Table1
DROP TABLE #Table2
Here is the output shown below.
col1 col2
t1 c1
t1 c2
t2 c2
t2 c1
t3 c1
t3 c2
CROSS JOIN will work for your case.
That is result-set contains the number of rows in the first table, multiplied by the number of rows in second table when there is no WHERE clause.
/**********************************/
SELECT
a.TITLE1 AS col1,
b.TITLE2 AS col2
FROM
TBL1 a
CROSS JOIN
TBL2 b
/**********************************/

T-SQL - Compare two tables and display result as Available on Both, table1 only and table2 only

I have 2 tables and structure is same on both tables.
Table 1:
ID Name Phone
1 xxx 111
2 yyy 222
Table 2:
ID Name Phone
1 xxx 111
3 zzz 333
I need to compare these two tables and display the results (based on ID column- where condition ID) as
Available in both tables
Table1 only
Table2 only
This should be like this,
ID Name Phone Status
----------------------------------------
1 xxx 111 Available in both
2 yyy 222 Available in T1 only
3 zzz 333 Available in T2 only
using HASHBYTES :Demo Here ..you dont need to consume table mutiple times,but only once
;with cte
as
(
select id,name,phone,hashbytes('sha1',concat(id,name,phone) )as tb1
from #t1
)
select isnull(c.id,b.id) as id,
isnull(c.name,b.name) as name,
isnull(c.phone,b.phone) as phone,
case when c.tb1 is null then 'exists in second table only'
when c.tb1 is not null and b.tb1 is not null then 'exists in both'
when b.tb1 is null then 'exists in first table only'
end as 'exidts' from cte c
full join
(
select id,name,phone,hashbytes('sha1',concat(id,name,phone) )as tb1
from #t2
) b
on
b.tb1=c.tb1
Try this:
declare #table1 table
(
name varchar(10),
phone varchar(10)
)
declare #table2 table
(
name varchar(10),
phone varchar(10)
)
INSERT INTO #table1 VALUES('xxx','111')
INSERT INTO #table1 VALUES('yyy','222')
INSERT INTO #table2 VALUES('xxx','111')
INSERT INTO #table2 VALUES('zzz','333')
SELECT t1.name, t1.phone, 'Available on both' FROM
#table1 t1 INNER JOIN #table2 t2
ON t1.name = t2.name and t1.phone = t2.phone
UNION
SELECT name, phone, 'Available on T1 only' FROM
#table1 t1 WHERE NOT EXISTS
(SELECT 1 FROM #table2 t2
WHERE t1.name = t2.name and t1.phone = t2.phone)
UNION
SELECT name, phone, 'Available on T2 only' FROM
#table2 t2 WHERE NOT EXISTS
(SELECT 1 FROM #table1 t1
WHERE t1.name = t2.name and t1.phone = t2.phone)
You can use combination of FULL JOIN and IS NULL to check availability from both tables -
SELECT ISNULL(t1.id, t2.id) AS Id
, ISNULL(t1.name, t2.name) AS Name
, ISNULL(t1.phone, t2.phone) AS Phone
, CASE
WHEN t1.id IS NULL THEN 'Available in T2 only'
WHEN t2.id IS NULL THEN 'Available in T1 only'
ELSE 'Available in both'
END AS Status
FROM Table1 AS t1
FULL JOIN Table2 AS t2 ON (t2.id = t1.id);
As this query uses only one JOIN operation and no sub queries it is very fast.
This could work:
CREATE TABLE #T1 ( ID INT, Name VARCHAR(10), Phone VARCHAR(10) )
CREATE TABLE #T2 ( ID INT, Name VARCHAR(10), Phone VARCHAR(10) )
INSERT INTO #T1 VALUES ( 1, 'xxx', '111' ), ( 2, 'yyy', '222' )
INSERT INTO #T2 VALUES ( 1, 'xxx', '111' ), ( 3, 'zzz', '333' )
SELECT #T1.ID, #T1.Name, #T1.Phone, 'Available on both' AS Status
FROM #T1 INNER JOIN #T2 ON #T1.ID = #T2.ID
UNION
SELECT #T1.ID, #T1.Name, #T1.Phone, 'Available on T1 only' AS Status
FROM #T1 LEFT JOIN #T2 ON #T1.ID = #T2.ID
WHERE #T2.ID IS NULL
UNION
SELECT #T2.ID, #T2.Name, #T2.Phone, 'Available on T2 only' AS Status
FROM #T1 RIGHT JOIN #T2 ON #T1.ID = #T2.ID
WHERE #T1.ID IS NULL
DROP TABLE #T1
DROP TABLE #T2

Is CTE the correct way to handle recursion with two tables?

I have a query setup below, and I'm having trouble with the recursion piece. I start with a contract(s), Abc and Xyz from Table1. I take Table1.Id, groupNo and look them up in Table2, to get the contracts(s) there, then look those contracts back up in Table1, repeating the process until it eventually returns null, and capturing the last iteration. Is CTE the way to handle this? If so, could someone help with the last iteration. I tried nesting, and haven't got it to work.
Table Structure
create table Table1 (id int, groupNo int, contract varchar(3))
insert into Table1 values(33,2,'Abc')
insert into Table1 values(34,8,'Xyz')
insert into Table1 values(88,11,'123')
insert into Table1 values(89,11,'456')
create table Table2 (id int, groupNo int, contract varchar(3))
insert into Table2 values(34,8,'123')
insert into Table2 values(34,8,'456')
insert into Table2 values(89,11,'789')
Query
with myCTE (id,groupNo,contract) as
(
select
t1.id
,t1.groupNo
,t2.contract
from Table1 t1
inner join Table2 t2 on t1.id = t2.id and t1.groupNo = t2.groupNo
union all
select
t1.id
,t1.groupNo
,c2.contract
from myCTE c2
inner join Table1 t1 on c2.contract = t1.contract
)
select top 10 id, groupNo, contract
from myCTE
SQL FIDDLE
This is one way of doing it.
Basically, I record the level of each recursion and only keep the highest level. See SQL Fiddle and query below:
declare #Table1 table(id int, groupNo int, contract varchar(3));
insert into #Table1 values(33,2,'Abc');
insert into #Table1 values(34,8,'Xyz');
insert into #Table1 values(88,11,'123');
insert into #Table1 values(89,11,'456');
declare #Table2 table(id int, groupNo int, contract varchar(3));
insert into #Table2 values(34,8,'123');
insert into #Table2 values(34,8,'456');
insert into #Table2 values(89,11,'789');
with myCTE (level, id, groupNo, contract, subcontract) as
(
select 0, t1.id,t1.groupNo, t1.contract
,t2.contract
from #Table1 t1
inner join #Table2 t2 on t1.id = t2.id and t1.groupNo = t2.groupNo
union all
select level+1, c2.id, c2.groupNo, c2.contract
,t2.contract
from myCTE c2
inner join #Table1 t1 on c2.subcontract = t1.contract
inner join #Table2 t2 on t1.id = t2.id and t1.groupNo = t2.groupNo
)
Select c.* From myCTE as c
Inner join (select id, groupNo, contract, level = max(level) From myCTE Group by id, groupNo, contract) as m
On m.level = c.level and m.id = c.id and m.groupNo = c.groupNo and m.contract = c.contract
OPTION (MAXRECURSION 0);
I also added table2 to the second select. You want it to behave like the first one and it needs to get the subcontract name from table2.

Resources