Select record from table1 where value from table2 - sql-server

I have 2 tables here:
table1
id name idfrom idto
1 test 2 3
2 test3 1 9
table2
id branch status
2 a from
1 b from
9 c to
3 d to
How do I select branch from table2 and table1 based on status in table2?
I want the result to look like this:
id name branchfrom branchto
1 test a d
2 test3 b c

I answer it doesn't mean I like it.
SELECT id, name, bfrom.branch branchfrom, bto.branch branchto
FROM table1 t1
INNER JOIN (SELECT id, branch
FROM table2
WHERE status = 'from') bfrom
ON t1.idfrom = bfrom.id
INNER JOIN (SELECT id, branch
FROM table2
WHERE status = 'to') bto
ON t1.idto = bto.id;
I use INNER JOIN as sample only. You must adjust with your requirement (which you didn't clearly specify).

Something like the following should do (assuming you're wanting to join on id in both tables):
select t1.id, t1.name, f.branch as branchfrom, t.branch as branchto
from table1 as t1
join table2 as f
on f.id = t1.id
and f.status = 'from'
join table2 as t
on t.id = t1.id
and t.status = 'to'

This should work for you:
select t1.id, t1.name, f.branch as branchfrom, f1.branch as branchto
from table1 as t1
join table2 as f
on t1.idfrom = f.id
join table2 as f1
on t1.idto = f1.id
Please see here for demo: SQL Fiddle Demo

I don't know if this is better or worse than what the other two people have suggested but
select
t1.name,
(select
t2.branch
from
table2 t2
where
t1.idfrom = t2.id
) as branchfrom,
(select
t2.branch
from
table2 t2
where
t1.idto = t2.id
) as branchto
from
table1 t1
Here is a fiddle

Use this Code:
CREATE TABLE #table1 (
id int,
name varchar(10),
idfrom int,
idto int
)
CREATE TABLE #table2 (
id int,
branch char,
statuss varchar(10)
)
INSERT INTO #table1
VALUES (1, 'test', 2, 3)
INSERT INTO #table1
VALUES (2, 'test3', 1, 9)
INSERT INTO #table2
VALUES (2, 'a', 'From')
INSERT INTO #table2
VALUES (1, 'b', 'From')
INSERT INTO #table2
VALUES (9, 'c', 'to')
INSERT INTO #table2
VALUES (3, 'd', 'to')
SELECT
a.id,
a.name,
(SELECT
b.branch
FROM #table2 b
WHERE a.idfrom = b.id
AND b.statuss = 'FROM')
AS BranchFrom,
(SELECT
b.branch
FROM #table2 b
WHERE a.idto = b.id
AND b.statuss = 'to')
AS BranchTo
FROM #table1 a

Related

Counting from 2 tables

I have 2 tables.
A
Id Name
1 ab
2 cd
3 eg
4 fg
B
FkID
1
2
2
1
1
2
4
Since 3 is not there in B in the FKID column. I need to find the count in table A which has value in table B which have a value in FKID also.
So th total count should be 3. In my query, I am getting 7 after the left join.
You don't need a join, you can do it with EXISTS:
select count(*) from a
where exists (
select 1 from b
where b.fkid = a.id
)
I believe EXISTS is more efficient than a join, but if you need a join then it has to be an INNER JOIN like this:
select count(distinct a.id)
from a inner join b
on b.fkid = a.id
Using COUNT(DISTINCT B.FkId) the result can be achiveable. The COUNT is not considering the NULL values, so the following query will work.
SELECT COUNT(DISTINCT B.FkId) AS Occurence
FROM TableA A
LEFT JOIN TableB B ON B.FkId = A.Id;
or it can be achiveable with INNER JOIN too
SELECT COUNT(DISTINCT B.FkId) AS Occurence
FROM TableA A
INNER JOIN TableB B ON B.FkId = A.Id;
Demo with sample data:
DECLARE #TableA TABLE (Id INT, [Name] VARCHAR (2));
INSERT INTO #TableA (Id, [Name]) VALUES
(1, 'ab'),
(2, 'cd'),
(3, 'eg'),
(4, 'fg');
DECLARE #TableB TABLE (FkId INT);
INSERT INTO #TableB (FkId) VALUES
(1),
(2),
(2),
(1),
(1),
(2),
(4);
SELECT COUNT(DISTINCT B.FkId) AS Occurence
FROM #TableA A
LEFT JOIN #TableB B ON B.FkId = A.Id

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

MS SQL match table on multiple rows

I want to join two tables based on multiple rows, and can't find the correct way to do this.
The tables looks something like this :
table1
Id Location LocationNo
1 1 1
1 2 2
1 3 3
2 1 1
2 2 2
3 2 1
3 1 2
3 3 3
4 1 1
4 2 2
4 3 3
4 4 4
table2
Location LocationNo
1 1
2 2
3 3
I want to get the Id from table1 that match exactly the rows in table2.
I expect that the return should be Id 1.
I've tried the query bellow but the result are not the one expected.
SELECT t.Id
FROM table1 t1
WHERE EXISTS (SELECT 1
FROM table2 t2
WHERE t1.LocationId = t2.LocationId
AND t1.LocationNo = t2.LocationNo)
Any suggestions? Thanks.
EDIT :
table2
Location LocationNo
1 1
2 2
3 3
5 4
For this case I expect that the result should be null
Make use of Inner Join.
select t1.Id -- or t2.id, depends which table you want the ID from
from table1 t1
inner join table2 t2
on t1.LocationId = t2.LocationId
and t1.LocationNo = t2.LocationNo
Select Distinct t1.Id --< Use Distinct to return unique values only
From table1 t1
Inner Join table2 t2 --< Use Inner Join instead of "where exists"
On t1.LocationId = t2.LocationId
AND t1.LocationNo = t2.LocationNo
Update: It actually turned out to be more interesting than that: here we are looking for the exact match on all rows:
Select t1.Id
From table1 t1
Left Join table2 t2 --< Left Join to register NULLs from table2
On t1.LocationId = t2.LocationId
AND t1.LocationNo = t2.LocationNo
Group By t1.Id
Having --< Number of records from each table equals the count of matching criteria rows
Count(t1.LocationId) = (Select Count(*) From table2)
AND Count(t2.LocationId) = (Select Count(*) From table2)
Source data for testing:
With table1 As (
Select * From (Values
(1, 1, 1),
(1, 2, 2),
(1, 3, 3),
(2, 1, 1),
(2, 2, 2),
(3, 2, 1),
(3, 1, 2),
(3, 3, 3),
(4, 1, 1),
(4, 2, 2),
(4, 3, 3),
(4, 4, 4)
) V (Id, LocationId, LocationNo)
), table2 As (
Select * From (Values
(1, 1),
(2, 2),
(3, 3)
) V (LocationId, LocationNo)
)
I think you are looking for this
IF EXISTS(SELECT 1
FROM (SELECT Count(1) cnt,
id
FROM Table1 a
GROUP BY id) a
JOIN (SELECT t1.Id,
Count(1) cnt
FROM table1 t1
JOIN table2 t2
ON t1.[Location] = t2.[Location]
AND t1.LocationNo = t2.LocationNo
GROUP BY t1.Id
HAVING Count(1) = (SELECT Count(1)
FROM table2)) b
ON a.cnt = b.cnt
AND a.Id = b.id)
WITH tot_count
AS (SELECT Count(1) cnt,
id
FROM #Table1 a
GROUP BY id),
sub_cnt
AS (SELECT t1.Id,
Count(1) cnt
FROM table1 t1
JOIN table2 t2
ON t1.[Location] = t2.[Location]
AND t1.LocationNo = t2.LocationNo
GROUP BY t1.Id
HAVING Count(1) = (SELECT Count(1)
FROM table2))
SELECT b.id
FROM tot_count a
JOIN sub_cnt b
ON a.cnt = b.cnt
AND a.Id = b.id
ELSE
SELECT NULL

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.

Inner join then full join among the matched records

I have two tables:
declare #Table1 as table (id int, value CHAR(1))
declare #Table2 as table (id int, value CHAR(1))
INSERT #Table1
VALUES (1, 'A'),
(1, 'B'),
(3, 'A')
INSERT #Table2
VALUES(1, 'A'),
(1, 'C'),
(2, 'A')
I want to join these two tables so that at the end I should be able to produce this result:
id value id value
1 A 1 A
1 B NULL NULL
NULL NULL 1 C
I'm sorry for inadequate explanation (I mean no explanation at all). What I am trying to do here is (something like) to make inner join for the id columns (I mean take the records which are common on both sets over the "id" column) then look at the value columns and compare them inside the boundaries of this common set.
I hope I could describe what I was trying to do.
Hope this will work
SELECT distinct t1_id as id, t1_value as value , t2_id as id , t2_value as value
FROM (SELECT t1.id as t1_id, t1.value as t1_value from #Table1 t1 INNER JOIN #Table2 t2 on t1.id = t2.id) as A
FULL OUTER JOIN
(SELECT t2.id as t2_id, t2.value as t2_value from #Table1 t1 INNER JOIN #Table2 t2 on t1.id = t2.id) as B
on A.t1_value = B.t2_value
ORDER BY t1_id desc
Basically, What I am doing is outer joining the inner set (which is inner join on id column) on value column of inner set.
What do I win?
SELECT c.id,c.value,d.id,d.value
FROM
#Table1 c
full join
#Table2 d
on c.id = d.id and c.value = d.value
WHERE exists
(
SELECT a.id
FROM
#Table1 a
INNER JOIN
#Table2 b
ON a.id = b.id and a.id = c.id or d.id = a.id
)
You can do this with a full outer join and by pre-filtering the tables:
select a.id as a_id, a.value as a_value,
b.id as b_id, b.value as b_value
from (select *
from tablea a
where a.id = 1
) a full outer join
(select *
from tableb b
where b.id = 1
) b
on a.id = b.id and a.value = b.value;

Resources