Duplicate Results with LISTAGG Function - sql

I do see there are solutions for a similar question but I was unable to get them to work in my scenario.
I am returning duplicate codes while using the LISTAGG function.
Returning now:
SELECT
,CD.CLAIM
,CD.CLAIMLN
,CD.PROV_INVOICE_UNTS
,CD.APPR_UNTS
,CD.PROV_INVOICE_AMT
,CD.PROV_CNTRCT_AMT
,CD.PLAN_CNTRCT_AMT as PLAN_AMT
,LISTAGG(DX.DIAG_CD,', ') WITHIN GROUP (ORDER BY DX.LVL_CD) AS DX_CODES
FROM CLAIM_DETAIL CD
INNER JOIN PATIENT_INTAKE_PLAN PIP
ON CD.PAT_NBR = PIP.PAT_NBR AND CD.ITK_ID = PIP.ITK_ID
INNER JOIN HEALTH_PLAN HP
ON HP.PLAN_ID = PIP.PLAN_ID
INNER JOIN PROVIDER_CCXPORTAL PR
ON PR.PROV_ID = CD.PROV_ID
INNER JOIN PROVIDER_PARENT PRP
ON PR.PROV_PRNT_ID = PRP.PROV_PRNT_ID
INNER JOIN PATIENT_CCXPORTAL PTP
ON PTP.PAT_NBR = CD.PAT_NBR
INNER JOIN CLAIM C
ON C.CLM_ID = CD.CLM_ID
LEFT JOIN CLAIM_DIAGNOSIS DX
ON CD.CLM_ID = DX.CLM_ID
WHERE
C.RCPT_DT >= '01-JUL-2014'
I need it to return:

Use a regex to get rid of the duplicates
....as PLAN_AMT,
RTRIM(
REGEXP_REPLACE(
(listagg(DX.DIAG_CD,',') WITHIN GROUP (ORDER BY DX.LVL_CD) ),
'([^,]*)(,\1)+($|,)',
'\1\3'),
',') AS DX_CODES
FROM......

If there are very many DX_CODES per claim, your may string exceed the max length for a SQL varchar2.
Can you try this instead?
SELECT
,CD.CLAIM
,CD.CLAIMLN
,CD.PROV_INVOICE_UNTS
,CD.APPR_UNTS
,CD.PROV_INVOICE_AMT
,CD.PROV_CNTRCT_AMT
,CD.PLAN_CNTRCT_AMT as PLAN_AMT
, (SELECT listagg(dx.diag_cd,',') within group ( order by dx.lvl_cd, dx.diag_cd ) FROM ( SELECT distinct clm_id, lvl_cd, diag_cd FROM claim_diagnosis ) dx WHERE dx.clm_id = cd.clm_id ) dx_codes
--,LISTAGG(DX.DIAG_CD,', ') WITHIN GROUP (ORDER BY DX.LVL_CD) AS DX_CODES
FROM CLAIM_DETAIL CD
INNER JOIN PATIENT_INTAKE_PLAN PIP
ON CD.PAT_NBR = PIP.PAT_NBR AND CD.ITK_ID = PIP.ITK_ID
INNER JOIN HEALTH_PLAN HP
ON HP.PLAN_ID = PIP.PLAN_ID
INNER JOIN PROVIDER_CCXPORTAL PR
ON PR.PROV_ID = CD.PROV_ID
INNER JOIN PROVIDER_PARENT PRP
ON PR.PROV_PRNT_ID = PRP.PROV_PRNT_ID
INNER JOIN PATIENT_CCXPORTAL PTP
ON PTP.PAT_NBR = CD.PAT_NBR
INNER JOIN CLAIM C
ON C.CLM_ID = CD.CLM_ID
--LEFT JOIN CLAIM_DIAGNOSIS DX
--ON CD.CLM_ID = DX.CLM_ID
WHERE
C.RCPT_DT >= '01-JUL-2014'
Make sure there is an index on CLAIM_DIAGNOSIS.CLM_ID.

Related

Trouble with aggregate in Where clause, Selecting Max(x) When Max(x) != 3

I am trying to reconfigure the below sql to only pull records when the Max(Field) != 3 but keep getting an error (detailed) below.
This is the code before adding the Where Max(field) != 3
SELECT P.Code,
MAX(PW.v1) AS V1
FROM SW
INNER JOIN S ON SW.S_Id = S.Id
INNER JOIN PW ON SW.PW_Id = PW.Id
INNER JOIN PON S.P_Id = P.id
WHERE S.P_Id = P.id
GROUP BY P.Code
My Attempt
SELECT P.Code,
MAX(PW.v1) AS V1
FROM SW
INNER JOIN S ON SW.S_Id = S.Id
INNER JOIN PW ON SW.PW_Id = PW.Id
INNER JOIN PON S.P_Id = P.id
WHERE S.P_Id = P.id
AND (SELECT MAX(PW.v1)
FROM SW AS SW2
WHERE SW.PWId = SW2.PW_Id) != 3
GROUP BY P.Code
This is the error I get and not sure what to do:
An aggregate may not appear in the WHERE clause unless it is in a subquery contained in a HAVING clause or a select list, and the column being aggregated is an outer reference.
Traditional method of filtering on results of an aggregate can be achieved by using HAVING clause. I also removed the unnecessary WHERE clause as you already joined those 2 tables on that column. Here is the query:
SELECT P.Code
,MAX(PW.v1) AS V1
FROM SW
INNER JOIN S
ON SW.S_Id = S.Id
INNER JOIN PW
ON SW.PW_Id = PW.Id
INNER JOIN P
ON S.P_Id = P.id
GROUP BY P.Code
HAVING MAX(PW.v1)!=3;

Return rows where a customer bought things on same day

Can someone help me with the rest of my Query.
This query gives me Customer, AdressNr, Date, Employee, Article, ActivityNr
from all the sales in my Company.
SELECT ad.Name + ' ' + ad.Vorname AS Customer,
pa.Kunde AS CustomerNr,
CONVERT(VARCHAR(10),p.datum,126) AS Date,
(SELECT a.name + ' ' + a.Vorname AS Name FROM PRO_Mitarbeiter m LEFT JOIN ADR_Adressen a ON a.AdressNrADR=m.AdressNrADR WHERE m.MitNrPRO = l.MitNrPRO) as Employee,
p.Artikel_1 AS Article,
l.AufgabenNrCRM AS OrderNr
FROM ZUS_Therapie_Positionen p
INNER JOIN CRM_AufgabenLink l ON l.AufgabenNrCRM = p.Id_Aktivitaet
INNER JOIN CRM_Aufgaben ab ON ab.AufgabenNrCRM = p.Id_Aktivitaet
INNER JOIN PRO_Auftraege pa ON pa.AuftragNrPRO = ab.AuftragNrPRO
INNER JOIN ADR_Adressen ad ON ad.AdressNrADR = pa.Kunde
INNER JOIN ADR_GruppenLink gl ON gl.AdressNrADR = ad.AdressNrADR
INNER JOIN ADR_Gruppen g ON g.GruppeADR = gl.GruppeADR
WHERE l.MitNrPRO != 0
GROUP BY l.AufgabenNrCRM,ad.Name,ad.Vorname,pa.Kunde,p.datum,p.Artikel_1,l.MitNrPRO
ORDER BY pa.Kunde,p.datum,l.AufgabenNrCRM
My goal is to filter this so i get only rows back where the customer has bought more then 1 Thing on the same day. It doesn't matter if a customer bought the same Article twice on the same day. I want too see this also.
It's to complicated to write some SQL Fiddle for you but in this Picture you can see what my goal is. I want to take away all rows with an X on the left side and thoose with a Circle i want to Keep.
As I don't speak German, I won't target this specifically to your SQL. But see the following quasi-code for a similar example that you should be able to apply to your own script.
SELECT C.CustomerName, O.OrderDate, O.OrderNumber
FROM CUSTOMER C
JOIN ORDERS O ON O.Customer_ID = C.Customer_ID
JOIN
(SELECT Customer_ID, OrderDate
FROM ORDERS
GROUP BY Customer_ID, OrderDate
HAVING COUNT(*) > 1) SRC
ON SRC.Customer_ID = O.Customer_ID AND SRC.OrderDate = O.OrderDate
In the script above, the last query (a subquery) would only return results where a customer had more than one order in a given day. By joining that to your main query, you would effectively produce the result asked in the OP.
Edit 1:
Regarding your comment below, I really recommend just going over your datamodel, trying to understand what's happening here, and fixing it on your own. But there is an easy - albeit hardly optimal solution to this by just using your own script above. Note, while this is not disastrous performance-wise, it's obviously not the cleanest, most effective method either. But it should work:
;WITH CTE AS (SELECT ad.Name + ' ' + ad.Vorname AS Customer,
pa.Kunde AS CustomerNr,
CONVERT(VARCHAR(10),p.datum,126) AS [Date],
(SELECT a.name + ' ' + a.Vorname AS Name FROM PRO_Mitarbeiter m LEFT JOIN ADR_Adressen a ON a.AdressNrADR=m.AdressNrADR WHERE m.MitNrPRO = l.MitNrPRO) as Employee,
p.Artikel_1 AS Article,
l.AufgabenNrCRM AS OrderNr
FROM ZUS_Therapie_Positionen p
INNER JOIN CRM_AufgabenLink l ON l.AufgabenNrCRM = p.Id_Aktivitaet
INNER JOIN CRM_Aufgaben ab ON ab.AufgabenNrCRM = p.Id_Aktivitaet
INNER JOIN PRO_Auftraege pa ON pa.AuftragNrPRO = ab.AuftragNrPRO
INNER JOIN ADR_Adressen ad ON ad.AdressNrADR = pa.Kunde
INNER JOIN ADR_GruppenLink gl ON gl.AdressNrADR = ad.AdressNrADR
INNER JOIN ADR_Gruppen g ON g.GruppeADR = gl.GruppeADR
WHERE l.MitNrPRO != 0
GROUP BY l.AufgabenNrCRM,ad.Name,ad.Vorname,pa.Kunde,p.datum,p.Artikel_1,l.MitNrPRO
ORDER BY pa.Kunde,p.datum,l.AufgabenNrCRM)
SELECT C.*
FROM CTE C
JOIN (Select CustomerNr, [Date]
FROM CTE B
GROUP BY CustomerNr, [Date]
HAVING COUNT(*) > 1) SRC
ON SRC.CustomerNr = C.CustomerNr AND SRC.[Date] = C.[Date]
This should work directly. But as I said, this is an ugly workaround where we're basically all but fetching the whole set twice, as opposed to just limiting the sub query to just the bare minimum of necessary tables. Your choice. :)
Tried that also and it didnt work. I also made a new query trying to Keep it so simple as possible and it doesnt work either. It still give me Single values back..
SELECT p.Datum,a.AufgabenNrCRM,auf.Kunde FROM CRM_Aufgaben a
LEFT JOIN ZUS_Therapie_Positionen p ON p.Id_Aktivitaet = a.AufgabenNrCRM
LEFT JOIN PRO_Auftraege auf ON auf.AuftragNrPRO = a.AuftragNrPRO
LEFT JOIN
(SELECT pa.Datum,au.Kunde FROM CRM_Aufgaben aa
LEFT JOIN ZUS_Therapie_Positionen pa ON pa.Id_Aktivitaet = aa.AufgabenNrCRM
LEFT JOIN PRO_Auftraege au ON au.AuftragNrPRO = aa.AuftragNrPRO
GROUP BY pa.Datum,au.Kunde
HAVING COUNT(*) > 1) SRC
ON SRC.Kunde = auf.Kunde
WHERE p.datum IS NOT NULL
GROUP BY p.Datum,a.AufgabenNrCRM,auf.Kunde
ORDER BY auf.Kunde,p.Datum

Join with comma-separated data returned from function using SQL

I am trying hard on this, but I am unable to solve it. I have data coming comma-separated from a column, and I am splitting it with a function, and I need to return all comma-separated values.
I am doing something like outer join ApplicationDocument Table.
Here is the query:
SELECT PA.Id,
Ad.Id,
Ad.DocumentTitle,
Ad.Path
,
S.value
FROM dbo.ApplicationDocument AS Ad
right JOIN dbo.PostApplication AS PA
ON Ad.ApplicationId = PA.Id
JOIN dbo.Post P
ON PA.JobId = P.Id
outer APPLY dbo.fnSplit(P.RequiredDocuments,',') as S
WHERE S.Value = Ad.DocumentTitle
CROSS APPlY (select value
from dbo.fnSplit(P.RequiredDocuments,',')
WHERE Value =Ad.DocumentTitle) as S
SELECT PA.Id,
Ad.Id,
Ad.DocumentTitle,
Ad.Path,
X.Value
FROM dbo.ApplicationDocument AS Ad
JOIN dbo.PostApplication AS PA
ON Ad.ApplicationId = PA.Id
JOIN dbo.Post P
ON PA.JobId = P.Id
OUTER APPLY
(SELECT Value FROM dbo.fnSplit(P.RequiredDocuments,',') as S
WHERE S.Value = Ad.DocumentTitle) X
I came up with the follwing query by the help of #Humpty Dumpty and #t-clausen-dk.
Here is what I needed. This query now fetches all the records, and I can now filter using a where clause on it.
SELECT PA.Id AS ApplicationId,
Ad.Id AS ApplicationDocumentId,
Ad.DocumentTitle,
Ad.Path,
S.value
FROM dbo.ApplicationDocument AS Ad
right JOIN dbo.PostApplication AS PA
ON Ad.ApplicationId = PA.Id
JOIN dbo.Post P
ON PA.JobId = P.Id
cross APPLY dbo.fnSplit(P.RequiredDocuments,',') as S
where PA.Id = SomeId here
Check the parenthesis, ')'. It's not properly used:
SELECT PA.Id,Ad.Id,Ad.DocumentTitle,Ad.Path
FROM dbo.ApplicationDocument AS Ad
INNER JOIN dbo.PostApplication AS PA
ON Ad.ApplicationId = PA.Id
INNER JOIN dbo.Post P
ON PA.JobId = P.Id
CROSS APPlY (select value from dbo.fnSplit(P.RequiredDocuments,',')
WHERE Value =Ad.DocumentTitle))

Error: Cannot use an aggregate or a subquery in an expression used for the group by list

I'm getting this error: Cannot use an aggregate or a subquery in an expression used for the group by list of a GROUP BY clause.
I searched on internet, but i don't know how to apply the correction in my case. I found different types of query only.
I'm trying to get a Count result in a field (line 5), but when I add the Count query i'm getting this error.
I'm using SQL SERVER 2008 R2.
When I remove the Count from SELECT and GROUP BY the query run correctly.
SELECT TF.COD_FORNECEDOR AS 'Cód. Fornec.',
TF.NOM_FANTASIA AS 'Fornecedor',
DM.COD_CONTRATO_RELACIONADO AS 'CONTRATO',
UA2.NOM_USUARIO AS 'NOM_USUARIO_COMPRADOR',
(SELECT COUNT(COD_CONTRATO_RELACIONADO) FROM TB_DEMANDA D INNER JOIN TB_PROCESSO P ON D.COD_CONTRATO_RELACIONADO = P.NUM_CONTRATO WHERE D.COD_CONTRATO_RELACIONADO = DM.COD_CONTRATO_RELACIONADO) AS 'NUM_ADITIVO',
0 AS 'Qtd. Aditivo',
SUM(DM.VAL_TOTAL_ORCADO) AS 'Valor Inicial',
SUM(TP.VAL_CONTRATADO) AS 'Valor Final',
((SUM(TP.VAL_CONTRATADO) / SUM(DM.VAL_TOTAL_ORCADO)) -1) * 100 AS 'Var. %'
FROM TB_FORNECEDOR TF
LEFT JOIN TB_DEMANDA DM ON DM.COD_FORNECEDOR = TF.COD_FORNECEDOR
LEFT JOIN TB_PROCESSO TP ON DM.COD_DEMANDA = TP.COD_DEMANDA
LEFT JOIN TB_PROCESSO_FORNECEDOR PF ON PF.COD_PROCESSO = TP.COD_PROCESSO
LEFT JOIN USUARIO UA ON UA.NUM_USUARIO = DM.NUM_USUARIO_COMPRADOR
LEFT JOIN USUARIO UA2 ON UA2.NUM_USUARIO = DM.NUM_USUARIO_COMPRADOR
LEFT JOIN TB_STATUS_DEMANDA_DATA SD ON SD.COD_DEMANDA = DM.COD_DEMANDA
LEFT JOIN TB_BASELINE BA ON BA.COD_PROCESSO = TP.COD_PROCESSO
LEFT JOIN TB_BASELINE_TAREFAS BT ON BT.COD_BASELINE = BA.COD_BASELINE AND BT.COD_PROCESSO = BA.COD_PROCESSO
LEFT JOIN TB_STATUS_PROCESSO SP ON SP.COD_STATUS = SD.COD_STATUS
LEFT JOIN TB_MEDIO_STATUS MS ON MS.COD_MEDIO_STATUS = SP.COD_MEDIO_STATUS
left JOIN #TB_PROCESSO TT ON TT.COD_PROCESSO = TP.COD_PROCESSO
GROUP BY
TF.COD_FORNECEDOR,
TF.NOM_FANTASIA,
DM.COD_CONTRATO_RELACIONADO,
UA2.NOM_USUARIO,
(SELECT COUNT(COD_CONTRATO_RELACIONADO) FROM TB_DEMANDA D INNER JOIN TB_PROCESSO P ON D.COD_CONTRATO_RELACIONADO = P.NUM_CONTRATO WHERE D.COD_CONTRATO_RELACIONADO = DM.COD_CONTRATO_RELACIONADO)
ORDER BY TF.NOM_FANTASIA
Try this:
SELECT TF.COD_FORNECEDOR AS 'Cód. Fornec.',
TF.NOM_FANTASIA AS 'Fornecedor',
DM.COD_CONTRATO_RELACIONADO AS 'CONTRATO',
UA2.NOM_USUARIO AS 'NOM_USUARIO_COMPRADOR',
sq.cnt AS 'NUM_ADITIVO',
0 AS 'Qtd. Aditivo',
SUM(DM.VAL_TOTAL_ORCADO) AS 'Valor Inicial',
SUM(TP.VAL_CONTRATADO) AS 'Valor Final',
((SUM(TP.VAL_CONTRATADO) / SUM(DM.VAL_TOTAL_ORCADO)) -1) * 100 AS 'Var. %'
FROM TB_FORNECEDOR TF
LEFT JOIN TB_DEMANDA DM ON DM.COD_FORNECEDOR = TF.COD_FORNECEDOR
LEFT JOIN TB_PROCESSO TP ON DM.COD_DEMANDA = TP.COD_DEMANDA
LEFT JOIN TB_PROCESSO_FORNECEDOR PF ON PF.COD_PROCESSO = TP.COD_PROCESSO
LEFT JOIN USUARIO UA ON UA.NUM_USUARIO = DM.NUM_USUARIO_COMPRADOR
LEFT JOIN USUARIO UA2 ON UA2.NUM_USUARIO = DM.NUM_USUARIO_COMPRADOR
LEFT JOIN TB_STATUS_DEMANDA_DATA SD ON SD.COD_DEMANDA = DM.COD_DEMANDA
LEFT JOIN TB_BASELINE BA ON BA.COD_PROCESSO = TP.COD_PROCESSO
LEFT JOIN TB_BASELINE_TAREFAS BT ON BT.COD_BASELINE = BA.COD_BASELINE AND BT.COD_PROCESSO = BA.COD_PROCESSO
LEFT JOIN TB_STATUS_PROCESSO SP ON SP.COD_STATUS = SD.COD_STATUS
LEFT JOIN TB_MEDIO_STATUS MS ON MS.COD_MEDIO_STATUS = SP.COD_MEDIO_STATUS
LEFT JOIN #TB_PROCESSO TT ON TT.COD_PROCESSO = TP.COD_PROCESSO
LEFT JOIN (
SELECT D.COD_CONTRATO_RELACIONADO, COUNT(COD_CONTRATO_RELACIONADO) AS cnt
FROM TB_DEMANDA D
INNER JOIN TB_PROCESSO P ON D.COD_CONTRATO_RELACIONADO = P.NUM_CONTRATO
GROUP BY D.COD_CONTRATO_RELACIONADO
) sq ON sq.COD_CONTRATO_RELACIONADO = DM.COD_CONTRATO_RELACIONADO
GROUP BY
TF.COD_FORNECEDOR,
TF.NOM_FANTASIA,
DM.COD_CONTRATO_RELACIONADO,
UA2.NOM_USUARIO,
sq.cnt
ORDER BY TF.NOM_FANTASIA
I integrated the num_aditivo subquery in a LEFT JOIN.

JOIN / LEFT JOIN conflict in SQL Server

I have a tricky query. I need to select all recent versions of 2 types of members of administrator groups. Here is the query:
SELECT refGroup.*
FROM tblSystemAdministratorGroups refGroup
JOIN tblGroup refMem ON refGroup.AttributeValue = refMem.ObjectUID
This query will return all the administrator groups. The next step will be getting the members of these groups. Since I have 2 types of memberships (Explicit, Computed), I will have to use a LEFT JOIN to make sure that I am not excluding any rows.
SELECT refGroup.*
FROM tblSystemAdministratorGroups refGroup
-- The JOIN bellow can be excluded but it is here just to clarify the architecture
JOIN tblGroup refMem ON refGroup.AttributeValue = refMem.ObjectUID
LEFT JOIN tblGroup_ComputedMember cm ON refMem.ObjectUID = cm.GroupObjectID
LEFT JOIN tblGroup_ExplicitMember em ON refMem.ObjectUID = em.GroupObjectID
The last piece in the puzzle is to get the latest version of each member. For that I will have to use JOIN to exclude older versions:
JOIN (
SELECT MAX([ID]) MaxId
FROM [OmadaReporting].[dbo].tblGroup_ComputedMember
GROUP BY ObjectID
) MostRecentCM ON MostRecentCM.MaxId = cm.Id
and
JOIN (
SELECT MAX([ID]) MaxId
FROM [OmadaReporting].[dbo].tblGroup_ExplicitMember
GROUP BY ObjectID
) MostRecentEM ON MostRecentEM.MaxId = em.Id
The full query will be:
SELECT refGroup.*
FROM tblSystemAdministratorGroups refGroup
JOIN tblGroup refMem ON refGroup.AttributeValue = refMem.ObjectUID
LEFT JOIN tblGroup_ComputedMember cm ON refMem.ObjectUID = cm.GroupObjectID
JOIN (
SELECT MAX([ID]) MaxId
FROM [OmadaReporting].[dbo].tblGroup_ComputedMember
GROUP BY ObjectID
) MostRecentCM ON MostRecentCM.MaxId = cm.Id
LEFT JOIN tblGroup_ExplicitMember em ON refMem.ObjectUID = em.GroupObjectID
JOIN (
SELECT MAX([ID]) MaxId
FROM [OmadaReporting].[dbo].tblGroup_ExplicitMember
GROUP BY ObjectID
) MostRecentEM ON MostRecentEM.MaxId = em.Id
The issue is clear: The 2 JOIN to exclude old versions are also applied to the select statement and clearly no rows are returned. What would be the best solution to escape such situation and to return the intended values?
SELECT refGroup.*
FROM tblSystemAdministratorGroups refGroup
JOIN tblGroup refMem ON refGroup.AttributeValue = refMem.ObjectUID
LEFT JOIN (
select GroupObjectID, ID, max(ID) over (partition by ObjectID) as maxID
from tblGroup_ComputedMember
) cm ON refMem.ObjectUID = cm.GroupObjectID and cm.ID = cm.maxID
LEFT JOIN (
select GroupObjectID, ID, max(ID) over (partition by ObjectID) as maxID
from tblGroup_ExplicitMember
) em ON refMem.ObjectUID = em.GroupObjectID and em.ID = em.maxID
where cm.ID = cm.MaxID
What about using LEFT join in your last two joins?
LEFT JOIN (
SELECT MAX([ID]) MaxId
FROM [OmadaReporting].[dbo].tblGroup_ComputedMember
GROUP BY ObjectID
) MostRecentCM ON MostRecentCM.MaxId = cm.Id
And then in Where clause filter values as:
WHERE MostRecentCM.MaxId IS NOT NULL
OR
MostRecentEM.MaxId IS NOT NULL