Join with comma-separated data returned from function using SQL - 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))

Related

SQL many to many select people with multiple vacancies

I am working with sql server through SSMS right now. How can i choose all people with multiple(>2)vacancies?
I am trying something like that, but i dont understand how to make part with "more than 2 vacancies"?
SELECT dbo.applicants.FirstName, dbo.vacancy.Name
FROM dbo.applicants INNER JOIN
dbo.VacancyApplicant ON dbo.applicants.id = dbo.VacancyApplicant.ApplicantId INNER JOIN
dbo.vacancy ON dbo.VacancyApplicant.VacancyId = dbo.vacancy.id WHERE dbo.vacancy.Name='third vacancy'
SELECT dbo.applicants.FirstName, dbo.vacancy.Name
FROM dbo.applicants A INNER JOIN
dbo.VacancyApplicant V ON A.id = V.ApplicantId
WHERE EXIST(
SELECT 1
FROM dbo.applicants INNER JOIN
dbo.VacancyApplicant ON dbo.applicants.id =
dbo.VacancyApplicant.ApplicantId INNER JOIN
dbo.vacancy ON dbo.VacancyApplicant.VacancyId = dbo.vacancy.id
WHERE A.id=dbo.applicants.id
GROUP BY dbo.applicants.id,dbo.vacancy.id
HAVING COUNT(1)>2
)
Group By and Having are you basic answer. Below is a simple solution, might not be ideal, but can give you the idea.
I am finding target "applicants" ids in subquery, that uses GROUP BY and HAVING then outer query joins to that to output FirstName and LastName of applicant
SELECT dbo.applicants.FirstName, dbo.applicants.LastName FROM
dbo.applicants a INNER JOIN
(
SELECT dbo.applicants.id
FROM dbo.applicants INNER JOIN
dbo.VacancyApplicant ON dbo.applicants.id = dbo.VacancyApplicant.ApplicantId INNER JOIN
dbo.vacancy ON dbo.VacancyApplicant.VacancyId = dbo.vacancy.id AND dbo.vacancy.Name='third vacancy'
GROUP BY dbo.applications.id
HAVING COUNT(dbo.vacancy.id) > 2
) targetIds ON a.id = targetIds.id
"more than 2 vacancies"?
Your question only mentions vacancies but your query is filtering for a particular name. I assume you really want more than two of that name.
If I understand correctly, you want aggregation:
SELECT a.FirstName, a.Name
FROM dbo.applicants a INNER JOIN
dbo.VacancyApplicant va
ON a.id = va.ApplicantId INNER JOIN
dbo.vacancy v
ON va.VacancyId = v.id
WHERE v.Name = 'third vacancy'
GROUP BY a.FirstName, v.Name
HAVING COUNT(*) > 2;
Note the use of table aliases. They make the query easier to write and to read.
WITH TempCTE AS (
SELECT DISTINCT ap.FirstName
,vc.Name
,COUNT (va.VacancyId) OVER (PARTITION BY ap.id) AS NoOfVacancies
FROM dbo.applicants ap
JOIN dbo.VacancyApplicant va
ON ap.id = va.ApplicantId
JOIN dbo.vacancy vc
ON va.VacancyId = vc.id
)
SELECT FirstName,[Name], NoOfVacancies FROM TempCTE
WHERE NoOfVacancies > 2

How to create distinct count from queries with several tables

I am trying to create one single query that will give me a distinct count for both the ActivityID and the CommentID. My query in MS Access looks like this:
SELECT
tbl_Category.Category, Count(tbl_Activity.ActivityID) AS CountOfActivityID,
Count(tbl_Comments.CommentID) AS CountOfCommentID
FROM tbl_Category LEFT JOIN
(tbl_Activity LEFT JOIN tbl_Comments ON
tbl_Activity.ActivityID = tbl_Comments.ActivityID) ON
tbl_Category.CategoryID = tbl_Activity.CategoryID
WHERE
(((tbl_Activity.UnitID)=5) AND ((tbl_Comments.PeriodID)=1))
GROUP BY
tbl_Category.Category;
I know the answer must somehow include SELECT DISTINCT but am not able to get it to work. Do I need to create multiple subqueries?
This is really painful in MS Access. I think the following does what you want to do:
SELECT ac.Category, ac.num_activities, aco.num_comments
FROM (SELECT ca.category, COUNT(*) as num_activities
FROM (SELECT DISTINCT c.Category, a.ActivityID
FROM (tbl_Category as c INNER JOIN
tbl_Activity as a
ON c.CategoryID = a.CategoryID
) INNER JOIN
tbl_Comments as co
ON a.ActivityID = co.ActivityID
WHERE a.UnitID = 5 AND co.PeriodID = 1
) as caa
GROUP BY ca.category
) as ca LEFT JOIN
(SELECT c.Category, COUNT(*) as num_comments
FROM (SELECT DISTINCT c.Category, co.CommentId
FROM (tbl_Category as c INNER JOIN
tbl_Activity as a
ON c.CategoryID = a.CategoryID
) INNER JOIN
tbl_Comments as co
ON a.ActivityID = co.ActivityID
WHERE a.UnitID = 5 AND co.PeriodID = 1
) as aco
GROUP BY c.Category
) as aco
ON aco.CommentId = ac.CommentId
Note that your LEFT JOINs are superfluous because the WHERE clause turns them into INNER JOINs. This adjusts the logic for that purpose. The filtering is also very tricky, because it uses both tables, requiring that both subqueries have both JOINs.
You can use DISTINCT:
SELECT
tbl_Category.Category, Count(DISTINCT tbl_Activity.ActivityID) AS CountOfActivityID,
Count(DISTINCT tbl_Comments.CommentID) AS CountOfCommentID
FROM tbl_Category LEFT JOIN
(tbl_Activity LEFT JOIN tbl_Comments ON
tbl_Activity.ActivityID = tbl_Comments.ActivityID) ON
tbl_Category.CategoryID = tbl_Activity.CategoryID
WHERE
(((tbl_Activity.UnitID)=5) AND ((tbl_Comments.PeriodID)=1))
GROUP BY
tbl_Category.Category;

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;

How to Fix Right Outer Join

I am Trying to make Left Outer Join Use bellow code;
The Result Using (LEFT OUTER , RIGHT OUTER, FULL OUTER And INNER JOIN) is The same Result.
I am Try to return All Publisher Name Include Those who don't connected with any Books yet!
SELECT P.PublisherName,
COUNT(B.BookID) AS BookPublished
FROM LR_Publisher AS P LEFT OUTER JOIN LR_Book As B
ON P.PublisherID = B.PublisherID
WHERE (P.PublisherID = #pPublisherID OR #pPublisherID IS NULL)
GROUP BY PublisherName
Thanks In Advance
Publishers that have no books published are filtered out by GROUP BY.
It can be fixed by using GROUP BY ALL:
SELECT P.PublisherName,
COUNT(B.BookID) AS BookPublished
FROM LR_Publisher AS P
LEFT OUTER JOIN LR_Book As B ON P.PublisherID = B.PublisherID
-- WHERE (P.PublisherID = #pPublisherID OR #pPublisherID IS NULL)
GROUP BY PublisherName
you could write it this way
select P.PublisherName,
isnull(bi.BookPublished, 0) as BookPublished
from LR_Publisher as P
left join (
select B.PublisherID, Count(B.BookID) BookPublished
from LR_Book as B
where (#pPublisherID is null or B.PublisherID = #pPublisherID)
group by B.PublisherID
) bi on P.PublisherID = Bi.PublisherID
where (#pPublisherID is null or P.PublisherID = #pPublisherID)
I also was not aware of the filtering done by group by. Thank you for the question.
simple left join will help you want all publisher name including who does not published any book yet
SELECT P.PublisherName
FROM LR_Publisher AS P LEFT OUTER JOIN LR_Book As B
ON P.PublisherID = B.PublisherID

Duplicate Results with LISTAGG Function

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.