Related
I want values to be null if there is any null in particular group.
When I am using aggregate functions, ie sum, then it is handling null itself but I don't want to handle null, I need null should make null when doing sum on it.
declare #tbl table (id int,grpid char )
insert into #tbl
values(1,'a'), (2,'b'),(null,'b')
select grpid,sum(id) as val
from #tbl
group by grpid
required output :
grpid val
a 1
b null
Simple as this I guess...
declare #tbl table (id int,grpid char )
insert into #tbl
values(1,'a'), (2,'b'),(null,'b')
;WITH cte AS(
SELECT DISTINCT grpid
FROM #tbl
WHERE id IS NULL
)
select t.grpid,sum(id) as val
from #tbl t
WHERE grpid NOT IN (SELECT grpid FROM cte)
GROUP BY t.grpid
UNION
SELECT grpid, NULL
FROM cte
You can try these methods:
Method 1:
select grpid,
case
when count(*)<>count(id) then null
else sum(id)
end as val
from #tbl
group by grpid
Note: Count(*) always return the number of records but Count(ColumnName) always return the number of records where ColumnName is not null
Method 2:
select grpid,
case
when exists(Select top 1 * from #tbl where grpid = t.grpid and id is null) then null
else sum(id)
end as val
from #tbl as t
group by grpid
Method 3:
select grpid, sum(id) as val
from #tbl as t
where grpid NOT IN (Select grpid from #tbl where id is null)
group by grpid
union
select grpid , null as val from #tbl where id is null
Another approach
declare #tbl table (id int, grpid char );
insert into #tbl
values (1,'a'), (2,'b'), (null,'b'), (3, 'a'), (null, 'c');
select t1.grpid
, case when t2.grpid is null then sum(t1.id)
else null
end as 'ssum'
from #tbl t1
left join #tbl t2
on t2.grpid = t1.grpid
and t2.id is null
group by t1.grpid, t2.grpid
order by t1.grpid;
Similar to some existing but might be more efficient
UNION will perform a distinct
declare #tbl table (id int, grpid char );
insert into #tbl
values (1,'a'), (2,'b'), (null,'b'), (3, 'a'), (null, 'c');
with cte as
( select id, grpid
from #tbl
where id is null
)
select grpid, id
from cte
union
select grpid, sum(id) as val
from #tbl
where not exists (select 1 from cte where cte.grpid = [#tbl].grpid)
group by grpid
order by grpid;
I have Parent and Child table.
The goal is to duplicate the records, except with new primary keys.
Original Tables
Parent(id)
1
Child(id,parentId, data)
1,1
2,1
After insert:
Parent
1
2
Child
1,1
2,1
3,2
4,2
How do I do that? The part I am having trouble with is getting the new parent key for use with the child records.
This is what I have come up with so far.
--DECLARE VARS
declare #currentMetadataDocumentSetId int = 1, --Ohio
#newMetadataDocumentSetid int = 3; --PA
--CLEANUP
IF OBJECT_ID('tempdb..#tempFileRowMap') IS NOT NULL
/*Then it exists*/
DROP TABLE #tempFileRowMap
--Remove existing file row maps.
delete from file_row_map where metadata_document_set_id = #newMetadataDocumentSetid;
--Create a temptable to hold data to be copied.
Select [edi_document_code],
[functional_group],
[description],
3 as [metadata_document_set_id],
[document_name],
[incoming_file_row_subtype],
[metadata_document_id],
[document_subcode],
[outgoing_file_row_subtype],
[asi_type_code],
[asi_action_code],
[metadata_document_set],
file_row_map_id as orig_file_row_map_id
into #tempFileRowMap
from file_row_map fileRowMap
where metadata_document_set_id = #currentMetadataDocumentSetId;
--Select * from #tempFileRowMap;
Insert into file_row_map select
[edi_document_code],
[functional_group],
[description],
[metadata_document_set_id],
[document_name],
[incoming_file_row_subtype],
[metadata_document_id],
[document_subcode],
[outgoing_file_row_subtype],
[asi_type_code],
[asi_action_code],
[metadata_document_set]
from #tempFileRowMap
--Show Results
Select * from file_row_map fileRowMap where fileRowMap.metadata_document_set_id = #newMetadataDocumentSetid
--Update Detail
Select
[file_row_map_id],
[file_row_column],
[element_code],
[element_metadata_id],
[col_description],
[example],
[translate],
[is_used],
[is_mapped],
[page_num],
[subcode],
[qualifier],
[loop_code],
[loop_subcode],
[default_value],
[delete_flag]
into #tempFileRowMapDetail
from [dbo].[file_row_map_detail] d
left join #tempFileRowMap m
on m.orig_file_row_map_id = d.file_row_map_id
select * from #tempFileRowMapDetail
Simply use OUTPUT clause for getting exact Parent Table Primary Key values.
Lets build Example Schema for your case
--For Capturing inserted ID
CREATE TABLE #ID_CAPTURE (PARENT_ID INT,ORDER_NME VARCHAR(20));
--Your Intermidiate Data To insert into Actual Tables
CREATE TABLE #DUMMY_TABLE (ORDER_NME VARCHAR(20), ITEM_NME VARCHAR(20));
--Actual Tables
CREATE TABLE #ORDER_PARENT (ORDER_ID INT IDENTITY,ORDER_NME VARCHAR(20))
CREATE TABLE #ORDER_CHILD (CHILD_ID INT IDENTITY ,ORDER_ID INT, ORDER_NME VARCHAR(20))
INSERT INTO #DUMMY_TABLE
SELECT 'BILL1','Oil'
UNION ALL
SELECT 'BILL1', 'Gas'
UNION ALL
SELECT 'BILL2', 'Diesel'
Now do Inserts in Parent & Child Tables
INSERT INTO #ORDER_PARENT
OUTPUT inserted.ORDER_ID, inserted.ORDER_NME into #ID_CAPTURE
SELECT DISTINCT ORDER_NME FROM #DUMMY_TABLE
INSERT INTO #ORDER_CHILD
SELECT C.PARENT_ID, ITEM_NME FROM #DUMMY_TABLE D
INNER JOIN #ID_CAPTURE C ON D.ORDER_NME = C.ORDER_NME
SELECT * FROM #ID_CAPTURE
SELECT * FROM #ORDER_CHILD
There are other ways to get Inserted Identity values.
See documentation ##IDENTITY (Transact-SQL) , SCOPE_IDENTITY
Try following approach:
DECLARE #Table1 TABLE (
ID INT NOT NULL PRIMARY KEY,
ParentID INT NULL, -- FK
[Desc] VARCHAR(50) NOT NULL
);
INSERT #Table1 (ID, ParentID, [Desc])
VALUES
(1, NULL, 'A'),
(2, 1, 'AA.1'),
(3, 1, 'AA.2'),
(4, NULL, 'B'),
(5, 4, 'BB.1'),
(6, 4, 'BB.2'),
(7, 4, 'BB.3'),
(8, 7, 'BBB.1');
DECLARE #ParentID INT = 4;
DECLARE #LastID INT = (SELECT TOP(1) ID FROM #Table1 x ORDER BY x.ID DESC)
IF #LastID IS NULL
BEGIN
RAISERROR('Invalid call', 16, 1)
--RETURN ?
END
SELECT #LastID AS LastID;
/*
LastID
-----------
8
*/
DECLARE #RemapIDs TABLE (
OldID INT NOT NULL PRIMARY KEY,
[NewID] INT NOT NULL UNIQUE
);
WITH CteRecursion
AS (
SELECT 1 AS Lvl, crt.ID, crt.ParentID --, crt.[Desc]
FROM #Table1 crt
WHERE crt.ID = #ParentID
UNION ALL
SELECT cld.Lvl + 1 AS Lvl, crt.ID, crt.ParentID --, crt.[Desc]
FROM #Table1 crt
JOIN CteRecursion cld ON crt.ParentID = cld.ID
)
INSERT #RemapIDs (OldID, [NewID])
SELECT r.ID, #LastID + ROW_NUMBER() OVER(ORDER BY r.Lvl) AS [NewID]
FROM CteRecursion r;
--INSERT #Table1 (ID, ParentID, [Desc])
SELECT nc.[NewID] AS ID, np.[NewID] AS ParentID, o.[Desc]
FROM #Table1 o -- old
JOIN #RemapIDs nc /*new child ID*/ ON o.ID = nc.OldID
LEFT JOIN #RemapIDs np /*new parent ID*/ ON o.ParentID = np.OldID
/*
ID ParentID Desc
----------- ----------- --------------------------------------------------
9 NULL B
10 9 BB.1
11 9 BB.2
12 9 BB.3
13 12 BBB.1
*/
Note: with some minor changes should work w. many ParentIDs values.
I want to call a stored procedure in a join statement of the Select Query.
For example,
Select *
from test
left join test1 on GetID(test.id)=test1.id
The idea is to match one to many relationship.
The structure of tables would be
Table: Test
ID Name
1 abc
2 te
Table: Test1
Id TestID Name
1 1 xxx
2 1 yyy
3 1 zzz
4 2 aaa
Stored procedure:
Create procedure GETID
#id int
as
begin
select top 1 id
from test1
where testid = #id
end
You can convert the stored procedure into an inline table-valued function or you can put the query inside an OUTER APPLY:
SELECT *
FROM test t
OUTER APPLY(
SELECT TOP 1 id
FROM test1
WHERE testid = t.testid
)x
Use a scalar function instead.
CREATE FUNCTION GETID
(
#id int
)
RETURNS int
AS
BEGIN
return (select top 1 id from test1 where testid=#id)
END
Or, review methods in post: Get top 1 row of each group
Use cross apply (or outer apply), which executes once on right side of query.
Or, use row_number() over partition to rank the group rows and select based on rank.
declare #test table (id int, name varchar(100))
insert into #test (id, name) values (1, 'abc')
insert into #test (id, name) values (1, 'te')
declare #test1 table (id int, testid int, name varchar(100))
insert into #test1 (id, testid, name) values (1, 1, 'xxx')
insert into #test1 (id, testid, name) values (2, 1, 'yyy')
insert into #test1 (id, testid, name) values (3, 1, 'zzz')
insert into #test1 (id, testid, name) values (4, 2, 'aaa')
Select * from #test t
cross apply (select top 1 * from #test1
where testid = t.id
order by id) -- change group order as needed
as t1
I have been racking my brains on this one for some time, so through it was about time to ask for some help.
I have a product database, each product has a number of hashtags associated with it. I want to be able to pull out related hashtags.
Let me take you through an example:
CREATE TABLE #Test (ProductID int, Hashtag varchar(30))
INSERT INTO #Test VALUES( 1 ,'toys')
INSERT INTO #Test VALUES( 1 ,'lego')
INSERT INTO #Test VALUES( 1 ,'construction')
INSERT INTO #Test VALUES( 2 ,'toys')
INSERT INTO #Test VALUES( 2 ,'lego')
INSERT INTO #Test VALUES( 2 ,'lego-city')
INSERT INTO #Test VALUES( 3 ,'clothing')
INSERT INTO #Test VALUES( 3 ,'womens')
INSERT INTO #Test VALUES( 3 ,'jeans')
INSERT INTO #Test VALUES( 4 ,'clothing')
INSERT INTO #Test VALUES( 4 ,'mens')
INSERT INTO #Test VALUES( 4 ,'tops')
INSERT INTO #Test VALUES( 4 ,'t-shirts')
INSERT INTO #Test VALUES( 5 ,'clothing')
INSERT INTO #Test VALUES( 5 ,'mens')
INSERT INTO #Test VALUES( 5 ,'tops')
INSERT INTO #Test VALUES( 5 ,'vests')
What I want to be able to do is select a Hashtag, for example "toys", then pull out all other hashtags that have a relationship (via the productId).
This is the results set that should be returned when querying "toys":
hashtag, count
lego, 2
construction, 1
lego-city, 1
Any help or ideas on how to go about implementing this would be much appreciated.
SQL Fiddle
MS SQL Server 2012 Schema Setup:
create table YourTable
(
Product_id int,
hashtag varchar(25)
)
insert into YourTable values
( 1, 'toys '),
( 1, 'lego '),
( 1, 'construction '),
( 2, 'toys '),
( 2, 'lego '),
( 3, 'lego '),
( 2, 'lego-city ')
Query 1:
select T1.hashtag,
count(*) as [count]
from YourTable as T1
where exists (
select *
from YourTable as T2
where T2.hashtag = 'toys' and
T1.Product_id = T2.Product_id
) and
T1.hashtag <> 'toys'
group by T1.hashtag
Results:
| HASHTAG | COUNT |
|---------------|-------|
| construction | 1 |
| lego | 2 |
| lego-city | 1 |
try this
select hashtag,count(hashtag) as count from #product_hashtags group by hashtag
CREATE TABLE #Test (ProductID int, Hashtag varchar(30))
INSERT INTO #Test VALUES( 1 ,'toys')
INSERT INTO #Test VALUES( 1 ,'lego')
INSERT INTO #Test VALUES( 1 ,'construction')
INSERT INTO #Test VALUES( 2 ,'toys')
INSERT INTO #Test VALUES( 2 ,'lego')
INSERT INTO #Test VALUES( 2 ,'lego-city')
SELECT * FROM #Test
SELECT * FROM (
SELECT Hashtag, COUNT(ProductID) Counter FROM #Test
GROUP BY Hashtag) as x
where x.Hashtag <> 'toys'
Is this what you want?
Use the query below:
SELECT Hashtag, COUNT(Hashtag)
FROM #Test
WHERE ProductID IN (SELECT ProductID FROM #Test WHERE Hashtag = 'toys')
AND Hashtag <> 'toys'
GROUP BY Hashtag
Given the following:
declare #a table
(
pkid int,
value int
)
declare #b table
(
otherID int,
value int
)
insert into #a values (1, 1000)
insert into #a values (1, 1001)
insert into #a values (2, 1000)
insert into #a values (2, 1001)
insert into #a values (2, 1002)
insert into #b values (-1, 1000)
insert into #b values (-1, 1001)
insert into #b values (-1, 1002)
How do I query for all the values in #a that completely match up with #b?
{#a.pkid = 1, #b.otherID = -1} would not be returned (only 2 of 3 values match)
{#a.pkid = 2, #b.otherID = -1} would be returned (3 of 3 values match)
Refactoring tables can be an option.
EDIT: I've had success with the answers from James and Tom H.
When I add another case in #b, they fall a little short.
insert into #b values (-2, 1000)
Assuming this should return two additional rows ({#a.pkid = 1, #b.otherID = -2} and {#a.pkid = 2, #b.otherID = -2}, it doesn't work. However, for my project this is not an issue.
This is more efficient (it uses TOP 1 instead of COUNT), and works with (-2, 1000):
SELECT *
FROM (
SELECT ab.pkid, ab.otherID,
(
SELECT TOP 1 COALESCE(ai.value, bi.value)
FROM (
SELECT *
FROM #a aii
WHERE aii.pkid = ab.pkid
) ai
FULL OUTER JOIN
(
SELECT *
FROM #b bii
WHERE bii.otherID = ab.otherID
) bi
ON ai.value = bi.value
WHERE ai.pkid IS NULL OR bi.otherID IS NULL
) unmatch
FROM
(
SELECT DISTINCT pkid, otherid
FROM #a a , #b b
) ab
) q
WHERE unmatch IS NOT NULL
Probably not the cheapest way to do it:
SELECT a.pkId,b.otherId FROM
(SELECT a.pkId,CHECKSUM_AGG(DISTINCT a.value) as 'ValueHash' FROM #a a GROUP BY a.pkId) a
INNER JOIN (SELECT b.otherId,CHECKSUM_AGG(DISTINCT b.value) as 'ValueHash' FROM #b b GROUP BY b.otherId) b
ON a.ValueHash = b.ValueHash
You can see, basically I'm creating a new result set for each representing one value for each Id's set of values in each table and joining only where they match.
The following query gives you the requested results:
select A.pkid, B.otherId
from #a A, #b B
where A.value = B.value
group by A.pkid, B.otherId
having count(B.value) = (
select count(*) from #b BB where B.otherId = BB.otherId)
Works for your example, and I think it will work for all cases, but I haven't tested it thoroughly:
SELECT
SQ1.pkid
FROM
(
SELECT
a.pkid, COUNT(*) AS cnt
FROM
#a AS a
GROUP BY
a.pkid
) SQ1
INNER JOIN
(
SELECT
a1.pkid, b1.otherID, COUNT(*) AS cnt
FROM
#a AS a1
INNER JOIN #b AS b1 ON b1.value = a1.value
GROUP BY
a1.pkid, b1.otherID
) SQ2 ON
SQ2.pkid = SQ1.pkid AND
SQ2.cnt = SQ1.cnt
INNER JOIN
(
SELECT
b2.otherID, COUNT(*) AS cnt
FROM
#b AS b2
GROUP BY
b2.otherID
) SQ3 ON
SQ3.otherID = SQ2.otherID AND
SQ3.cnt = SQ1.cnt
-- Note, only works as long as no duplicate values are allowed in either table
DECLARE #validcomparisons TABLE (
pkid INT,
otherid INT,
num INT
)
INSERT INTO #validcomparisons (pkid, otherid, num)
SELECT a.pkid, b.otherid, A.cnt
FROM (select pkid, count(*) as cnt FROM #a group by pkid) a
INNER JOIN (select otherid, count(*) as cnt from #b group by otherid) b
ON b.cnt = a.cnt
DECLARE #comparison TABLE (
pkid INT,
otherid INT,
same INT)
insert into #comparison(pkid, otherid, same)
SELECT a.pkid, b.otherid, count(*)
FROM #a a
INNER JOIN #b b
ON a.value = b.value
GROUP BY a.pkid, b.otherid
SELECT COMP.PKID, COMP.OTHERID
FROM #comparison comp
INNER JOIN #validcomparisons val
ON comp.pkid = val.pkid
AND comp.otherid = val.otherid
AND comp.same = val.num
I've added a few extra test cases. You can change your duplicate handling by changing the way you use distinct keywords in your aggregates. Basically, I'm getting a count of matches and comparing it to a count of required matches in each #a and #b.
declare #a table
(
pkid int,
value int
)
declare #b table
(
otherID int,
value int
)
insert into #a values (1, 1000)
insert into #a values (1, 1001)
insert into #a values (2, 1000)
insert into #a values (2, 1001)
insert into #a values (2, 1002)
insert into #a values (3, 1000)
insert into #a values (3, 1001)
insert into #a values (3, 1001)
insert into #a values (4, 1000)
insert into #a values (4, 1000)
insert into #a values (4, 1001)
insert into #b values (-1, 1000)
insert into #b values (-1, 1001)
insert into #b values (-1, 1002)
insert into #b values (-2, 1001)
insert into #b values (-2, 1002)
insert into #b values (-3, 1000)
insert into #b values (-3, 1001)
insert into #b values (-3, 1001)
SELECT Matches.pkid, Matches.otherId
FROM
(
SELECT a.pkid, b.otherId, n = COUNT(*)
FROM #a a
INNER JOIN #b b
ON a.Value = b.Value
GROUP BY a.pkid, b.otherId
) AS Matches
INNER JOIN
(
SELECT
pkid,
n = COUNT(DISTINCT value)
FROM #a
GROUP BY pkid
) AS ACount
ON Matches.pkid = ACount.pkid
INNER JOIN
(
SELECT
otherId,
n = COUNT(DISTINCT value)
FROM #b
GROUP BY otherId
) AS BCount
ON Matches.otherId = BCount.otherId
WHERE Matches.n = ACount.n AND Matches.n = BCount.n
How do I query for all the values in #a that completely match up with #b?
I'm afraid this definition is not quite perfectly clear. It seems from your additional example that you want all pairs of a.pkid, b.otherID for which every b.value for the given b.otherID is also an a.value for the given a.pkid.
In other words, you want the pkids in #a that have at least all the values for otherIDs in b. Extra values in #a appear to be okay. Again, this is reasoning based on your additional example, and the assumption that (1, -2) and (2, -2) would be valid results. In both of those cases, the a.value values for the given pkid are more than the b.value values for the given otherID.
So, with that in mind:
select
matches.pkid
,matches.otherID
from
(
select
a.pkid
,b.otherID
,count(1) as cnt
from #a a
inner join #b b
on b.value = a.value
group by
a.pkid
,b.otherID
) as matches
inner join
(
select
otherID
,count(1) as cnt
from #b
group by otherID
) as b_counts
on b_counts.otherID = matches.otherID
where matches.cnt = b_counts.cnt
To iterate the point further:
select a.*
from #a a
inner join #b b on a.value = b.value
This will return all the values in #a that match #b
If you are trying to return only complete sets of records, you could try this. I would definitely recommend using meaningful aliases, though ...
Cervo is right, we need an additional check to ensure that a is an exact match of b and not a superset of b. This is more of an unwieldy solution at this point, so this would only be reasonable in contexts where analytical functions in the other solutions do not work.
select
a.pkid,
a.value
from
#a a
where
a.pkid in
(
select
pkid
from
(
select
c.pkid,
c.otherid,
count(*) matching_count
from
(
select
a.pkid,
a.value,
b.otherid
from
#a a inner join #b b
on a.value = b.value
) c
group by
c.pkid,
c.otherid
) d
inner join
(
select
b.otherid,
count(*) b_record_count
from
#b b
group by
b.otherid
) e
on d.otherid = e.otherid
and d.matching_count = e.b_record_count
inner join
(
select
a.pkid match_pkid,
count(*) a_record_count
from
#a a
group by
a.pkid
) f
on d.pkid = f.match_pkid
and d.matching_count = f.a_record_count
)
1) i assume that you don't have duplicate id
2) get the key with the same number of value
3) the row with the number of key value equal to the number of equal value is the target
I hope it's what you searched for (you don't search performance don't you ?)
declare #a table( pkid int, value int)
declare #b table( otherID int, value int)
insert into #a values (1, 1000)
insert into #a values (1, 1001)
insert into #a values (2, 1000)
insert into #a values (2, 1001)
insert into #a values (2, 1002)
insert into #a values (3, 1000)
insert into #a values (3, 1001)
insert into #a values (4, 1000)
insert into #a values (4, 1001)
insert into #b values (-1, 1000)
insert into #b values (-1, 1001)
insert into #b values (-1, 1002)
insert into #b values (-2, 1001)
insert into #b values (-2, 1002)
insert into #b values (-3, 1000)
insert into #b values (-3, 1001)
select cntok.cntid1 as cntid1, cntok.cntid2 as cntid2
from
(select cnt.cnt, cnt.cntid1, cnt.cntid2 from
(select acnt.cnt as cnt, acnt.cntid as cntid1, bcnt.cntid as cntid2 from
(select count(pkid) as cnt, pkid as cntid from #a group by pkid)
as acnt
full join
(select count(otherID) as cnt, otherID as cntid from #b group by otherID)
as bcnt
on acnt.cnt = bcnt.cnt)
as cnt
where cntid1 is not null and cntid2 is not null)
as cntok
inner join
(select count(1) as cnt, cnta.cntid1 as cntid1, cnta.cntid2 as cntid2
from
(select cnt, cntid1, cntid2, a.value as value1
from
(select cnt.cnt, cnt.cntid1, cnt.cntid2 from
(select acnt.cnt as cnt, acnt.cntid as cntid1, bcnt.cntid as cntid2 from
(select count(pkid) as cnt, pkid as cntid from #a group by pkid)
as acnt
full join
(select count(otherID) as cnt, otherID as cntid from #b group by otherID)
as bcnt
on acnt.cnt = bcnt.cnt)
as cnt
where cntid1 is not null and cntid2 is not null)
as cntok
inner join #a as a on a.pkid = cntok.cntid1)
as cnta
inner join
(select cnt, cntid1, cntid2, b.value as value2
from
(select cnt.cnt, cnt.cntid1, cnt.cntid2 from
(select acnt.cnt as cnt, acnt.cntid as cntid1, bcnt.cntid as cntid2 from
(select count(pkid) as cnt, pkid as cntid from #a group by pkid)
as acnt
full join
(select count(otherID) as cnt, otherID as cntid from #b group by otherID)
as bcnt
on acnt.cnt = bcnt.cnt)
as cnt
where cntid1 is not null and cntid2 is not null)
as cntok
inner join #b as b on b.otherid = cntok.cntid2)
as cntb
on cnta.cntid1 = cntb.cntid1 and cnta.cntid2 = cntb.cntid2 and cnta.value1 = cntb.value2
group by cnta.cntid1, cnta.cntid2)
as cntequals
on cntok.cnt = cntequals.cnt and cntok.cntid1 = cntequals.cntid1 and cntok.cntid2 = cntequals.cntid2
Several ways of doing this, but a simple one is to create a union view as
create view qryMyUinion as
select * from table1
union all
select * from table2
be careful to use union all, not a simple union as that will omit the duplicates
then do this
select count( * ), [field list here]
from qryMyUnion
group by [field list here]
having count( * ) > 1
the Union and Having statements tend to be the most overlooked part of standard SQL, but they can solve a lot of tricky issues that otherwise require procedural code
As CQ says, a simple inner join is all you need.
Select * -- all columns but only from #a
from #a
inner join #b
on #a.value = #b.value -- only return matching rows
where #a.pkid = 2