Add logic inside of a SELECT - sql

Note in the below query that the first two queries inside of the parenthesis, I've added two repeated queries, I'm sure that this is not a good practice. I need to repeat this query anytime where I need the value.
SQL Server is throwing an exception about not to write DECLARE inside of the SELECT keyword. What can I do or what I'm missing to refactor it?
SELECT A.StudentId,
(
CASE WHEN (SELECT B.OverwrittenScore
FROM dbo.OverwrittenScores AS B
WHERE B.StudentId = A.StudentId
AND B.AssignmentId = #assignmentId
) IS NOT NULL
THEN (
SELECT B.OverwrittenScore
FROM dbo.OverwrittenScores AS B
WHERE B.StudentId = A.StudentId
AND B.AssignmentId = #assignmentId)
ELSE (-- ANOTHER QUERY, BY THE MOMENT: SELECT 0 )
END
) AS FinalScore
FROM dbo.Students AS A

My suggestion would be to look at using a JOIN:
SELECT A.StudentId,
case
when B.OverwrittenScore is not null
then B.OverwrittenScore
else 0
end AS FinalScore
FROM dbo.Students AS A
LEFT JOIN dbo.OverwrittenScores B
ON B.StudentId = A.StudentId
AND B.AssignmentId = #assignmentId
If you want to use another select in the else, then you could add more joins as needed:
SELECT A.StudentId,
case
when B.OverwrittenScore is not null
then B.OverwrittenScore
else c.whatever
end AS FinalScore
FROM dbo.Students AS A
LEFT JOIN dbo.OverwrittenScores B
ON B.StudentId = A.StudentId
AND B.AssignmentId = #assignmentId
LEFT JOIN anothertable c
ON a.col = c.col
Or even you could use COALESCE to replace the null values:
SELECT A.StudentId,
coalesce(B.OverwrittenScore, 0) as FinalScore
FROM dbo.Students AS A
LEFT JOIN dbo.OverwrittenScores B
ON B.StudentId = A.StudentId
AND B.AssignmentId = #assignmentId

Not sure where error regarding DECLARE is coming from, but you could change what you do show to
SELECT
A.StudentId,
COALESCE(B.OverwrittenScore, 0) AS FinalScore
FROM dbo.Students AS A
LEFT JOIN dbo.OverwrittenScores AS B
ON A.StudentId = B.StudentId AND B.AssignmentId = #assignmentId

Related

How to pass multiple values in parameter

In this stored procedure, I need to pass multiple parameter values in #GDNNO. Right now I can pass only a single value.
Please help me.
ALTER PROCEDURE dbo.xspSHEGONPrintQuery4
#GDNNO varchar(4000) = ''
AS
BEGIN
SELECT
a.ID, a.[To], a.FlowCode, a.TranNum, a.Status,
ART.ARTICLECODE, StockGDNID, DetailID, SubDocCode, ArticleID,
ColorCode, ColorName, SizeCode, SizeName,
DispatchedUnits * (CASE WHEN u.value IS NULL THEN FreezeStoringUOM ELSE u.value END) AS DispatchedUnits
FROM
xtstockgdn a (nolock)
JOIN
xtstockgdndetail b (nolock) ON a.id = b.stockgdnid
JOIN
XTARTICLE ART (nolock) ON ART.ID = B.ARTICLEID
LEFT JOIN
xtUOMConversion u (nolock) ON u.FromUOM = art.StoringUOM
AND u.ToUOM = art.consuom
WHERE
a.ID IN (#GDNNO)
AND FlowCode = 'POO_RET[E-]'
END
Since your query is only Select it can be change to TVF(table-value function). Change your Procedure to TVF
CREATE FUNCTION dbo.xspSHEGONPrintQuery4(
#GDNNO varchar(4000) = ''
)
RETURNS TABLE
AS
RETURN
SELECT
a.ID, a.[To], a.FlowCode, a.TranNum, a.Status,
ART.ARTICLECODE, StockGDNID, DetailID, SubDocCode, ArticleID,
ColorCode, ColorName, SizeCode, SizeName,
DispatchedUnits * (CASE WHEN u.value IS NULL THEN FreezeStoringUOM ELSE u.value END) AS DispatchedUnits
FROM
xtstockgdn a (nolock)
JOIN
xtstockgdndetail b (nolock) ON a.id = b.stockgdnid
JOIN
XTARTICLE ART (nolock) ON ART.ID = B.ARTICLEID
LEFT JOIN
xtUOMConversion u (nolock) ON u.FromUOM = art.StoringUOM
AND u.ToUOM = art.consuom
WHERE
a.ID IN (#GDNNO)
AND FlowCode = 'POO_RET[E-]'
END
Then use Cross apply to your TVF
Select a.GDNNO,b.* from yourtable a /*list of GDNNO Values */
Cross Apply dbo.xspSHEGONPrintQuery4(a.GDNNO) b
you can use Dynamic query as well

Pull a separate column that matches the (min) of an aggregate function

It works well so far but I am stumped from here as I am brand new to this. This query finds the closest distance match, pairing up every item in the "FAILED" folder against everything that isn't in the "FAILED" folder.
There is a column "RouteID" in the "table p" that I want to match up with the min() aggregate.
I cannot process how to make the SELECT query simply show the associated "RouteID" column from tbl p but ultimately, I want to turn this into an update query that will SET a.Route = p.Route that is associated with the min()
Any help would be appreciated.
SELECT a.name, a.Reference1,
MIN(round(ACOS(COS(RADIANS(90-a.lat))
*COS(RADIANS(90-p.latpoint))
+SIN(RADIANS(90-a.lat))
*SIN(RADIANS(90-p.latpoint))
*COS(RADIANS(a.lon-p.longpoint)))
*3958.756,2)) AS 'DISTANCE'
FROM tblOrder AS a WITH (NOLOCK)
LEFT JOIN
(
SELECT b.lat AS latpoint, b.lon AS longpoint,
b.Sequence, b.routeid
from tblOrder b WITH (NOLOCK)
WHERE b.CUSTID = 180016
AND b.routeID <> 'FAILED'
AND b.StopType = 1
) AS p ON 1=1
WHERE a.CustID = 180016
AND a.RouteID = 'FAILED'
AND a.StopType = 1
AND P.RouteID <> 'FAILED'
GROUP BY
a.name, a.Reference1
You can select them separately and then join them
SELECT c.name, c.Reference1, q.RouteID
FROM
(
SELECT a.name, a.Reference1,
MIN(round(ACOS(COS(RADIANS(90-a.lat))
*COS(RADIANS(90-p.latpoint))
+SIN(RADIANS(90-a.lat))
*SIN(RADIANS(90-p.latpoint))
*COS(RADIANS(a.lon-p.longpoint)))
*3958.756,2)) AS 'DISTANCE'
FROM tblOrder AS a WITH (NOLOCK)
LEFT JOIN
(
SELECT b.lat AS latpoint, b.lon AS longpoint,
b.Sequence, b.routeid
from tblOrder b WITH (NOLOCK)
WHERE b.CUSTID = 180016
AND b.routeID <> 'FAILED'
AND b.StopType = 1
) AS p ON 1=1
WHERE a.CustID = 180016
AND a.RouteID = 'FAILED'
AND a.StopType = 1
AND P.RouteID <> 'FAILED'
GROUP BY
a.name, a.Reference1
) c
LEFT JOIN
(
SELECT b.lat AS latpoint, b.lon AS longpoint,
b.Sequence, b.routeid
from tblOrderRouteStops b WITH (NOLOCK)
WHERE b.CUSTID = 180016
AND b.routeID <> 'FAILED'
AND b.StopType = 1
) AS q
ON q.routeID = c.DISTANCE

Convert Exist condition to Join with T-SQL

I am trying to convert the following T-SQL Select query to exclude "Exists" Clause and Include "Join" Clause. but i am ending up not getting the right result. can some one from this expert team help me with some tips.
select *
FROM HRData
INNER JOIN (
SELECT eeceeid, MIN(eecdateoftermination) eTermDate
FROM dbo.empcomp
INNER JOIN
(
SELECT xeeid FROM HRData_EEList
INNER JOIN dbo.empcomp t ON xeeid = eeceeid AND xcoid = eeccoid
WHERE eecemplstatus = 'T' AND eectermreason <> 'TRO' AND eeccoid <> 'WAON6'
AND EXISTS ( SELECT 1 FROM dbo.empded
INNER JOIN dbo.dedcode on deddedcode = eeddedcode AND deddedtype = 'MED' AND (eedbenstopdate IS NULL OR eedbenstopdate > '12/31/2005')
WHERE eedeeid = xeeid AND eedcoid = xcoid )
GROUP BY xeeid
HAVING COUNT(*) > 1) Term ON xeeid = eeceeid
group by eeceeid
) Terms ON eeid = eeceeid AND Termdate = eTermDate
The algorithm to convert EXISTS to JOIN is very simple.
Instead of
FROM A
WHERE EXISTS (SELECT *
FROM B
WHERE A.Foo = B.Foo)
Use
FROM A
INNER JOIN (SELECT DISTINCT Foo
FROM B) AS B
ON A.Foo = B.Foo
But the first one probably will be optimised better
Interesting request.
select *
FROM HRData
INNER JOIN (
SELECT eeceeid, MIN(eecdateoftermination) eTermDate
FROM dbo.empcomp
INNER JOIN
(
SELECT xeeid FROM HRData_EEList
INNER JOIN dbo.empcomp t ON xeeid = eeceeid AND xcoid = eeccoid
INNER JOIN
( SELECT DISTINCT xeeid, xcoid FROM dbo.empded
INNER JOIN dbo.dedcode on deddedcode = eeddedcode AND deddedtype = 'MED' AND (eedbenstopdate IS NULL OR eedbenstopdate > '12/31/2005')
-- WHERE eedeeid = xeeid AND eedcoid = xcoid
) AS A ON xeeid = A.xeeid AND eedcoid = A.eedcoid
WHERE eecemplstatus = 'T' AND eectermreason <> 'TRO' AND eeccoid <> 'WAON6'
GROUP BY xeeid
HAVING COUNT(*) > 1) Term ON xeeid = eeceeid
group by eeceeid
) Terms ON eeid = eeceeid AND Termdate = eTermDate
Another method of converting an exists to a join is to use a ROW_NUMBER() in the subselect to assist in removing duplicates.
EXISTS:
FROM A
WHERE EXISTS (SELECT *
FROM B
WHERE B.Condition = 'true' AND A.Foo = B.Foo)
JOIN:
FROM A
JOIN (SELECT B.Foo, ROW_NUMBER() OVER (PARTITION BY B.Foo ORDER BY B.Foo) RN
FROM B
WHERE B.Condition = 'true') DT
ON A.Foo = DT.Foo AND DT.RN = 1
The ORDER BY is totally arbitrary since you don't care which record it selects, but it's required. You may be able to use (SELECT NULL) instead.

Using a group by to group a select statement

Using a group by to group a select stament
SELECT
k.Ivalue, k.JOBDESCRIPTION ,
count( k.Ivalue) as TOTAL
FROM
(SELECT
a."ID" as Ivalue, b."JOBDESCRIPTION", rq."CURRENTSTATUS"
FROM
tblG2o_Requests a
INNER JOIN
tblG2o_JOBS b ON a."JOBPOSTID" = b."ID"
INNER JOIN
(SELECT
r.REQUESTID, ir."CURRENTSTATUS"
FROM
TBLG2O_RESULTSPOOL r
INNER JOIN
tblG2o_Requests ir ON r.RequestID = ir."ID"
WHERE
r.ShortListed = '1') rq ON rq.REQUESTID = a."ID"
WHERE
"ACTIVE" = '1'
AND "DATECOMPLETED" IS NULL
ORDER BY
"REQUESTDATE" DESC) k
GROUP BY
k.JOBDESCRIPTION
What is the question? You seem to be missing the group by clause, and you do not need double quotes around field names unless you have spaces in them, and even then, if TSQL for example, you would use [] in preference.
I had to remove an ORDER BY in the subquery, that isn't allowed unless other conditions demand it (like TOP n in TSQL)
SELECT
k.Ivalue
, k.JOBDESCRIPTION
, COUNT(k.Ivalue) AS TOTAL
FROM (
SELECT
a.ID AS Ivalue
, b.JOBDESCRIPTION
, rq.CURRENTSTATUS
FROM tblG2o_Requests a
INNER JOIN tblG2o_JOBS b
ON a.JOBPOSTID = b.ID
INNER JOIN (
SELECT
r.REQUESTID
, ir.CURRENTSTATUS
FROM TBLG2O_RESULTSPOOL r
INNER JOIN tblG2o_Requests ir
ON r.RequestID = ir.ID
WHERE r.ShortListed = '1'
) rqenter
ON rq.REQUESTID = a.ID
WHERE ACTIVE = '1'
AND DATECOMPLETED IS NULL
) k
GROUP BY
k.Ivalue
, k.JOBDESCRIPTION
Finally worked
SELECT
k.Ivalue
, l.JOBDESCRIPTION
, k.TOTAL,
k.CURRENTSTATUS
FROM (
SELECT
a.ID AS Ivalue
,b.ID as JobPostID
, rq."CURRENTSTATUS"
,COUNT(a.ID) AS TOTAL
FROM tblG2o_Requests a
INNER JOIN tblG2o_JOBS b
ON a."JOBPOSTID" = b.ID
INNER JOIN (
SELECT
r."REQUESTID"
, ir."CURRENTSTATUS"
FROM TBLG2O_RESULTSPOOL r
INNER JOIN tblG2o_Requests ir
ON r."REQUESTID" = ir.ID
WHERE r."SHORTLISTED" = 1
) rq
ON rq."REQUESTID" = a.ID
WHERE ACTIVE = '1'
AND DATECOMPLETED IS NULL
GROUP BY
a.ID ,b.ID
, rq."CURRENTSTATUS" ) k
inner join tblG2o_JOBS l on k.JobPostID =l.ID
enter code here

How to join these two queries?

This query gets several AssignmentId's
SELECT AS2.AssignmentId
FROM dbo.AssignmentSummary AS AS2
WHERE AS2.SixweekPosition = 1 AND AS2.TeacherId = 'mggarcia'
This query gets a value for only one assignment through the variable #assignmentId
SELECT S.StudentId,
CASE WHEN OW.OverwrittenScore IS NOT NULL
THEN OW.OverwrittenScore
ELSE dbo.GetFinalScore(S.StudentId, #assignmentId)
END AS FinalScore
FROM dbo.Students AS S
LEFT JOIN dbo.OverwrittenScores AS OW
ON S.StudentId = OW.StudentID
AND OW.AssignmentId = #assignmentId
WHERE S.ClassId IN (
SELECT C.ClassId
FROM Classes AS C
WHERE C.TeacherId = #teacherId
)
As I pointed, in the last query works when you assign a value through the variable and returns a table. Now I want to get a table of several AssignmentId's from the first query.
What do I need? A Join table? I have no idea about what to do now.
AND OW.AssignmentId IN
(
SELECT AS2.AssignmentId
FROM dbo.AssignmentSummary AS AS2
WHERE AS2.SixweekPosition = 1 AND AS2.TeacherId = 'mggarcia'
)
the suggestion can be optimize if you can tell me how are the tables are related with each other.
You can combine them using in:
SELECT S.StudentId,
CASE WHEN OW.OverwrittenScore IS NOT NULL
THEN OW.OverwrittenScore
ELSE dbo.GetFinalScore(S.StudentId, #assignmentId)
END AS FinalScore
FROM dbo.Students AS S
LEFT JOIN dbo.OverwrittenScores AS OW
ON S.StudentId = OW.StudentID
AND OW.AssignmentId in (SELECT AS2.AssignmentId
FROM dbo.AssignmentSummary AS AS2
WHERE AS2.SixweekPosition = 1 AND AS2.TeacherId = 'mggarcia'
)
WHERE S.ClassId IN (
SELECT C.ClassId
FROM Classes AS C
WHERE C.TeacherId = #teacherId
)
There may be ways to simplify this query. This does a direct conversion of substituting the first query into the second.
Use APPLY operator with correlated subquery. Also you can replace CASE expression to function ISNULL.
SELECT S.StudentId,
ISNULL(o.OverwrittenScore, dbo.GetFinalScore(S.StudentId, o.AssignmentId)) AS FinalScore
FROM dbo.Students AS S
OUTER APPLY (
SELECT OW.OverwrittenScore, AS2.AssignmentId
FROM dbo.OverwrittenScores AS OW JOIN dbo.AssignmentSummary AS AS2
ON OW.AssignmentId = AS2.AssignmentId
WHERE AS2.SixweekPosition = 1 AND AS2.TeacherId = 'mggarcia'
AND S.StudentId = OW.StudentID
) o
WHERE S.ClassId IN (
SELECT C.ClassId
FROM Classes AS C
WHERE C.TeacherId = #teacherId
)