I'm currently working on a SQL query in T-SQL on SQL Server 2012 with the objective to concate or merge several tables into 1 table and concate several rows. So far it's working out fine. I use STUFF and FOR XML PATH to concate several rows into 1.
Unfortunately, when I want to merge my 2 temporary tables into 1 final result table, the concatinated (merged) rows disappear again.
My tables look the following way:
table #BasicOffers
OfferId | Tile | Manager | DeliveryVersionId |
----------+--------+----------+-------------------|
4 | Offer1 | John Doe | 1 |
5 | Offer2 | Jane Doe | 2 |
table #TmpLabels
DeliveryVersionId | Label |
------------------+-------------------------+
1 | Service, Time, Material |
2 | Consulting, Time |
final result, unfortunately not the desired output. the temporary tables seem to be split-up again:
OfferId | Title | Manager | Delivery
----------+--------+----------+------------------------
4 | Offer1 | John Doe | Service
4 | Offer1 | John Doe | Time
4 | Offer1 | John Doe | Material
5 | Offer2 | Jane Doe | Consulting
5 | Offer2 | Jane Doe | Time
Desired Output:
OfferId | Title | Manager | Delivery
----------+--------+----------+------------------------
4 | Offer1 | John Doe | Service, Time, Material
5 | Offer2 | Jane Doe | Consulting, Time
My query to merge the tables looks like this:
-- Delivery Methods
SELECT [D].DeliveryVersionId, [DM].Label
INTO #TmpLabels
FROM [MySchema].[Delivery] [D]
INNER JOIN dbo.DeliveryMethods [DM] ON [DM].DeliveryMethodId = [D].DeliveryMethodId
SELECT DeliveryVersionId,
Label = STUFF(
(SELECT ',' + Label FROM #TmpLabels FOR XML PATH('')), 1, 1, ''
)
FROM #TmpLabels
GROUP BY DeliveryVersionId
-- FinalResults
SELECT [O].OfferId, [O].Title, [O].OfferManager, [DL].Label AS Delivery
FROM #BasicOffers [O]
INNER JOIN #TmpLabels [DL] ON [DL].DeliveryVersionId = [O].DeliveryVersionId
I don't really know, if it's the best solution to store everything into a temporary table and then merge it or to select it all at once.
In any case unfortunately my query seems not to work correctly.
Do you have an idea on how to solve this issue?
Thanks a lot!
;WITH BasicOffers(OfferId,Tile,Manager,DeliveryVersionId )
AS
(
SELECT 4 , 'Offer1' , 'John Doe' , 1 Union all
SELECT 5 , 'Offer2' , 'Jane Doe' , 2
)
,TmpLabels(DeliveryVersionId,Label)
AS
(
SELECT 1 , 'Service, Time, Material ' Union all
SELECT 2 , 'Consulting, Time'
)
Select B.OfferId,B.Tile,B.Manager, T.Label AS Delivery
From BasicOffers B
INNER JOIN TmpLabels T
ON T.DeliveryVersionId=B.DeliveryVersionId
--To COnvert into Comma separated
;WITH Cte_Convert(OfferId,Title,Manager,Delivery )
AS
(
SELECT 4 , 'Offer1' , 'John Doe' , 'Service' Union All
SELECT 4 , 'Offer1' , 'John Doe' , 'Time' Union All
SELECT 4 , 'Offer1' , 'John Doe' , 'Material' Union All
SELECT 5 , 'Offer2' , 'Jane Doe' , 'Consulting' Union All
SELECT 5 , 'Offer2' , 'Jane Doe' , 'Time'
)
Select DISTINCT OfferId,Title,Manager,STUFF((SELECT DISTINCT ',' + CAST(i.Delivery AS VARCHAR(20)) FROM Cte_Convert i
WHERE i.OfferId=o.OfferId
FOR XML PATH ('')),1,1,'')AS Delivery
FROM Cte_Convert o
I Assume either above or below code might be useful
--Split Delivery column as comma separted in below Cte
;WITH Cte_Convert(OfferId,Title,Manager,Delivery )
AS
(
SELECT 4 , 'Offer1' , 'John Doe' , 'Service' Union All
SELECT 4 , 'Offer1' , 'John Doe' , 'Time' Union All
SELECT 4 , 'Offer1' , 'John Doe' , 'Material' Union All
SELECT 5 , 'Offer2' , 'Jane Doe' , 'Consulting' Union All
SELECT 5 , 'Offer2' , 'Jane Doe' , 'Time'
)
,Final
AS
(
SELECT ROW_NUMBER()OVER(Order by (SELECT ''))AS DeliveryVersionId ,* FROM
(
SELECT DISTINCT OfferId,Title,Manager,STUFF((SELECT DISTINCT ',' + CAST(i.Delivery AS VARCHAR(20)) FROM Cte_Convert i
WHERE i.OfferId=o.OfferId
FOR XML PATH ('')),1,1,'')AS Label
FROM Cte_Convert o
)dt
)
,BasicOffers(OfferId,Tile,Manager,DeliveryVersionId )
AS
(
SELECT 4 , 'Offer1' , 'John Doe' , 1 Union all
SELECT 5 , 'Offer2' , 'Jane Doe' , 2
)
,TmpLabels(DeliveryVersionId,Label)
AS
(
SELECT 1 , 'Service, Time, Material ' Union all
SELECT 2 , 'Consulting, Time'
)
Select B.OfferId,B.Tile,B.Manager, T.Label AS Delivery
From BasicOffers B
INNER JOIN Final T
ON T.DeliveryVersionId=B.DeliveryVersionId
I used temporary tables and Left outer join between them to solve it. Please note that I supposed that DeliveryVersionId is a primary Key in the #TmpLabels.
Please let me know if it helps you.
DECLARE #BasicOffers Table (
OfferId int,
Tile varchar(100),
Manager varchar(100),
DeliveryVersionId int)
insert into #BasicOffers values (4,'Offer1','John Doe',1)
insert into #BasicOffers values (5,'Offer2','Jane Doe',2)
DECLARE #TmpLabels Table (
DeliveryVersionId int,
Label varchar(100)
)
insert into #TmpLabels values (1,'Service, Time, Material')
insert into #TmpLabels values (2,'Consulting, Time')
Select OfferId, Tile, Manager, Label as Delivery
From #BasicOffers A Left Outer join
#TmpLabels B on A.DeliveryVersionId=B.DeliveryVersionId
Related
I have the following table with data
+---------+--------+--------+
| Trans | Status | Step |
+---------+--------+--------+
| ABCDE | Comple | 1
+---------+--------+--------+
| ABCDE | Error | 2
+---------+--------+--------+
| FGHIJ | Comple | 1
+---------+--------+--------+
| FGHIJ | Comple | 2
+---------+--------+--------+
| KLMNO | Comple | 1
+---------+--------+--------+
| KLMNO | Comple | 2
+---------+--------+--------+
I only want to delete the records where the count of trans and status = 'comple' is the same as count of trans
I could probably do a cursor and loop but that is something I don't want to do.
Thinking along the lines of a having count but probably miles off.
Thanks
I just want to delete FGHIJ and KLMNO as I know all the steps completed.
I want to keep abcde as not all steps completed
Is this what you want?
--delete
select *
from yourtable t
where not exists
(
select 1
from yourtable t2
where t1.Trans=t2.Trans
and status<>'Comple'
)
Use it as it is first to make sure this is what you want to remove, then comment out the SELECT and uncomment the delete
DELETE FROM tbl
WHERE Trans IN ( SELECT trans
FROM tbl
GROUP BY Trans
HAVING COUNT(*) = SUM(CASE WHEN status = 'Comple' THEN 1 ELSE 0 END) )
It deletes rows (by filtering on Trans), where the number of rows in a group of trans is equal to the number of rows in this group with the Comple status
http://sqlfiddle.com/#!18/1768b/10
Try this
DECLARE #Data AS TABLE (Trans Varchar(10) , Status Varchar(10) , Step INT )
INSERT INTO #Data
SELECT 'ABCDE', 'Comple' , 1 UNION ALL
SELECT 'ABCDE', 'Error' , 2 UNION ALL
SELECT 'FGHIJ', 'Comple' , 1 UNION ALL
SELECT 'FGHIJ', 'Comple' , 2 UNION ALL
SELECT 'KLMNO', 'Comple' , 1 UNION ALL
SELECT 'KLMNO', 'Comple' , 2
SELECT * FROM #Data
;WITH CTe
AS
(
SELECT * , ROW_NUMBER()OVER(PArtition by Trans , [Status] ORDER BY Trans) AS TwocountsMatch
FROM #Data
)
DELETE FROM CTe WHERE TwocountsMatch=2 AND [Status]='Comple'
SELECT * FROM #Data
Demo Result :http://rextester.com/TYK92230
If I understand you correctly, you want to delete all of a [Trans] rows, if all of those rows [status] are 'Comple'?
DECLARE #Data AS TABLE (Trans Varchar(10) , Status Varchar(10) , Step INT )
INSERT INTO #Data
SELECT 'ABCDE', 'Comple' , 1 UNION ALL
SELECT 'ABCDE', 'Error' , 2 UNION ALL
SELECT 'FGHIJ', 'Comple' , 1 UNION ALL
SELECT 'FGHIJ', 'Comple' , 2 UNION ALL
SELECT 'KLMNO', 'Comple' , 1 UNION ALL
SELECT 'KLMNO', 'Comple' , 2
SELECT * FROM #Data;
WITH
summarised
AS
(
SELECT
* ,
COUNT(*) OVER (PARTITION BY [trans] ) AS count_trans,
COUNT(*) OVER (PARTITION BY [trans], [status]) AS count_trans_status
FROM
#Data
)
DELETE
summarised
WHERE
[status] = 'Comple'
AND count_trans = count_trans_status
;
SELECT * FROM #Data
What I have
From the following #MyTable I just have Name and Number columns.
My goal is to fill the valus where Number = NULL with a progressive number and get the values I have wrote into the Desidered_col column.
+------+--------+---------------+
| Name | Number | Desidered_col |
+------+--------+---------------+
| John | 1 | 1 |
| John | 2 | 2 |
| John | 3 | 3 |
| John | NULL | 4 |
| John | NULL | 5 |
| John | 6 | 6 |
| Mike | 1 | 1 |
| Mike | 2 | 2 |
| Mike | NULL | 3 |
| Mike | 4 | 4 |
| Mike | 5 | 5 |
| Mike | 6 | 6 |
+------+--------+---------------+
What I have tried
I have tried with the following query
SELECT Name, Number, row_number() OVER(PARTITION BY [Name] ORDER BY Number ASC) AS rn
FROM #MyTable
but it put all the NULL values first and then count the rows.
How can I fill the empty values?
Why I don't think is a duplicate question
I have read this question and this question but I don't think it is duplicate because they don't consider the PARTITION BY construct.
This is the script to create and populate the table
SELECT *
INTO #MyTable
FROM (
SELECT 'John' AS [Name], 1 AS [Number], 1 AS [Desidered_col] UNION ALL
SELECT 'John' AS [Name], 2 AS [Number], 2 AS [Desidered_col] UNION ALL
SELECT 'John' AS [Name], 3 AS [Number], 3 AS [Desidered_col] UNION ALL
SELECT 'John' AS [Name], NULL AS [Number], 4 AS [Desidered_col] UNION ALL
SELECT 'John' AS [Name], NULL AS [Number], 5 AS [Desidered_col] UNION ALL
SELECT 'John' AS [Name], 6 AS [Number], 6 AS [Desidered_col] UNION ALL
SELECT 'Mike' AS [Name], 1 AS [Number], 1 AS [Desidered_col] UNION ALL
SELECT 'Mike' AS [Name], 2 AS [Number], 2 AS [Desidered_col] UNION ALL
SELECT 'Mike' AS [Name], NULL AS [Number], 3 AS [Desidered_col] UNION ALL
SELECT 'Mike' AS [Name], 4 AS [Number], 4 AS [Desidered_col] UNION ALL
SELECT 'Mike' AS [Name], 5 AS [Number], 5 AS [Desidered_col] UNION ALL
SELECT 'Mike' AS [Name], 6 AS [Number], 6 AS [Desidered_col]
) A
This query is a bit complicated but seems to return your expected result. The only case it may be wrong is when someone does not have Number = 1.
The idea is that you must find gaps between numbers and count how many null values can be used to fill them.
Sample data
create table #myTable (
[Name] varchar(20)
, [Number] int
)
insert into #myTable
insert into #myTable
SELECT 'John' AS [Name], 1 AS [Number] UNION ALL
SELECT 'John' AS [Name], 2 AS [Number]UNION ALL
SELECT 'John' AS [Name], 3 AS [Number] UNION ALL
SELECT 'John' AS [Name], NULL AS [Number] UNION ALL
SELECT 'John' AS [Name], NULL AS [Number] UNION ALL
SELECT 'John' AS [Name], 6 AS [Number] UNION ALL
SELECT 'Mike' AS [Name], 1 AS [Number] UNION ALL
SELECT 'Mike' AS [Name], 2 AS [Number] UNION ALL
SELECT 'Mike' AS [Name], NULL AS [Number] UNION ALL
SELECT 'Mike' AS [Name], 4 AS [Number] UNION ALL
SELECT 'Mike' AS [Name], 5 AS [Number] UNION ALL
SELECT 'Mike' AS [Name], 6 AS [Number]
Query
;with gaps_between_numbers as (
select
t.Name, cnt = t.nextNum - t.Number - 1, dr = dense_rank() over (partition by t.Name order by t.Number)
, rn = row_number() over (partition by t.Name order by t.Number)
from (
select
Name, Number, nextNum = isnull(lead(Number) over (partition by Name order by number), Number + 1)
from
#myTable
where
Number is not null
) t
join master.dbo.spt_values v on t.nextNum - t.Number - 1 > v.number
where
t.nextNum - t.Number > 1
and v.type = 'P'
)
, ordering_nulls as (
select
t.Name, dr = isnull(q.dr, 2147483647)
from (
select
Name, rn = row_number() over (partition by Name order by (select 1))
from
#myTable
where
Number is null
) t
left join gaps_between_numbers q on t.Name = q.Name and t.rn = q.rn
)
, ordering_not_null_numbers as (
select
Name, Number, rn = dense_rank() over (partition by Name order by gr)
from (
select
Name, Number, gr = sum(lg) over (partition by Name order by Number)
from (
select
Name, Number, lg = iif(Number - lag(Number) over (partition by Name order by Number) = 1, 0, 1)
from
#myTable
where
Number is not null
) t
) t
)
select
Name, Number
, Desidered_col = row_number() over (partition by Name order by rn, isnull(Number, 2147483647))
from (
select * from ordering_not_null_numbers
union all
select Name, null, dr from ordering_nulls
) t
CTE gaps_between_numbers is seeking for numbers that are not consecutive. Number difference between current and next row shows how many NULL values can be used to fill the gaps. Then master.dbo.spt_values is used to multiply each row by that amount. In gaps_between_numbers dr column is gap number and cnt is amount of NULL values that need to used.
ordering_nulls orders only NULL values and is joined with CTE gaps_between_numbersto know in which position each row should appear.
ordering_not_null_numbers orders values that are not NULL. Consecutive Numbers will have same row number
And last step is to union CTE's ordering_not_null_numbers and ordering_nulls and make desired ordering
Rextester DEMO
In order to do this, you need a column that specifies the order of the rows in the table. You can do this using the identity() function:
SELECT identity(int, 1, 1) as MyTableId, a.*
INTO #MyTable
. . .
I'm pretty sure SQL Server will follow the ordering of a values() statement and in practice will follow the ordering of a union all. You can explicitly put this column in each row, if you prefer.
Then you can use this to assign your value:
select t.*,
row_number() over (partition by name order by mytableid) as desired_col
from #MyTable
You could also assign the new ranking based on Desidered_col using row_number() function with ORDER BY clause (select 1 or select null)
select *,
row_number() over (partition by Name order by (select 1)) New_Desidered_col
from #MyTable
These are the 2 tables.
Tech_data:
Id Tech Agent1_id Agent2_ID
1 JAVA 1 2
2 SQL 3 4
Agent_table
Id Name
1 Mike
2 John
3 Jim
4 Baron
I need to write a query to bring the below output
TECH_ID Tech Agent1_Name Agent2_Name
1 Java Mike John
2 SQL Jim Baron
I wrote LEFT OUTER JOIN ON tech_id=agent1_id, but i do not know how to join 2 ids in ON condition.
To prevent having to do multiple joins to the same table, you can unpivot, join and then pivot (then if you had 50 ID columns you would still only need to perform one join):
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE Tech_data (Id, Tech, Agent1_id, Agent2_ID ) AS
SELECT 1, 'JAVA', 1, 2 FROM DUAL UNION ALL
SELECT 2, 'SQL', 3, 4 FROM DUAL;
CREATE TABLE Agent_table ( Id, Name ) AS
SELECT 1, 'Mike' FROM DUAL UNION ALL
SELECT 2, 'John' FROM DUAL UNION ALL
SELECT 3, 'Jim' FROM DUAL UNION ALL
SELECT 4, 'Baron' FROM DUAL;
Query 1:
SELECT *
FROM (
SELECT t.id,
t.tech,
t.num,
a.name
FROM (
SELECT *
FROM tech_data
UNPIVOT ( Agent_ID FOR num IN ( Agent1_id AS 1, Agent2_id AS 2 ) )
) t
INNER JOIN Agent_table a
ON ( t.agent_id = a.id )
)
PIVOT ( MAX( name ) FOR num IN ( 1 AS Agent1_Name, 2 AS Agent2_Name ) )
Results:
| ID | TECH | AGENT1_NAME | AGENT2_NAME |
|----|------|-------------|-------------|
| 1 | JAVA | Mike | John |
| 2 | SQL | Jim | Baron |
You can add a second left outer join just like the one you have used, on the same table by giving them different aliases as follows.
select t.Id tech_id, t.tech, a1.name, a2.name
from tech_data t
left outer join agent_table a1 on a1.Id = t.agent1_id
left outer join agent_table a2 on a2.Id = t.agent2_Id;
Check the fiddle below:
http://sqlfiddle.com/#!4/73f02b/1
I Have three tables like bellow
**tRole**
+--------+----------+-----------+
| RoleID | RoleCode | RoleTitle |
+--------+----------+-----------+
| 1 | Role1 | RT1 |
| 2 | Role2 | RT2 |
| 3 | Role3 | RT3 |
+--------+----------+-----------+
**tEmployee**
+-------+-------+
| EmpID | Name |
+-------+-------+
| 1 | Emp 1 |
| 2 | Emp 2 |
| 3 | Emp 3 |
+-------+-------+
**tEmployeeRole**
+-------+--------+
| EmpID | RoleID |
+-------+--------+
| 1 | 1 |
| 1 | 2 |
| 2 | 1 |
| 2 | 2 |
| 3 | 3 |
+-------+--------+
I want a output like below ,If a role mapped with only one employee then employee name will show other wise Multiple will show.
+--------+----------+-----------+----------+
| RoleID | RoleCode | RoleTitle | Employee |
+--------+----------+-----------+----------+
| 1 | Role1 | RT1 | Multiple |
| 2 | Role2 | RT2 | Multiple |
| 3 | Role3 | RT3 | Emp 3 |
+--------+----------+-----------+----------+
I write bellow query but when I group by emp.First_Name then the result is wrong
select cr.RoleCode,cr.RoleID,
case
when count(ear.RoleID)=1 then emp.First_Name
else 'M' end as 'AssignedTO'
from tRole as cr
left outer join tEmployeeRole as ear on cr.RoleID=ear.RoleID
left outer join tEmployee as emp on ear.EmployeeID=emp.EmployeeID
group by cr.RoleCode,crRoleID,emp.First_Name
Hello You can use this query for your solution :
you need to count with partition and use distinct data
DECLARE #tRole TABLE (
RoleID INT
,RoleCode VARCHAR(50)
,RoleTitle VARCHAR(50)
)
DECLARE #tEmployee TABLE (
EmpID INT
,EmpName VARCHAR(50)
)
DECLARE #tEmployeeRole TABLE ( EmpID INT, RoleID INT )
INSERT #tRole ( RoleID, RoleCode, RoleTitle )
SELECT 1, 'Role1', 'RT1'
UNION
SELECT 2, 'Role2', 'RT2'
UNION
SELECT 3, 'Role3', 'RT3'
INSERT #tEmployee ( EmpID, EmpName )
SELECT 1, 'Epm 1'
UNION
SELECT 2, 'Epm 2'
UNION
SELECT 3, 'Epm 3'
INSERT #tEmployeeRole ( EmpID, RoleID )
SELECT 1, 1
UNION
SELECT 1, 2
UNION
SELECT 2, 1
UNION
SELECT 2, 2
UNION
SELECT 3, 3
SELECT DISTINCT tRole.RoleID
, RoleCode
, RoleTitle
, CASE WHEN COUNT(tEmployeeRole.EmpID) OVER ( PARTITION BY tEmployee.EmpID ) = 1 THEN tEmployee.EmpName ELSE 'Multiple'END [Employee]
FROM #tEmployee tEmployee
LEFT OUTER JOIN #tEmployeeRole tEmployeeRole ON tEmployeeRole.EmpID = tEmployee.EmpID
LEFT OUTER JOIN #tRole tRole ON tRole.RoleID = tEmployeeRole.RoleID
You can Modify the answer from #Pratik to add a col that lists the employees
;with CTE as(
SELECT
DISTINCT tRole.RoleID
RoleCode
, RoleTitle
, CASE WHEN COUNT(tEmployeeRole.EmpID) OVER ( PARTITION BY tEmployee.EmpID ) = 1 THEN tEmployee.EmpName ELSE 'Multiple'END [Employee]
FROM #tEmployee tEmployee
LEFT OUTER JOIN #tEmployeeRole tEmployeeRole ON tEmployeeRole.EmpID = tEmployee.EmpID
LEFT OUTER JOIN #tRole tRole ON tRole.RoleID = tEmployeeRole.RoleID
)
select *
,stuff( (select ','+EmpName from #tEmployee IE inner join #tEmployeeRole IER on IE.EmpID = IER.EmpID where IER.RoleID = CTE.rolecode for xml PATH('') ),1,1,'') AS EMList
from CTE
This query might help you out . Make a try
Your Tables Data looks like
create TABLE #tRole (RoleID INT ,RoleCode VARCHAR(50) ,RoleTitle VARCHAR(50) )
create TABLE #tEmployee (EmpID INT ,EmpName VARCHAR(50) )
create TABLE #tEmployeeRole( EmpID INT, RoleID INT )
INSERT #tRole ( RoleID, RoleCode, RoleTitle )
SELECT 1, 'Role1', 'RT1'
UNION
SELECT 2, 'Role2', 'RT2'
UNION
SELECT 3, 'Role3', 'RT3'
INSERT #tEmployee ( EmpID, EmpName )
SELECT 1, 'Epm 1'
UNION
SELECT 2, 'Epm 2'
UNION
SELECT 3, 'Epm 3'
INSERT #tEmployeeRole ( EmpID, RoleID )
SELECT 1, 1
UNION
SELECT 1, 2
UNION
SELECT 2, 1
UNION
SELECT 2, 2
UNION
SELECT 3, 3
Desired Query
;with cte as
(
select tr.roleid,tr.rolecode,tr.roletitle,te.empname
,COUNT(ter.EmpID) OVER ( PARTITION BY ter.EmpID ) as emp_count
from #tEmployee te
inner join #tEmployeeRole tER on tER.empid=te.empid
inner join #tRole tr on tr.roleid=ter.roleid
)
select distinct RoleID,RoleCode,RoleTitle
,case when emp_count>1 then 'Multiple' else empname end as Employee
from cte
Needing some help with SQL Server select query here.
I have the following tables defined:
UserSource
UserSourceID ID Name Dept SourceID
1 1 John AAAA 1
2 1 John AAAA 2
3 2 Nena BBBB 1
4 2 Nena BBBB 2
5 3 Gord AAAA 2
6 3 Gord AAAA 1
7 4 Stan CCCC 3
Source
SourceID Description RankOrder
1 FromHR 1
2 FromTemp 2
3 Others 3
Need to join both tables and select only the row where the rank is the smallest. Such that the resulting row would be:
UserSourceID ID Name Dept SourceID Description RankOrder
1 1 John AAAA 1 FromHR 1
3 2 Nena BBBB 1 FromHR 1
6 3 Gord AAAA 1 FromHR 1
7 4 Stan CCCC 3 Others 3
TIA.
Edit:
Here's what I have come up so far, but I seem to be missing something:
WITH
TableA AS(
SELECT 1 AS UserSourceID, 1 AS ID, 'John' AS [Name], 'AAAA' as [Dept], 1 as SourceID
UNION SELECT 2, 1, 'John', 'AAAA', 2
UNION SELECT 3, 2, 'Nena', 'BBBB', 1
UNION SELECT 4, 2, 'Nena', 'BBBB', 2
UNION SELECT 5, 3, 'Gord', 'AAAA', 2
UNION SELECT 6, 3, 'Gord', 'AAAA', 1
UNION SELECT 7, 4, 'Stan', 'DDDD', 3)
,
TableB AS(
SELECT 1 as SourceID, 'FromHR' as [Description], 1 as RankOrder
UNION SELECT 2, 'FromTemp', 2
UNION SELECT 3, 'Others', 3
)
SELECT DISTINCT tblA.*, tblB.SourceID, tblB.Description
FROM TableB tblB
JOIN TableA tblA ON tblA.SourceID = tblB.SourceID
LEFT JOIN TableB b2 ON b2.SourceID = tblB.SourceID
AND B2.RankOrder < tblB.RankOrder
WHERE B2.SourceID IS NULL
UPDATE:
I scanned the tables and there might be some variations of data. I have updated the data for the question as above.
Practically, I need to join these two tables, and be able to only select the row which would have the least RankOrder. In case of record UserSourceID = 7, that particular record would be selected because there's only one row that exists after the tables have been joined.
I use windowed aggregates for this type of solution pretty regularly. ROW_NUMBER will order and number the rows based on the PARTITION and ORDER you specify in the OVER clause.
select UserSoruceID
, ID
, Name
, Dept
, SourceID
, Description
, RankOrder
FROM (SELECT UserSoruceID
, ID
, Name
, Dept
, u.SourceID
, Description
, RankOrder
, ROW_NUMBER() over(PARTITION BY ID ORDER BY RankOrder) ranknum
FROM UserSource u
INNER JOIN
Source s
on s.SourceID = u.SourceID ) a
WHERE ranknum = 1
So in this case, for every ID, number the rows based on RankOrder, and then filter where so you only view the first row.
Here's a helpful link to that function from Microsoft. ROW_NUMBER
----UPDATE----
Here's with Rank and Row Number as options.
select UserSoruceID
, ID
, Name
, Dept
, SourceID
, Description
, RankOrder
FROM (SELECT UserSoruceID
, ID
, Name
, Dept
, u.SourceID
, Description
, RankOrder
, ROW_NUMBER() over(PARTITION BY ID ORDER BY RankOrder) row_num
, RANK() over(PARTITION BY ID ORDER BY RankOrder) rank_num --use this if you want to see the duplicate records
FROM UserSource u
INNER JOIN
Source s
on s.SourceID = u.SourceID ) a
WHERE row_num = 1 --rank_num = 1
Replace row_num with rank_num to view any items with duplicate RankOrder entries