I am trying to combine many columns together to create a full string.
This is what I mean:
I have a table named QRFormats that looks like this:
| Id | Text1 | Variable1 | Text2 | Variable2 | Text3 | Variable3 |
| 1 | The Color | Color | Is designated | Description | *NULL* | *NULL* |
| 2 | The Company | Company| Is Located | Location| In Country | Country|
| 3 | The Part is | PartNumber| Work Order:| WorkOrder| *NULL* | CompanyCode |
.
.
The complete string should print the Text and lookup the Variable in completely different table using FK/PK correlations.
All the Variables are located in two possible tables called PartData and Company
PartData
| Id | PartNumber | Color | WorkOrder | Description |
| 1 | 123456789 | Blue | 111222333 | Microchip |
| 2 | 101441414 | Silver | 55556666 | Handel |
Company
| Id | Company | Location | CompanyCode | Country |
| 1 | Microsoft | Seattle | 1234 | USA |
| 2 | Apple | California | 1122 | USA |
.
Some Examples of what I am trying to do....
.
The Complete string should look as follows if my:
-QRFormats FK is a 1:
-PartDataFK is a 1:
-Company FK is a 1:
"The Color Blue Is designated Microchip"
.
The Complete string should look as follows if my:
-QRFormats FK is a 2:
-PartDataFK is a 1:
-Company FK is a 3:
"The Company Apple Is Located California In Country USA"
.
The Complete string should look as follows if my:
-QRFormats FK is a 3:
-PartDataFK is a 2:
-Company FK is a 1:
"The Part is 101441414 WorkOrder: 555566661234"
.
Thank you very much for you help, I am using SSIS in VisualStudio 2015.
This is a very interesting request. First the DML:
create table #QFR
(
Id int
, Text1 varchar(100)
, Variable1 varchar(100)
, Text2 varchar(100)
, Variable2 varchar(100)
, Text3 varchar(100)
, Variable3 varchar(100)
)
insert into #QFR
values
( 1,' The Color ','Color',' Is designated ','Description ',NULL ,NULL )
,( 2,' The Company ','Company',' Is Located ','Location',' In Country ','Country' )
,( 3,' The Part is ','PartNumber','Work Order:','WorkOrder',NULL ,'CompanyCode' )
create table #parts
(
Id int
, PartNumber varchar(100)
, Color varchar(100)
, WorkOrder varchar(100)
, Description varchar(100)
)
insert into #parts
values
(1,'123456789','Blue ','111222333',' Microchip '),
(2,'101441414','Silver ','55556666',' Handel ')
create table #company
(
Id int
, Company varchar(100),
Location varchar(100)
, CompanyCode varchar(100)
, Country varchar(100)
)
insert into #company
values
(1,' Microsoft ','Seattle ','1234',' USA ')
,(2,' Apple ','California ','1122',' USA ')
I create a CTE to flip the variable logic on its side and joined it in several times to make this work...
declare #qID int = 1
,#pID int = 1
,#cID int = 1
;with cte as
(
select Label,Value
from #parts
cross apply (values('PartNumber',PartNumber),('Color',Color),('WorkOrder',WorkOrder),('Description',Description)) as a(Label,Value)
where id =#pID
union all
select Label,Value
from #company
cross apply (values('Company',Company),('Location',Location),('CompanyCode',CompanyCode),('Country',Country)) as a(Label,Value)
where id =#cID
)
select Text1 , t1.Value , text2 , t2.Value , text3 , t3.Value
from #QFR q
left join cte t1 on q.Variable1=t1.Label
left join cte t2 on t2.Label = q.Variable2
left join cte t3 on t3.label = q.Variable3
where q.id = #qID
Changed to a function:
create function fn_BuildAsentence (#qID int
,#pID int
,#cID int)
returns varchar(max)
as
BEGIN
declare #v varchar(Max)
;with cte as
(
select Label,Value
from parts
cross apply (values('PartNumber',PartNumber),('Color',Color),('WorkOrder',WorkOrder),('Description',Description)) as a(Label,Value)
where id =#pID
union all
select Label,Value
from company
cross apply (values('Company',Company),('Location',Location),('CompanyCode',CompanyCode),('Country',Country)) as a(Label,Value)
where id =#cID
)
select #v = concat(Text1 , t1.Value , text2 , t2.Value , text3 , t3.Value)
from QFR q
left join cte t1 on q.Variable1=t1.Label
left join cte t2 on t2.Label = q.Variable2
left join cte t3 on t3.label = q.Variable3
where q.id = #qID
return #v
END
Finally, I would use a SQL Source (I presume that you are doing this in a data flow to go somewhere)
Select dbo.fn_BuildAsentence(QFR,parts,company),QFR,parts,company
from [whereever]
Related
I have 2 tables like this
[Table 1]:
|cust_id| tran |item |
| ------| -----|-------
| id1 | 123 |a,b,c |
| id2 | 234 |b,b |
| id3 | 345 |c,d,a,b|
[Table 2]:
| item. | value |
| ----- | ----- |
| a | 1 |
| b | 2 |
| c | 3 |
| d | 4 |
I want to create a target value by doing a lookup from table 2 in table 1 using big query.
|cust_id| tran.|item |target|
| ------| -----|------|------|
| id1 | 123 |a,b,c | 6
| id2 | 234 |b,b | 4
| id3 | 345 |c,d,a,b| 10
What can I try next?
Consider below simple approach
select *,
( select sum(value)
from unnest(split(item)) item
join table2
using (item)
) target
from table1
if applied to sample data in your question - output is
Try the following:
select t1.cust_id
, t1.tran
, t1.item
, sum(t2.value) as target
from table_1 t1
, UNNEST(split(t1.item ,',')) as item_unnested
LEFT JOIN table_2 t2
on item_unnested=t2.item
group by t1.cust_id
, t1.tran
, t1.item
With your data it gives the following:
Create a center table that splits the item column values on rows and join that table with table2.
Try following
--Cursor is used to split the item data row by row
--#temp is a temporary table
create table #temp (id varchar(10), trans varchar(10), item varchar(10), item1 varchar(10));
DECLARE #item varchar(10);
DECLARE #id varchar(10);
DECLARE #trans varchar(10);
DECLARE item_cusor CURSOR FOR
SELECT *
FROM table1;
OPEN item_cusor
FETCH NEXT FROM item_cusor
INTO #id,#trans,#item
WHILE ##FETCH_STATUS = 0
BEGIN
insert into #temp
SELECT #id,#trans,#item,*
FROM STRING_SPLIT (#item, ',')
FETCH NEXT FROM item_cusor
INTO #id,#trans,#item
END
CLOSE item_cusor;
DEALLOCATE item_cusor;
--select * from temp
select t.id as cust_id, t.trans,t.item , sum(cast(t2.value as int)) as target
from #temp t
JOIN table2 t2
on t.item1=t2.item
group by t.id, t.trans,t.item;
Cursors: https://www.c-sharpcorner.com/article/cursors-in-sql-server/
Temporary tables: https://www.sqlservertutorial.net/sql-server-basics/sql-server-temporary-tables/
String split function: https://learn.microsoft.com/en-us/sql/t-sql/functions/string-split-transact-sql
I'm using a Confluence Web page, which display a dropdown list based on a database function. This function have no parameter. This function returns results of a view.
When I begin to entered some text on the textfield, the dropdown list result show data sort.
By instance:
text entered : toto
dropdown list list result :
aaa.toto.aim
aaa.toto.becare
toto
toto.aim
toto.aim.thisis
toto.becare
toto.becare.xxx
the view has multiple columns : code_part1, code_part2, code_part3, fullcode (correspond to result display, concatenation of code_part1 + '.' + code_part2 + '.' + code_part3 ) :
fullcode | code_part1 | code_part2 | code_part3
aaa.toto.aim | aaa | toto | aim
aaa.toto.becare | aaa | toto | becare
toto | toto | (null) | (null)
toto.aim | toto | aim | (null)
toto.aim.thisis | toto | aim | thisis
toto.becare | toto | becare | (null)
toto.becare.xxx | toto | becare | xxx
How it's possible update the function with the order by clause depending on what I entered on text box ("toto" here) :
toto
toto.aim
toto.aim.thisis
toto.becare
toto.becare.xxx
aaa.toto.aim
aaa.toto.becare
you can make use of case in order by
DECLARE #SearchString CHAR ='toto'
SELECT fullcode
FROM TABLENAME
ORDER BY CASE WHEN part1 = #SearchString THEN part1 WHEN part2 = #SearchString THEN PART2 ELSE part3 END
try this,
declare #t table(fullcode varchar(50),code_part1 varchar(50), code_part2 varchar(50), code_part3 varchar(50))
insert INTO #t VALUES
('aaa.toto.aim' ,'aaa' , 'toto' , 'aim' )
,('aaa.toto.becare' ,'aaa' , 'toto' , 'becare' )
,('toto' ,'toto' , null , null )
,('toto.aim' ,'toto' , 'aim' , null )
,('toto.aim.thisis' ,'toto' , 'aim' , 'thisis' )
,('toto.becare' ,'toto' , 'becare' , null )
,('toto.becare.xxx' ,'toto' , 'becare', 'xxx' )
declare #key varchar(50)='toto'
select *,1 rownum from #t where code_part1=#key
union ALL
select *,2 rownum from #t where code_part2=#key
union ALL
select *,3 rownum from #t where code_part3=#key
I have a table in database which contains hospital names as follow:
+------------+--------------+
| HospitalID | HospitalName |
+------------+--------------+
| 1 | Hosp1 |
| 2 | Hosp2 |
| 3 | Hosp3 |
| 4 | Hosp4 |
+------------+--------------+
Another table also exist which contains activity names as follows:
+------------+--------------+
| ActivityID | ActivityName |
+------------+--------------+
| 1 | Act1 |
| 2 | Act2 |
| 3 | Act3 |
| 4 | Act4 |
| 5 | Act5 |
+------------+--------------+
There's a N*M relation between these tables, i.e. each hospital can operate different activities. Therefore another table is required as follows:
+----+------------+------------+
| ID | HospitalID | ActivityID |
+----+------------+------------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 5 |
| 4 | 2 | 1 |
| 5 | 2 | 3 |
| 6 | 3 | 2 |
+----+------------+------------+
I want to write a select statement which selects hospital names and their related activities in a string field as follows:
+--------------+------------------+
| HospitalName | ActivityNames |
+--------------+------------------+
| Hosp1 | Act1, Act2, Act5 |
| Hosp2 | Act1, Act3 |
| Hosp3 | Act2 |
| Hosp4 | |
+--------------+------------------+
I have written the select statement using a function for ActivityNames field using a cursor but it is not optimized and the system performance decreases as the number of records increases.
Any solution or suggestion on how to solve this problem?
You can do this just with a select. No need of looping or Cursor for this. Looping will make performance degrade.
So the Schema will be
CREATE TABLE #HOSPITAL( HOSPITALID INT, HOSPITALNAME VARCHAR(20))
INSERT INTO #HOSPITAL
SELECT 1, 'HOSP1'
UNION ALL
SELECT 2 , 'HOSP2'
UNION ALL
SELECT 3 ,'HOSP3'
UNION ALL
SELECT 4 , 'HOSP4'
CREATE TABLE #ACTIVITY( ActivityID INT, ActivityName VARCHAR(50) )
INSERT INTO #ACTIVITY
SELECT 1, 'Act1'
UNION ALL
SELECT 2, 'Act2'
UNION ALL
SELECT 3, 'Act3'
UNION ALL
SELECT 4, 'Act4'
UNION ALL
SELECT 5, 'Act5'
CREATE TABLE #HOSPITAL_ACT_MAP(ID INT, HospitalID INT, ActivityID INT)
INSERT INTO #HOSPITAL_ACT_MAP
SELECT 1, 1, 1
UNION ALL
SELECT 2, 1, 2
UNION ALL
SELECT 3, 1, 5
UNION ALL
SELECT 4, 2, 1
UNION ALL
SELECT 5, 2, 3
UNION ALL
SELECT 6, 3, 2
And do Select like below with CTE
;WITH CTE AS (
SELECT DISTINCT H.HOSPITALNAME, A.ActivityName FROM #HOSPITAL_ACT_MAP HA
INNER JOIN #HOSPITAL H ON HA.HospitalID = H.HOSPITALID
INNER JOIN #ACTIVITY A ON HA.ActivityID = A.ActivityID
)
SELECT HOSPITALNAME
, (SELECT STUFF((SELECT ','+ActivityName FROM CTE C1
WHERE C1.HOSPITALNAME = C.HOSPITALNAME
FOR XML PATH('')),1,1,''))
FROM CTE C
GROUP BY HOSPITALNAME
Edit from Comments
If you can't use CTE and Stuff go for Method 2
DECLARE #TAB TABLE (HOSPITALNAME VARCHAR(20),ActivityName VARCHAR(20) )
INSERT INTO #TAB
SELECT DISTINCT H.HOSPITALNAME, A.ActivityName FROM #HOSPITAL_ACT_MAP HA
INNER JOIN #HOSPITAL H ON HA.HospitalID = H.HOSPITALID
INNER JOIN #ACTIVITY A ON HA.ActivityID = A.ActivityID
SELECT HOSPITALNAME, SUBSTRING(ACTIVITIES,1, LEN(ACTIVITIES)-1) FROM(
SELECT DISTINCT HOSPITALNAME,(SELECT ActivityName+',' FROM #TAB T1
WHERE T1.HOSPITALNAME = T.HOSPITALNAME
FOR XML PATH('') ) AS ACTIVITIES FROM #TAB T
)A
Note: For the performance purpose I have stored the Intermediate result on #TAB (Table variable). If you want you can directly Query it with Sub Query.
using STUFF function to achieve your result :
CREATE TABLE #Hospital(HospitalID INT,HospitalName VARCHAR(100))
CREATE TABLE #Activity(ActivityID INT,ActivityName VARCHAR(100))
CREATE TABLE #RelationShip(Id INT,HospId INT,ActId INT)
CREATE TABLE #ConCat(HospitalID INT ,HospName VARCHAR(100), ActName
VARCHAR(100),UpFlag TINYINT DEFAULT(0))
DECLARE #HospId INT = 0,#String VARCHAR(200) = ''
INSERT INTO #Hospital(HospitalID ,HospitalName )
SELECT 1,'Hosp1' UNION ALL
SELECT 2,'Hosp2' UNION ALL
SELECT 3,'Hosp3' UNION ALL
SELECT 4,'Hosp4'
INSERT INTO #Activity(ActivityID ,ActivityName )
SELECT 1,'Act1' UNION ALL
SELECT 2,'Act2' UNION ALL
SELECT 3,'Act3' UNION ALL
SELECT 4,'Act4' UNION ALL
SELECT 5,'Act5'
INSERT INTO #RelationShip(ID,HospId,ActId)
SELECT 1 , 1 , 1 UNION ALL
SELECT 2 , 1 , 2 UNION ALL
SELECT 3 , 1 , 5 UNION ALL
SELECT 4 , 2 , 1 UNION ALL
SELECT 5 , 2 , 3 UNION ALL
SELECT 6 , 3 , 2
SELECT HospitalName , STUFF( ( SELECT ',' + ActivityName FROM #Activity
JOIN #RelationShip ON ActId = ActivityID WHERE HospId = HospitalID FOR XML
PATH('') ),1,1,'')
FROM #Hospital
GROUP BY HospitalID,HospitalName
***FOR SQLServer2005 Use below code***
INSERT INTO #ConCat (HospitalID ,HospName)
SELECT DISTINCT HospitalID ,HospitalName
FROM #Hospital
WHILE EXISTS(SELECT 1 FROM #ConCat WHERE UpFlag = 0)
BEGIN
SELECT #HospId = HospitalID FROM #ConCat WHERE UpFlag = 0 ORDER BY
HospitalID
SET #String = ''
SELECT #String = ISNULL(#String,'') + CAST(A.ActivityName AS VARCHAR) +
',' FROM
(
SELECT ActivityName
FROM #RelationShip
JOIN #Activity ON ActId = ActivityID
WHERE HospId = #HospId
) A
UPDATE #ConCat SET UpFlag = 1,ActName = CASE WHEN #String = '' THEN
#String ELSE SUBSTRING(#String,0,LEN(#String) ) END WHERE HospitalID
= #HospId
END
SELECT * FROM #ConCat
You can use json to increase the performance of front end.
There is no particular solution if you are using open source databases.
Try to use IBM db2 or ORACLE database to ensure performance of your app.
then generate json data . You will find the improvement in speed
I got a lookup list table of valid US state abbreviations and a source table:
States lookup and Source tables respectively
+-------+ +-----------------+
|States | |ID | Location |
+=======+ +=================+
| AK | | 1 | Madrid |
--------- -------------------
| AL | | 2 | AK |
--------- -------------------
| AR | | 3 | AR |
--------- -------------------
| ... | | ..| ... |
--------- -------------------
How do I create an INSERT statement into a Target table such that if Location is a valid state, it will be placed in the State column and if it's not, it would be placed in the Other Locale column?
Expected Target table output
+------------+-----------------
|ID | State | Other Locale |
+============+=================
| 1 | | Madrid |
-------------------------------
| 2 | AK | |
-------------------------------
| 3 | AR | |
-------------------------------
| ..| ... | ... |
-------------------------------
Since nobody has suggested using NULLIF i might as well throw that in.
DECLARE #Location TABLE (Id INT, Location VARCHAR(MAX))
DECLARE #States TABLE (States VARCHAR(MAX))
INSERT INTO #Location VALUES
(1, 'Madrid'), (2, 'AK'), (3, 'AR')
INSERT INTO #States VALUES
('AK'), ('AL'), ('AR')
SELECT l.Id,
s.States [State],
NULLIF(l.Location,s.States) [Other Locale]
FROM #Location l
LEFT JOIN #States s ON l.Location = s.States
Do a LEFT JOIN and check for NULLs due to non-matching states:
insert into target
select source.id, states.state,
case when states.state is null then location end as Other_Locale
from source left join states
on source.location = states.state
You could use an left join and pick the column value depending on match:
SELECT so.ID, CASE WHEN States.States IS NOT NULL THEN so.Location END,
CASE WHEN States.States IS NULL THEN so.Location END
FROM Source so LEFT JOIN States
ON States.States = so.Location
See SQLFiddle
Then of course you can insert that to whatever table you want :-)
You want to use a case statement; something like this (roughly)
INSERT INTO dbo.ResultsTable
SELECT CASE WHEN EXISTS ( SELECT 1
FROM StatesTable
WHERE States = l.Location ) THEN l.Location
ELSE NULL
END AS [State] ,
CASE WHEN NOT EXISTS ( SELECT 1
FROM StatesTable
WHERE States = l.Location ) THEN l.Location
ELSE NULL
END AS [Other Locale]
FROM dbo.LocationsTable l
I would do something like this
INSERT INTO Target (State , Other Locale)
SELECT Location , "" FROM Source Where Location IN
(SELECT States FROM States) UNION
SELECT "" , Location FROM Source Where Location NOT IN
(SELECT States FROM States) ;
Maybe depending on the database or config you would need to use AS to Name the columns like :
INSERT INTO Target (State , Other Locale)
SELECT Location AS "State" , "" AS " Other Locale"
FROM Source Where Location IN (SELECT States FROM States) UNION
SELECT "" AS "State", Location AS " Other Locale"
FROM Source Where Location NOT IN (SELECT States FROM States) ;
This may be the long way, but it's easier (for me anyways) to read & troubleshoot:
CREATE PROCEDURE spLocations (#inLocation varchar(255))
AS
-- declare local variables
declare #col_name nvarchar(255) = ''
declare #location nvarchar(255) = ''
SELECT #location = [colState] from tblStates where [colState] = #inLocation;
SET #col_name = CASE #location
WHEN Null
THEN 'State'
ELSE 'Other Locale'
END;
INSERT INTO targetTBL ([' + #col_name + ']) VALUES (#inLocation);
GO;
i have the below table. (no primary key in this table)
ID | IC | Name | UGCOS | MCOS
---------------------------------------------------------
1AA | A123456B | Edmund | Australia | Denmark
1AA | A123456B | Edmund | Australia | France
2CS | C435664C | Grace | Norway | NULL
3TG | G885595H | Rae | NULL | Japan
I need to get the result like this.
ID | IC | Name | UGCOS | MCOS | MCOS1
--------------------------------------------------------------------
1AA | A123456B | Edmund | Australia | Denmark | France
2CS | C435664C | Grace | Norway | NULL | NULL
3TG | G885595H | Rae | NULL | Japan | NULL
Did googled around and seems like PIVOT is what i need to do that. However i am not sure how can that be implemented to my tables. It would be great help if somebody can help me with it. Thanks!
I'll create a second answer, as this approach is something completely different from my first:
This dynamic query will first find the max count of a distinct ID and then build a dynamic pivot
CREATE TABLE #tmpTbl (ID VARCHAR(100),IC VARCHAR(100),Name VARCHAR(100),UGCOS VARCHAR(100),MCOS VARCHAR(100))
INSERT INTO #tmpTbl VALUES
('1AA','A123456B','Edmund','Australia','Denmark')
,('1AA','A123456B','Edmund','Australia','France')
,('1AA','A123456B','Edmund','Australia','OneMore')
,('2CS','C435664C','Grace','Norway',NULL)
,('3TG','G885595H','Rae',NULL,'Japan');
GO
DECLARE #maxCount INT=(SELECT TOP 1 COUNT(*) FROM #tmpTbl GROUP BY ID ORDER BY COUNT(ID) DESC);
DECLARE #colNames VARCHAR(MAX)=
(
STUFF
(
(
SELECT TOP(#maxCount)
',MCOS' + CAST(ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS VARCHAR(10))
FROM sys.objects --take any large table or - better! - an numbers table or a tally CTE
FOR XML PATH('')
),1,1,''
)
);
DECLARE #cmd VARCHAR(MAX)=
'SELECT p.*
FROM
(
SELECT *
,''MCOS'' + CAST(ROW_NUMBER() OVER(PARTITION BY ID ORDER BY (SELECT NULL)) AS VARCHAR(10)) AS colName
FROM #tmpTbl
) AS tbl
PIVOT
(
MIN(MCOS) FOR colName IN(' + #colNames + ')
) AS p';
EXEC(#cmd);
GO
DROP TABLE #tmpTbl;
The result
1AA A123456B Edmund Australia Denmark France OneMore
2CS C435664C Grace Norway NULL NULL NULL
3TG G885595H Rae NULL Japan NULL NULL
This is a suggestion with a concatenated result:
CREATE TABLE #tmpTbl (ID VARCHAR(100),IC VARCHAR(100),Name VARCHAR(100),UGCOS VARCHAR(100),MCOS VARCHAR(100))
INSERT INTO #tmpTbl VALUES
('1AA','A123456B','Edmund','Australia','Denmark')
,('1AA','A123456B','Edmund','Australia','France')
,('2CS','C435664C','Grace','Norway',NULL)
,('3TG','G885595H','Rae',NULL,'Japan');
SELECT ID,IC,Name,UGCOS,
(
STUFF(
(
SELECT ' ,' + x.MCOS
FROM #tmpTbl AS x
WHERE x.ID=outerTbl.ID
FOR XML PATH('')
),1,2,''
)
) AS MCOS
FROM #tmpTbl AS outerTbl
GROUP BY ID,IC,Name,UGCOS;
GO
DROP TABLE #tmpTbl;
The result
1AA A123456B Edmund Australia Denmark ,France
2CS C435664C Grace Norway NULL
3TG G885595H Rae NULL Japan
Using Cross Apply and Pivot we can achieve this
DECLARE #Table1 TABLE
( ID varchar(3), IC varchar(8), Name varchar(6), UGCOS varchar(9), MCOS varchar(7))
;
INSERT INTO #Table1
( ID , IC , Name , UGCOS , MCOS )
VALUES
('1AA', 'A123456B', 'Edmund', 'Australia', 'Denmark'),
('1AA', 'A123456B', 'Edmund', 'Australia', 'France'),
('2CS', 'C435664C', 'Grace', 'Norway', NULL),
('3TG', 'G885595H', 'Rae', NULL, 'Japan')
;
Select ID , IC , Name , UGCOS,MAX([MCOS1])[MCOS1],MAX([MCOS2])[MCOS2] from (
select ID , IC , Name , UGCOS , MCOS,col,val,col +''+CAST(ROW_NUMBER()OVER(PARTITION BY ID ORDER BY col) AS VARCHAR)RN from #Table1
CROSS APPLY (values('MCOS',MCOS))CS(col,val))T
PIVOT (MAX(val) FOR RN IN ([MCOS1],[MCOS2]))PVT
GROUP BY ID , IC , Name , UGCOS
Do you always have a maximum of 2 rows of data that you'll want to turn into columns? If so, this would do you;
CREATE TABLE #TableName (ID varchar(3), IC varchar(8), Name varchar(6), UCGOS varchar(9), MCOS varchar(7))
INSERT INTO #TableName
VALUES
('1AA','A123456B','Edmund','Australia','Denmark')
,('1AA','A123456B','Edmund','Australia','France')
,('2CS','C435664C','Grace','Norway',NULL)
,('3TG','G885595H','Rae',NULL,'Japan')
SELECT DISTINCT a.ID
,a.IC
,a.NAME
,a.UCGOS
,b.Mcos1 MCOS
,c.Mcos2 MCOS1
FROM #TableName a
LEFT JOIN (
SELECT ID
,MAX(MCOS) Mcos1
FROM #TableName
GROUP BY ID
) b ON a.ID = b.ID
LEFT JOIN (
SELECT ID
,MIN(MCOS) Mcos2
FROM #TableName
GROUP BY ID
) c ON a.ID = c.ID
AND (
b.ID = c.ID
AND b.Mcos1 <> c.Mcos2
)
DROP TABLE #TableName
Gives you the result you're after.