How to use a created column as a JOIN parameter SQL query - sql

I have 3 Tables of Data which i am trying to Join (TEXTDATA, STOREDATA, SALESDATA). My TEXTDATA has a name string within on of the columns so have created a substring to find it.
I am trying to then used that newly formed string (name) as the basis to join to the SALESDATA table.
Here is my code
SELECT b.*,
a.text,
a.textname,
SUBSTRING(a.[textname], CHARINDEX('/ ', a.[textname]) + 1, 11) AS NAME,
c.[Sales],
c.[Customer],
c.[Class]
FROM [dbo].[TEXTDATA] a
INNER JOIN [dbo].[STOREDATA] b
ON a.[ID_TEXTDATA] = b.[ID_STOREDATA]
LEFT JOIN [dbo].[SALESDATA] c
ON NAME = c.FirstName
With the error saying Invalid column name 'name'
Any ideas on how to reference the new column made later in a query?
Thanks very much!

Easiest option is just to use the same formula in the LEFT JOIN's ON clause:
LEFT JOIN [dbo].[SALESDATA] c
ON SUBSTRING(a.[textname],CHARINDEX('/ ',a.[textname])+1,11) = c.FirstName
Or you could put the formula in a CTE abstraction of your TEXTDATA table:
;with cte AS (
SELECT [ID_TEXTDATA], text, textname, SUBSTRING(a.[textname],CHARINDEX('/ ',a.[textname])+1,11) as name
From [dbo].[TEXTDATA] a
)
SELECT b.*
,cte.text
,cte.textname
,cte.name
,c.[Sales]
,c.[Customer]
,c.[Class]
From
cte
INNER JOIN [dbo].[STOREDATA] b
on cte.[ID_TEXTDATA] = b.[ID_STOREDATA]
LEFT JOIN [dbo].[SALESDATA] c
on cte.name = c.FirstName

Select b.*
,a.text
,a.textname
,SUBSTRING(a.[textname],CHARINDEX('/ ',a.[textname])+1,11) as name
,c.[Sales]
,c.[Customer]
,c.[Class]
From
[dbo].[TEXTDATA] a
INNER JOIN [dbo].[STOREDATA] b
on a.[ID_TEXTDATA] = b.[ID_STOREDATA]
LEFT JOIN [dbo].[SALESDATA] c
on SUBSTRING(a.[textname],CHARINDEX('/ ',a.[textname])+1,11) = c.FirstName
First, join takes place and can't find the name

I think you should try this in your ON CLAUSE:
SUBSTRING(a.[textname],CHARINDEX('/ ',a.[textname])+1,11)
Select b.*,a.text,a.textname,SUBSTRING(a.[textname],CHARINDEX('/ ',a.[textname])+1,11)
as name,c.[Sales] ,c.[Customer],c.[Class]
From [dbo].[TEXTDATA] a
INNER JOIN [dbo].[STOREDATA] b
on a.[ID_TEXTDATA] = b.[ID_STOREDATA]
LEFT JOIN [dbo].[SALESDATA] c
on SUBSTRING(a.[textname],CHARINDEX('/ ',a.[textname])+1,11) = c.FirstName

You can't reference the column alias name on the same level.
You have to use the entire expression on the ON
ON SUBSTRING(a.[textname],CHARINDEX('/ ',a.[textname])+1,11) = c.FirstName
Or you can make use of a CTE or derived query and compose the expression name in the CTE or derived query.
with Text_Data as
(
SELECT *,
SUBSTRING(a.[textname],CHARINDEX('/ ',a.[textname])+1,11) as [name]
FROM [dbo].[TEXTDATA] a
)
Select b.*
,a.text
,a.textname
,a.name
,c.[Sales]
,c.[Customer]
,c.[Class]
From
Text_Data a
INNER JOIN [dbo].[STOREDATA] b
on a.[ID_TEXTDATA] = b.[ID_STOREDATA]
LEFT JOIN [dbo].[SALESDATA] c
on a.name = c.FirstName
Or alternatively use a CROSS APPLY to compute the expression and then use it in the JOIN
Select b.*
,a.text
,a.textname
,n.name
,c.[Sales]
,c.[Customer]
,c.[Class]
From
[dbo].[TEXTDATA] a
CROSS APPLY
(
SELECT SUBSTRING(a.[textname],CHARINDEX('/ ',a.[textname])+1,11) as name
) n
INNER JOIN [dbo].[STOREDATA] b
on a.[ID_TEXTDATA] = b.[ID_STOREDATA]
LEFT JOIN [dbo].[SALESDATA] c
on n.name = c.FirstName

As the order of execution of SQL query says the select statement is run after all join statements so you can use alias in select for manipulation but not the same manipulated alias in join as join has already run by that time instead ypu need to have an extra select on top of it or using a WITH CLAUSE Subquery
Select *, name from ( select *,.. as
name from table) left join othertable
t1 on
name=t1.value
Or using WITH CLAUSE
WITH data as
( select *,.. as name from table)
Select * from data left join table1 t1
on data.name=t1.value

Related

How do I make the TotalScores unique to their Reference data in my View?

I have a View that has a column named 'Reference' and a column named 'RateeId' and collects and computes data from another table and used SUM function to get its TotalScores. However, when I input the same RateeId but different Reference, the SUM calculates both and displays the same Scores.
This is what I have tried so far.
This is my script for my view:
select e.Id, b.Name, f.SiteName, e.Reference, e.Amount, e.DateTransaction, SUM(a.Score * (c.Weight / 100) * (d.Weight / 100)) as TotalScore, a.Status, a.CreatedByUserId
from prs_rate as a
left outer join prs_ratee as b on a.RateeId = b.Id
left outer join prs_kpi as c on a.KpiId = c.Id
left outer join prs_group as d on c.GroupId = d.Id
left outer join prs_totalratee as e on a.RateeId = e.RateeId
left outer join core_vSiteInfo as f on e.SiteCatered = f.siteCode
group by b.Name, a.Status, a.CreatedByUserId, e.Reference, e.Amount, e.DateTransaction, f.SiteName, e.Id
This is what it returned:
This is the View prs_vMainKPI. The result of the above script.
Please add order by clause and try again...
select e.Id, b.Name, f.SiteName, e.Reference, e.Amount, e.DateTransaction, SUM(a.Score * (c.Weight / 100) * (d.Weight / 100)) as TotalScore, a.Status, a.CreatedByUserId
from prs_rate as a
left outer join prs_ratee as b on a.RateeId = b.Id
left outer join prs_kpi as c on a.KpiId = c.Id
left outer join prs_group as d on c.GroupId = d.Id
left outer join prs_totalratee as e on a.RateeId = e.RateeId
left outer join core_vSiteInfo as f on e.SiteCatered = f.siteCode
group by e.Id, e.Reference, b.Name, a.Status, a.CreatedByUserId, e.Amount, e.DateTransaction, f.SiteName
order by e.Id, e.Reference

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

update table column using two subset query

I am using one query where i have to update one column for that i have two subset of query which is below:
select a.AuthorId as 'Source_Author',b.AuthorId as 'Target_Author' from (
select d.documentnodeid,AuthorId from wv_blogdata
inner join CMS_Document d on wv_blogdata.BlogDataID = d.DocumentForeignKeyValue
Where DocumentCulture ='en-US') a
INNER JOIN
(select d.documentnodeid,AuthorId from wv_blogdata
inner join CMS_Document d on wv_blogdata.BlogDataID = d.DocumentForeignKeyValue
Where DocumentCulture ='de-DE') b
ON a.documentnodeid =b.documentnodeid
using this query i have value like below:
Now i have to update target author with source author.
Use a common table expression
;WITH cteUpdate
AS(
select a.AuthorId as 'Source_Author',b.AuthorId as 'Target_Author'
FROM
(
SELECT d.documentnodeid,AuthorId from wv_blogdata
INNER join CMS_Document d on wv_blogdata.BlogDataID = d.DocumentForeignKeyValue
WHERE DocumentCulture ='en-US'
) a
INNER JOIN
( SELECT d.documentnodeid,AuthorId from wv_blogdata
INNER join CMS_Document d on wv_blogdata.BlogDataID = d.DocumentForeignKeyValue
WHERE DocumentCulture ='de-DE'
) b
ON a.documentnodeid =b.documentnodeid
)
UPDATE
cteUpdate
SET
cteUpdate.Target_Author = cteUpdate.Source_Author

Problems with Sql query join

I am struggling with a sql query. I want to include the sum from an other table.
SELECT DISTINCT
tblProject.CompanyID,
tblCompany.Name,
tblCompany.AvtalsKund,
tblProject.ProjectName,
tblProject.Estimate,
tblProject.ProjectStart,
tblProject.Deadline,
CONVERT(VARCHAR(8), tblProject.Deadline, 2) AS [YY.MM.DD] ,
tblProject.PreOffered,
tblProject.ProjectType,
tblProjectType.ProjType,
tblOrdered.FirstName + + tblOrdered.LastName as OrderedFullName,
tblProject.ProjectID,
tblProject.RegDate,
tblProject.ProjectNr,
tblProject.ProjectNr
FROM tblProject
INNER JOIN tblCompany ON tblProject.CompanyID = tblCompany.CompanyID
---> INNER JOIN (SELECT tblTimeRecord.ProjectID, SUM(CONVERT(float,replace([Hours],',','') ))
FROM tblTimeRecord group by tblTimeRecord.ProjectID) as b
ON b.ProjectID = tblProject.ProjectID
INNER JOIN tblTimeRecord ON tblTimeRecord.ProjectID = tblProject.ProjectID
INNER JOIN tblProjectType ON tblProject.ProjectType = tblProjectType.ProjTypeID
LEFT OUTER JOIN tblOrdered ON tblProject.OrderedBy = tblOrdered.OrderedID
LEFT OUTER JOIN tblRel_WorkerProject ON tblProject.ProjectID = tblRel_WorkerProject.ProjectID
LEFT OUTER JOIN tblPerson ON tblPerson.PersonID = tblRel_WorkerProject.WorkerID
LEFT OUTER JOIN tblRel_StatusWorkerProject ON tblProject.ProjectID = tblRel_StatusWorkerProject.ProjectID
I want to include this sum-block from table tblTimeRecord.
I get a sum of timerapports with this code
SELECT tblTimeRecord.ProjectID,
SUM(CONVERT(float,replace([Hours],',','') ))
FROM tblTimeRecord where ProjectID=1312 group by tblTimeRecord.ProjectID
Guess i do it in join?
Got it working with this.
SELECT DISTINCT
tblProject.ProjectID,
Summa,
tblProject.CompanyID,
tblCompany.Name,
tblCompany.AvtalsKund,
tblProject.ProjectName,
tblProject.Estimate,
tblProject.ProjectStart,
tblProject.Deadline,
CONVERT(VARCHAR(8), tblProject.Deadline, 2) AS [YY.MM.DD] ,
tblProject.PreOffered,
tblProject.ProjectType,
tblProjectType.ProjType,
tblOrdered.FirstName + + tblOrdered.LastName as OrderedFullName,
tblProject.ProjectID,
tblProject.RegDate,
tblProject.ProjectNr,
tblProject.ProjectNr
FROM tblProject
INNER JOIN tblCompany ON tblProject.CompanyID = tblCompany.CompanyID
INNER JOIN (SELECT tblTimeRecord.ProjectID, SUM(CONVERT(float,replace([Hours],',','') )) as Summa FROM tblTimeRecord group by tblTimeRecord.ProjectID) as b
ON b.ProjectID = tblProject.ProjectID
INNER JOIN tblTimeRecord ON tblTimeRecord.ProjectID = tblProject.ProjectID
INNER JOIN tblProjectType ON tblProject.ProjectType = tblProjectType.ProjTypeID
LEFT OUTER JOIN tblOrdered ON tblProject.OrderedBy = tblOrdered.OrderedID
LEFT OUTER JOIN tblRel_WorkerProject ON tblProject.ProjectID = tblRel_WorkerProject.ProjectID
LEFT OUTER JOIN tblPerson ON tblPerson.PersonID = tblRel_WorkerProject.WorkerID
LEFT OUTER JOIN tblRel_StatusWorkerProject ON tblProject.ProjectID = tblRel_StatusWorkerProject.ProjectID
There are two ways to do this.
You can use a WITH clause to create the aggregate table then join this to the main query.
Or do it this way:
SELECT m.BLAH
,m.FOO
,x.AMOUNT
FROM MAINTABLE m
LEFT JOIN
(
SELECT FOO
,SUM(AMOUNT) as AMOUNT
FROM OTHERTABLE
GROUP BY FOO
) x
ON m.FOO = x.FOO
I prefer the second way.

subquery - how to refer to outer query value

The query below is working fine:
SELECT
tblCase.ID AS CaseID, tblCase.UserID AS MyCasesFilter,
tblGroupMembership.UserID AS GroupShareFilter,
tblDirectCaseSharing.ReceiverUserID AS DirectShareFilter, tblCase.EntryDate,
tblUser.LastName AS CaseAuthor, tblCase.Name AS CaseName,
COUNT(DISTINCT tblCaseImage.ID) AS TotalImages,
tblCaseType.Name AS CaseType, tblCase.SiteName, tblCase.Category,
tblCase.FollowUpDateTime, tblCase.Notes
FROM
tblDirectCaseSharing
RIGHT OUTER JOIN
tblCase
INNER JOIN tblUser ON tblCase.UserID = tblUser.ID ON tblDirectCaseSharing.CaseID = tblCase.ID
LEFT OUTER JOIN
tblGroupMembership
INNER JOIN
tblGroupCase ON tblGroupMembership.GroupID = tblGroupCase.GroupID ON tblCase.ID = tblGroupCase.CaseID
LEFT OUTER JOIN
tblCaseType ON tblCase.CaseTypeID = tblCaseType.ID
LEFT OUTER JOIN
tblCaseImage ON tblCase.ID = tblCaseImage.CaseID
GROUP BY
tblCase.ID, tblCaseType.Name, tblCase.SiteName, tblCase.EntryDate,
tblCase.Category, tblCase.FollowUpDateTime, tblCase.Notes, tblCase.UserID,
tblGroupMembership.UserID, tblDirectCaseSharing.ReceiverUserID,
tblUser.LastName, tblCase.Name
HAVING
(tblCase.UserID = 1)
AND (tblGroupMembership.UserID = 2)
AND (tblDirectCaseSharing.ReceiverUserID = 3)
ORDER BY
tblCase.EntryDate DESC
I want to add an additional select column to the above result using a select subquery which is:
STUFF((
SELECT ', ' +tblGroup.Name as [text()]
FROM tblCase INNER JOIN
tblGroupCase ON tblCase.ID = tblGroupCase.CaseID INNER JOIN
tblGroup ON tblGroupCase.GroupID = tblGroup.ID
WHERE tblCase.ID = ***
FOR XML PATH('')
),1,2,'')
AS ConcatGroupShares
The select subquery has a where clause and I need to get the tblcase.id which is the first column of the result set. how to i reference that value in the subquery.
Put an alias name in the main query
SELECT
tcase.ID AS CaseID, tblCase.UserID AS MyCasesFilter,
tblGroupMembership.UserID AS GroupShareFilter,
tblDirectCaseSharing.ReceiverUserID AS DirectShareFilter, tblCase.EntryDate,
tblUser.LastName AS CaseAuthor, tblCase.Name AS CaseName,
COUNT(DISTINCT tblCaseImage.ID) AS TotalImages,
tblCaseType.Name AS CaseType, tblCase.SiteName, tblCase.Category,
tblCase.FollowUpDateTime, tblCase.Notes
FROM
tblDirectCaseSharing
RIGHT OUTER JOIN
tblCase As tcase <=====
And use this alias name in the subquery:
STUFF((
SELECT ', ' +tblGroup.Name as [text()]
FROM tblCase INNER JOIN
tblGroupCase ON tblCase.ID = tblGroupCase.CaseID INNER JOIN
tblGroup ON tblGroupCase.GroupID = tblGroup.ID
WHERE tblCase.ID = tcase.id
FOR XML PATH('')
),1,2,'')
AS ConcatGroupShares
More about co-related sub-queries:
http://en.wikipedia.org/wiki/Correlated_subquery