I have address table which can have multiple addresses for a customer based on address_id. I have written CTE to get address_id having more count which is as below
SELECT * FROM (
SELECT address_id
, customer_key
, attention
, ROW_NUMBER() OVER (PARTITION BY customer_key ORDER BY total_addresses DESC, address_id DESC ) AS row_num
FROM (
SELECT address_id
, customer_key
, attention
, count(*) AS total_addresses
FROM (
SELECT address_id
, i.customer_key
, amcp.attention
FROM address_mailing_current_pre amcp
JOIN v_list_of_bus_pre vlobp ON vlobp.busi_role_rel_id = amcp.busi_role_rel_id
JOIN party_current_pre pcp ON pcp.party_link_id = vlobp.party_link_id
JOIN vw_crods_inscope_customer i on trim(vlobp.bus_src_sys_name_cde) || '-' || trim(vlobp.src_sys_party_id) = i.customer_key
AND vlobp.lobstatus_cde LIKE 'RENEWAL%'
AND vlobp.party_bus_role_cde LIKE 'PH%'
JOIN party_grp_role_current_pre pgrc ON pgrc.PARTY_LINK_ID = vlobp.PARTY_LINK_ID AND pgrc.PARTY_GRP_ID = vlobp.PARTY_GRP_ID
JOIN bus_role_rel_pre brrc ON brrc.BUSI_ROLE_REL_ID = vlobp.BUSI_ROLE_REL_ID
UNION ALL
SELECT address_id
, i.customer_key
, arcp.attention
FROM address_risk_current_pre arcp
JOIN v_list_of_bus_pre vlobp ON vlobp.src_sys_bus_id= arcp.src_sys_bus_id
JOIN party_current_pre pcp ON pcp.party_link_id = vlobp.party_link_id
JOIN vw_crods_inscope_customer i on trim(vlobp.bus_src_sys_name_cde) || '-' || trim(vlobp.src_sys_party_id) = i.customer_key
AND vlobp.lobstatus_cde LIKE 'RENEWAL%'
AND vlobp.party_bus_role_cde LIKE 'PH%'
JOIN party_grp_role_current_pre pgrc ON pgrc.PARTY_LINK_ID = vlobp.PARTY_LINK_ID AND pgrc.PARTY_GRP_ID = vlobp.PARTY_GRP_ID
JOIN bus_role_rel_pre brrc ON brrc.BUSI_ROLE_REL_ID = vlobp.BUSI_ROLE_REL_ID
)
GROUP BY address_id, customer_key, attention
ORDER BY total_addresses DESC, address_id DESC
)
)
WHERE row_num = 1
This gives me latest address_id. Sometimes it happens that latest address_id doesn't have address in main address_current table but the next address_id can have address. so I want to use that address_id.
for e.g. If I run below query
SELECT address_id
, customer_key
, attention
, count(*) AS total_addresses
FROM (
SELECT address_id
, i.customer_key
, amcp.attention
FROM address_mailing_current_pre amcp
JOIN v_list_of_bus_pre vlobp ON vlobp.busi_role_rel_id = amcp.busi_role_rel_id
JOIN party_current_pre pcp ON pcp.party_link_id = vlobp.party_link_id
JOIN vw_crods_inscope_customer i on trim(vlobp.bus_src_sys_name_cde) || '-' || trim(vlobp.src_sys_party_id) = i.customer_key
AND vlobp.lobstatus_cde LIKE 'RENEWAL%'
-- AND vlobp.party_bus_role_cde LIKE 'PH%'
WHERE vlobp.src_sys_party_id LIKE '151167409%'
UNION ALL
SELECT address_id
, i.customer_key
, arcp.attention
FROM address_risk_current_pre arcp
JOIN v_list_of_bus_pre vlobp ON vlobp.src_sys_bus_id= arcp.src_sys_bus_id
JOIN party_current_pre pcp ON pcp.party_link_id = vlobp.party_link_id
JOIN vw_crods_inscope_customer i on trim(vlobp.bus_src_sys_name_cde) || '-' || trim(vlobp.src_sys_party_id) = i.customer_key
AND vlobp.lobstatus_cde LIKE 'RENEWAL%'
-- AND vlobp.party_bus_role_cde LIKE 'PH%'
WHERE vlobp.src_sys_party_id LIKE '151167409%'
I get below result
Here 1st address_id doesn't give any address but the next one does. How can I iterate over each address_id in a VIEW and get the address_id which has the address?
Related
I'm writing a query that will bring me back either row or rank '1'. When I run the query with the 'where rank or row clause equals 1', no data returns for those columns but if I take out the 'where rank or row clause' the data populates. Can someone tell me why the where clause is causing no data to return?
LEFT OUTER JOIN
(SELECT DISTINCT CLMED.SIMPLE_GENERIC_C
, MEDINFO.MEDICATION_ID as [CYTOTEC]
,FMED.PAT_ENC_CSN_ID
, FMED.HOSP_ADMSN_DATE
-- , MIN(FMED.TAKEN_DATETIME) over (Partition by FMED.PAT_ENC_CSN_ID,
MEDINFO.MEDICATION_ID ) as 'FIRST DOSE'
, MIN(FMED.TAKEN_DATETIME) over (Partition by FMED.PAT_ENC_CSN_ID, CLMED.SIMPLE_GENERIC_C
) AS 'FIRST DOSE'
, RANK() over (Partition by FMED.PAT_ENC_CSN_ID, CLMED.SIMPLE_GENERIC_C order by
FMED.TAKEN_DATETIME DESC) 'CYTOTEC_RANK'
, ROW_NUMBER() over (Partition by FMED.PAT_ENC_CSN_ID, MEDINFO.MEDICATION_ID order by
FMED.TAKEN_DATETIME) AS 'CYTOTEC_ROW'
, FMED.DISPLAY_NAME
, FMED.ORDER_MED_ID
, ORDMED.DESCRIPTION
, ZCGEN.NAME
FROM MED_ADMIN FMED
LEFT JOIN MEDINFO MEDINFO ON FMED.ORDER_MED_ID = MEDINFO.ORDER_MED_ID
LEFT JOIN MED ORDMED ON FMED.ORDER_MED_ID = ORDMED.ORDER_MED_ID
LEFT JOIN MEDICATION CLMED ON MEDINFO.MEDICATION_ID = CLMED.MEDICATION_ID
LEFT JOIN GENERIC ZCGEN ON CLMED.SIMPLE_GENERIC_C = ZCGEN.SIMPLE_GENERIC_C
WHERE ZCGEN.NAME = 'miSOPROStol'
AND 'CYTOTEC_RANK' = 1
) AS [CYT] ON CYT.PAT_ENC_CSN_ID = VITALS.PAT_ENC_CSN_ID
In this query I cant understand what would be the proper syntax to PIVOT it by month and also display just top 10 records based on SUM(NetWrittenPremium).
;with cte_TopClasses
AS (
select
b.YearNum,
b.MonthNum,
REPLACE(ClassCode,'+','') + ' - '+ QLL.Description as Description,
SUM( Premium) as NetWrittenPremium
FROM tblCalendar b
LEFT JOIN ProductionReportMetrics prm ON b.MonthNum=Month(prm.EffectiveDate) AND b.YearNum = YEAR(EffectiveDate)
AND prm.EffectiveDate >=DateAdd(yy, -1, DATEADD(d, 1, EOMONTH(GETDATE()))) AND prm.EffectiveDate <= EOMONTH(GETDATE()) AND CompanyLine = 'Ironshore Insurance Company'
LEFT JOIN NetRate_Quote_Insur_Quote Q ON prm.NetRate_QuoteID = Q.QuoteID
LEFT JOIN NetRate_Quote_Insur_Quote_Locat QL ON Q.QuoteID = QL.QuoteID
LEFT JOIN (SELECT * FROM NetRate_Quote_Insur_Quote_Locat_Liabi nqI
JOIN ( SELECT LocationID as LocID, MAX(ClassCode) as ClCode
FROM NetRate_Quote_Insur_Quote_Locat_Liabi GROUP BY LocationID ) nqA
ON nqA.LocID = nqI.LocationID AND nqA.ClCode = nqI.ClassCode ) QLL
ON QLL.LocationID = QL.LocationID
WHERE ( b.YearNum = YEAR(GETDATE())-1 and b.MonthNum >= MONTH(GETDATE())+1 ) OR
( b.YearNum = YEAR(GETDATE()) and b.MonthNum <= MONTH(GETDATE()) )
GROUP BY b.YearNum,b.MonthNum,ClassCode, QLL.Description
)
SELECT
--TOP 10
RANK() OVER (ORDER BY NetWrittenPremium DESC) AS Rank, *
FROM cte_TopClasses
WHERE Description IS NOT NULL
ORDER BY NetWrittenPremium DESC,YearNum,MonthNum
The result should look something like that:
If I use the query below and then using matrics in SSRS to PIVOT it - then after grouping by Description it only displays me 2 Description.
;with cte_TopClasses
AS (
select
b.YearNum,
b.MonthNum,
REPLACE(ClassCode,'+','') + ' - '+ QLL.Description as Description,
SUM( Premium) as NetWrittenPremium
FROM tblCalendar b
LEFT JOIN ProductionReportMetrics prm ON b.MonthNum=Month(prm.EffectiveDate) AND b.YearNum = YEAR(EffectiveDate)
AND prm.EffectiveDate >=DateAdd(yy, -1, DATEADD(d, 1, EOMONTH(GETDATE()))) AND prm.EffectiveDate <= EOMONTH(GETDATE()) AND CompanyLine = 'Ironshore Insurance Company'
LEFT JOIN NetRate_Quote_Insur_Quote Q ON prm.NetRate_QuoteID = Q.QuoteID
LEFT JOIN NetRate_Quote_Insur_Quote_Locat QL ON Q.QuoteID = QL.QuoteID
LEFT JOIN (SELECT * FROM NetRate_Quote_Insur_Quote_Locat_Liabi nqI
JOIN ( SELECT LocationID as LocID, MAX(ClassCode) as ClCode
FROM NetRate_Quote_Insur_Quote_Locat_Liabi GROUP BY LocationID ) nqA
ON nqA.LocID = nqI.LocationID AND nqA.ClCode = nqI.ClassCode ) QLL
ON QLL.LocationID = QL.LocationID
WHERE ( b.YearNum = YEAR(GETDATE())-1 and b.MonthNum >= MONTH(GETDATE())+1 ) OR
( b.YearNum = YEAR(GETDATE()) and b.MonthNum <= MONTH(GETDATE()) )
GROUP BY b.YearNum,b.MonthNum,ClassCode, QLL.Description
)
SELECT *
FROM (SELECT RANK() OVER (ORDER BY NetWrittenPremium DESC) AS Rank, *
FROM cte_TopClasses
WHERE Description IS NOT NULL) AA
WHERE AA.Rank <= 10
ORDER BY AA.NetWrittenPremium DESC, AA.YearNum, AA.MonthNum
And the result of it in SSRS matrics :
You could try something like this at the end of the query, rather than what is there now:
SELECT *
FROM (SELECT RANK() OVER (ORDER BY [Description] DESC) AS Rank, *
FROM cte_TopClasses
WHERE Description IN (SELECT [Description]
FROM (SELECT RANK() OVER (ORDER BY SUM(NetWrittenPremium) DESC) AS [Rank], [Description], SUM(NetWrittenPremium) AS total
FROM cte_TopClasses
WHERE [Description] IS NOT NULL
GROUP BY [Description]) BB
WHERE [Rank] <= 10)) AA
ORDER BY YearNum, MonthNum
This wraps the query in a SELECT, and filters the ranked results to the 10 you want.
Then use a matrix in the report to pivot the results.
i need to show some field from another table in oracle here is my query
SELECT
ANGGARAN.SIMPEG_PEGAWAI.ID_PEGAWAI AS KODE,
ANGGARAN.SIMPEG_PEGAWAI.NAMA,
ANGGARAN.SIMPEG_PEGAWAI.NIP,
ANGGARAN.SIMPEG_ESELON_JABATAN.JABATAN,
ANGGARAN.SIMPEG_KODE_GOLONGAN_PANGKAT.GOLONGAN,
ANGGARAN.SIMPEG_KODE_GOLONGAN_PANGKAT.PANGKAT,
(SELECT *
FROM (SELECT CONCAT(TO_CHAR(abs(sysdate - TO_DATE(TMT_JABATAN))/360,'9,999,999.9'),' TAHUN')
FROM SIMPEG_JABATAN where ID_PEGAWAI=KODE ORDER BY TMT_JABATAN desc)
WHERE ROWNUM = 1) AS MASA_KERJA
FROM
ANGGARAN.SIMPEG_PEGAWAI
INNER JOIN ANGGARAN.SIMPEG_ESELON_JABATAN
ON ANGGARAN.SIMPEG_PEGAWAI.ESELON_JABATAN = ANGGARAN.SIMPEG_ESELON_JABATAN.ID_ESELON_JABATAN
INNER JOIN ANGGARAN.SIMPEG_KODE_GOLONGAN_PANGKAT
ON ANGGARAN.SIMPEG_PEGAWAI.PANGKAT = ANGGARAN.SIMPEG_KODE_GOLONGAN_PANGKAT.ID_GOLONGAN_PANGKAT
WHERE
ANGGARAN.SIMPEG_PEGAWAI.ST_AKTIF = 1 AND
ANGGARAN.SIMPEG_PEGAWAI.ESELON2 <> 1 AND
ANGGARAN.SIMPEG_PEGAWAI.PANGKAT >= 12 AND
ANGGARAN.SIMPEG_ESELON_JABATAN.STATUS = 1 AND
ANGGARAN.SIMPEG_ESELON_JABATAN.ID_ESELON2=2
ORDER BY
ANGGARAN.SIMPEG_KODE_GOLONGAN_PANGKAT.SORT DESC
result i got
[Err] ORA-00904: "KODE": invalid identifier
the KODE come from query ANGGARAN.SIMPEG_PEGAWAI.ID_PEGAWAI AS KODE, and used for this query
(SELECT *
FROM (SELECT CONCAT(TO_CHAR(abs(sysdate - TO_DATE(TMT_JABATAN))/360,'9,999,999.9'),' TAHUN')
FROM SIMPEG_JABATAN where ID_PEGAWAI=KODE ORDER BY TMT_JABATAN desc)
WHERE ROWNUM = 1) AS MASA_KERJA
that i miss something ? or that could be worogn using an alias in subquery where clause in oracle database ?
You can use an identifier defined in an external query in only one level deep queries. You have to rethink your strategy. My suggestion is to remove the subquery from the select list and put it in the FROM clause. And add another rownumber column like this:
(SELECT
ID_PEGAWAI,
CONCAT(TO_CHAR(abs(sysdate - TO_DATE(TMT_JABATAN))/360,'9,999,999.9'),' TAHUN') MASA_KERJA,
ROW_NUMBER() OVER (PARTITION BY ID_PEGAWAI ORDER BY TMT_JABATAN DESC) rownumber
FROM SIMPEG_JABATAN) xxx
And join like:
ON ANGGARAN.SIMPEG_PEGAWAI = xxx.ID_PEGAWAI
Then in the where clause you can do simply:
WHERE
....
AND xxx.rownumber = 1
Complete query:
SELECT
ANGGARAN.SIMPEG_PEGAWAI.ID_PEGAWAI AS KODE,
ANGGARAN.SIMPEG_PEGAWAI.NAMA,
ANGGARAN.SIMPEG_PEGAWAI.NIP,
ANGGARAN.SIMPEG_ESELON_JABATAN.JABATAN,
ANGGARAN.SIMPEG_KODE_GOLONGAN_PANGKAT.GOLONGAN,
ANGGARAN.SIMPEG_KODE_GOLONGAN_PANGKAT.PANGKAT
FROM
ANGGARAN.SIMPEG_PEGAWAI
INNER JOIN ANGGARAN.SIMPEG_ESELON_JABATAN
ON ANGGARAN.SIMPEG_PEGAWAI.ESELON_JABATAN = ANGGARAN.SIMPEG_ESELON_JABATAN.ID_ESELON_JABATAN
INNER JOIN ANGGARAN.SIMPEG_KODE_GOLONGAN_PANGKAT
ON ANGGARAN.SIMPEG_PEGAWAI.PANGKAT = ANGGARAN.SIMPEG_KODE_GOLONGAN_PANGKAT.ID_GOLONGAN_PANGKAT
INNER JOIN (
SELECT
ID_PEGAWAI,
CONCAT(TO_CHAR(abs(sysdate - TO_DATE(TMT_JABATAN))/360,'9,999,999.9'),' TAHUN') MASA_KERJA,
ROW_NUMBER() OVER (PARTITION BY ID_PEGAWAI ORDER BY TMT_JABATAN DESC) rownumber
FROM SIMPEG_JABATAN
) xxx
ON ANGGARAN.SIMPEG_PEGAWAI.ID_PEGAWAI = xxx.ID_PEGAWAI
WHERE
ANGGARAN.SIMPEG_PEGAWAI.ST_AKTIF = 1 AND
ANGGARAN.SIMPEG_PEGAWAI.ESELON2 <> 1 AND
ANGGARAN.SIMPEG_PEGAWAI.PANGKAT >= 12 AND
ANGGARAN.SIMPEG_ESELON_JABATAN.STATUS = 1 AND
ANGGARAN.SIMPEG_ESELON_JABATAN.ID_ESELON2=2 AND
xxx.rownumber = 1
ORDER BY ANGGARAN.SIMPEG_KODE_GOLONGAN_PANGKAT.SORT DESC
Oracle does not support columns aliases in WHERE clauses (or similar situations like here). You have to name the column again (by its original name).
select dummy as kode from dual where kode = 'X'
> ORA-00904: "KODE": invalid identifier
You need to assign an alias in the level below to use it in a query (I haven't checked the syntax and workability of your query, just changed the part which is essential to answer your question):
SELECT
TMP.KODE,
TMP.NAMA,
TMP.NIP,
ANGGARAN.SIMPEG_ESELON_JABATAN.JABATAN,
ANGGARAN.SIMPEG_KODE_GOLONGAN_PANGKAT.GOLONGAN,
ANGGARAN.SIMPEG_KODE_GOLONGAN_PANGKAT.PANGKAT,
(SELECT *
FROM (SELECT CONCAT(TO_CHAR(abs(sysdate - TO_DATE(TMT_JABATAN))/360,'9,999,999.9'),' TAHUN')
FROM SIMPEG_JABATAN where ID_PEGAWAI=TMP.KODE ORDER BY TMT_JABATAN desc)
WHERE ROWNUM = 1) AS MASA_KERJA
FROM
(SELECT ANGGARAN.SIMPEG_PEGAWAI.ID_PEGAWAI AS KODE, ANGGARAN.SIMPEG_PEGAWAI.* FROM ANGGARAN.SIMPEG_PEGAWAI) TMP
INNER JOIN ANGGARAN.SIMPEG_ESELON_JABATAN
ON TMP.ESELON_JABATAN = ANGGARAN.SIMPEG_ESELON_JABATAN.ID_ESELON_JABATAN
INNER JOIN ANGGARAN.SIMPEG_KODE_GOLONGAN_PANGKAT
ON TMP.PANGKAT = ANGGARAN.SIMPEG_KODE_GOLONGAN_PANGKAT.ID_GOLONGAN_PANGKAT
WHERE
TMP.ST_AKTIF = 1 AND
TMP.ESELON2 <> 1 AND
TMP.PANGKAT >= 12 AND
ANGGARAN.SIMPEG_ESELON_JABATAN.STATUS = 1 AND
ANGGARAN.SIMPEG_ESELON_JABATAN.ID_ESELON2=2
ORDER BY
ANGGARAN.SIMPEG_KODE_GOLONGAN_PANGKAT.SORT DESC
I have not been able to figure out scope of reference when there are nested queries. For example I can't seem to reference NoCarsFound.CU in my inner join. I don't understand why in my join I can't reference previous result sets...I think I just don't undrestand the scope of referencing previous select results or referencing aliases in my inner join's ON comparisons.
I also get Ambiguous column name 'CU'
So I keep getting errors saying it doesn't know NoCarsFound.CU. I even tried to reference a straight view such as vwInvalidCars.CU, and it doesn't understand vwInvalidCars either.
create procedure [Rac].[GetCarStatDetails_sp]
#Year int,
#CarTitle varchar(30),
#Company varchar(31),
#CU varchar(12),
#UserName varchar(50)
as
BEGIN
DECLARE #CarMatch table
(
FaceValueTol varchar(100),
FaceValueDesc varchar(100),
Year int,
CU varchar(16),
PaintTypeDesc varchar(50)
)
insert into #CarMatch
Select temp1.FaceValueTol,
temp1.FaceValueDesc,
temp1.Year,
temp1.CU,
temp1.PaintTypeDesc
from Rac.viewCarBase as temp1
join (select Username, userCars.CU from Nep.viewUserCars userCars where UserName = #UserName) as userCars on userCars.CU = temp1.CU
INNER JOIN
(
Select CU,
from Rac.vwCarFactor carfactors
where RiskFactorTypeID not in (334,553,34334,534,7756)
Group by CU
) as temp
on
and temp1.CU = temp.CU
and temp1.PaintTypeDesc = temp.CalcPaintTypeDesc
Where
temp1.RiskFactorTypeID=4
and temp1.[Year]=#Year
and (temp1.CarTitle=#CarTitle or #CarTitle='<All>')
and (temp1.CU=#CU or #CU='<All>')
SELECT ProductID_bo,
Coalesce(CarTitle_bo,LTRIM(RTRIM(CarTitle))) as CarTitle,
Coalesce(Company_bo,LTRIM(RTRIM(Company))) as Company,
Coalesce(CU_bo,LTRIM(RTRIM(CU))) as CU
FROM
Rac.viewCarBase as NoCarsFound
join (select Username, userCars.CU from Nep.viewUserCars userCars where UserName = #UserName) as userCars on userCars.CU = NoCarsFound.CU
LEFT OUTER JOIN
(
Select ProductID_bo,
CarTitle_bo,
Company_bo,
CU_bo,
from (
SELECT ProductID as ProductID_bo,
LTRIM(RTRIM(CarTitle)) as CarTitle_bo,
LTRIM(RTRIM(Company)) as Company_bo,
FROM Rac.viewCarBase
join (select Username, userCars.CU from Nep.viewUserCars userCars where UserName = #UserName) as userCars on userCars.CU = Rac.viewCarBase.CU
where ProductID in (Select ProductID from #CarMatch) and
and (CarTitle=#CarTitle or #CarTitle='<All>')
and (Company=#Company or #Company='<All>')
and (CU=#CU or #CU='<All>')
) AS SUB1
Group By
CarTitle_bo,
Company_bo,
CU_bo,
ON
NoCarsFound.CU = CarsFoundDeals.CU_bo
where
and (CarTitle=#CarTitle or #CarTitle='<All>')
and (Company=#Company or #Company='<All>')
and (CU=#CU or #CU='<All>')
end
I would look at the two following pieces of SQL from what you have above:
LEFT OUTER JOIN
(
Select ProductID_bo,
CarTitle_bo,
Company_bo,
CU_bo,
from (
SELECT ProductID as ProductID_bo,
LTRIM(RTRIM(CarTitle)) as CarTitle_bo,
LTRIM(RTRIM(Company)) as Company_bo,
FROM Rac.viewCarBase
join (select Username, userCars.CU from Nep.viewUserCars userCars where UserName = #UserName) as userCars on userCars.CU = Rac.viewCarBase.CU
where ProductID in (Select ProductID from #CarMatch) and
and (CarTitle=#CarTitle or #CarTitle='<All>')
and (Company=#Company or #Company='<All>')
and (CU=#CU or #CU='<All>') --<--HERE!!!!!!!!!!!!!!!!!!!!!!!!
) AS SUB1
and
where
and (CarTitle=#CarTitle or #CarTitle='<All>')
and (Company=#Company or #Company='<All>')
and (CU=#CU or #CU='<All>') -- <--HERE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Both of these appear to be referencing CU in a way that could potentially cause the error you are reporting.
I want to know if it is possible to create another column in a table that has data that I wish to populate in this new column? The new column is Flag2. Here is the table:
what I want to do is, where item id is 30, I want the ITEM ID to only display 30 once and, populate the QC Unsupportted in Flag2? How do I do this?
I can only think of doing an inner join but this is not working.
This is what I have done in trying to do so:
SELECT
A.ITEMID, A.FLAG1, A.FLAG2
FROM
#FLAGS as A
INNER JOIN
#FLAGS as B ON A.ITEMID = B.ITEMID
GROUP BY
a.ITEMID, a.FLAG1, A.FLAG2
ORDER BY
ITEMID
Assuming I understand what you are after, if the current FLAG1 values are distinct for any ITEMID and you only have at most two instances of the same ID, I think this should do what you want:
SELECT
lft.ITEMID
, lft.FLAG1
, rght.FLAG1 FLAG2
FROM (
SELECT
t.ITEMID
, t.FLAG1
FROM (
SELECT
l.ITEMID
, l.FLAG1
, COUNT(l.ITEMID) i
FROM #FLAGS l
INNER JOIN #FLAGS r ON l.ITEMID = r.ITEMID
WHERE r.FLAG1 <= l.FLAG1
GROUP BY
l.ITEMID
, l.FLAG1) t
WHERE t.i=1) lft
LEFT OUTER JOIN (
SELECT
t.ITEMID
, t.FLAG1
FROM (
SELECT
l.ITEMID
, l.FLAG1
, COUNT(l.ITEMID) i
FROM #FLAGS l
INNER JOIN #FLAGS r ON l.ITEMID = r.ITEMID
WHERE r.FLAG1 <= l.FLAG1
GROUP BY
l.ITEMID
, l.FLAG1) t
WHERE t.i=2) rght ON lft.ITEMID = rght.ITEMID
-- Or better
SELECT
lft.ITEMID
, lft.FLAG1
, rght.FLAG1 FLAG2
FROM (
SELECT
t.ITEMID
, t.FLAG1
FROM (
SELECT
l.ITEMID
, l.FLAG1
, ROW_NUMBER() OVER(PARTITION BY ITEMID ORDER BY FLAG1) as i
FROM test l) t
WHERE t.i=1) lft
LEFT OUTER JOIN (
SELECT
t.ITEMID
, t.FLAG1
FROM (
SELECT
l.ITEMID
, l.FLAG1
, ROW_NUMBER() OVER(PARTITION BY ITEMID ORDER BY FLAG1) as i
FROM test l) t
WHERE t.i=2) rght ON lft.ITEMID = rght.ITEMID
If you have additional flag values for the same ID, a new outer join can be added to a new inline table (rght2, rght3, etc.) where i=3, 4, etc. and you are selecting rght2 AS FLAG3, rght3 AS FLAG4, etc.
Also note that the current values for FLAG1 will be distributed through FLAG1 and FLAG2 in alphabetical order. If you wanted to distribute them in reverse order you could replace <= with >=. If you had more than two flags that you wanted distributed in a specific order, you would have to create a separate table with a ranking value and join to that which would be doable but even uglier!