Reputation: 329
I have a column "Designation" in which for some employees there are multiple values. So I want to keep only 1 value in it and also assign that value based on its priority from "designation priority table". example:
Agentdetails:
accountid designation
1455 owner / Ceo
2035 /Application Consultant/Director
1233 /General / It
1453 /Hrd/It Support/Engineering/It Mgr/ Assistant Marketing Manager
Designation Priority:
CEO/Application Consultant/IT Mgr/IT 1
Owner/Director 2
It staff/HRD 1
so now as per the priority my agentdetails table should look like:
accountid designation
1455 Ceo ( as ceo is 1 so it should be taken and rest values should be removed)
2035 Application Consultant
1233 It ( as there is no general and it value is 1)
1453 Hrd (Here hrd as it's value is 1 and comes first )
Let me know how to achieve this in SQL. Is there any function or do I need to create a UDF?
Let me know any suggestions.
Upvotes: 0
Views: 277
Reputation: 12959
You have to use STRING_SPLIT to split the multi-valued string into separate rows for each table and then join them to get the result.
Even though below code works, I would suggest you make few changes to the datamodel and data quality issues:
Test setup
CREATE TABLE AgentDetails
(accountid int, designation VARCHAR(8000))
INSERT INTO AgentDetails
VALUES
('1455','owner / Ceo'),
('2035','/Application Consultant/Director'),
('1233','/General / It'),
('1453','/Hrd/It Support/Engineering/It Mgr/ Assistant Marketing Manager')
;
CREATE TABLE DesignationPriority
(Designation VARCHAR(8000), Priority int)
INSERT INTO DesignationPriority
VALUES
('CEO/Application Consultant/IT Mgr/IT',1),
('Owner/Director', 2),
('It staff/HRD', 1);
Query to Execute
;WITH CTE_AgentDetails AS
(
SELECT accountId, TRIM(value) AS Designation
FROM AgentDetails
CROSS APPLY STRING_SPLIT(designation,'/')
WHERE LEN(value) > 0
), CTE_DesignationPriority AS
(
SELECT Priority, TRIM(value) AS Designation
FROM DesignationPriority
CROSS APPLY STRING_SPLIT(Designation,'/')
)
SELECT accountID, Designation
FROM
(
SELECT accountID
,a.Designation
, ROW_NUMBER() OVER(PARTITION BY a.AccountID ORDER BY CASE WHEN p.Priority IS NULL THEN 999 ELSE p.priority END) AS rnk
FROM
CTE_AgentDetails AS a
LEFT OUTER JOIN CTE_DesignationPriority AS p
ON p.Designation = a.Designation
) AS t
WHERE rnk = 1;
If you dont want CTE, you can go for derived table.
SELECT accountID, Designation
FROM
(
SELECT accountID
,a.Designation
, ROW_NUMBER() OVER(PARTITION BY a.AccountID ORDER BY CASE WHEN p.Priority IS NULL THEN 999 ELSE p.priority END) AS rnk
FROM
(SELECT accountId, TRIM(value) AS Designation
FROM AgentDetails
CROSS APPLY STRING_SPLIT(designation,'/')
WHERE LEN(value) > 0)AS a
LEFT OUTER JOIN
(SELECT Priority, TRIM(value) AS Designation
FROM DesignationPriority
CROSS APPLY STRING_SPLIT(Designation,'/')) AS p
ON p.Designation = a.Designation
) AS t
WHERE rnk = 1;
Resultset
+-----------+------------------------+
| accountID | Designation |
+-----------+------------------------+
| 1233 | It |
| 1453 | Hrd |
| 1455 | Ceo |
| 2035 | Application Consultant |
+-----------+------------------------+
Upvotes: 1