(SQL) Query Results on one row - sql-server

So I have two tables, named "Questions" and Answers
I made a INNER JOIN for those two tables
SELECT Questions.ID, Questions.QText, Answers.AText
FROM Questions INNER JOIN Answers
ON Questions.ID=Answers.QuestionID;
And the result looks like this:
However, you can clearly see, that the question is displayed 4 times each time with on of the answers.
Now My question is: Is it possible to have the result in one row, consisting of
[ID] - [Question] - [Answer1] - [Answer2] - [Answer3] - [Answer4]

Use CROSS APPLY for CSV. Don't do it inline, then you need a grouping...
SELECT q.ID, q.QText, Answers = STUFF(x.csv, 1, 1, '')
FROM Questions q
CROSS APPLY
(
SELECT
'-' + a.Atext
FROM
Answers a
WHERE
a.QuestionID = q.ID
FOR XML PATH ('')
) x (csv)

You could use this Query for a Pivot:
SELECT QID, QText, [1], [2], [3], [4]
FROM (SELECT Q.ID AS QID, A.ID AS AID, Q.QText, A.AText FROM Questions AS Q
INNER JOIN Answers AS A ON Q.ID = A.QuestionID) QA
PIVOT
(
MAX(AText)
FOR AID
IN ([1], [2], [3], [4])
) AS PV
BUT: You must use a combined Primary Key for your Answer Table.
With this Pivot Table the answer ID must be 1, 2, 3, 4 every time. Otherwise you don't get your answers.
FOR AID declares, which column is used for this.
Otherwise you could add a column to answers which called "AnswerNr" or something like that. In this column you put 1 to 4 for your answers and change the query to:
SELECT QID, QText, [1], [2], [3], [4]
FROM (SELECT Q.ID AS QID, ->A.AnswerNr<-, Q.QText, A.AText FROM Questions AS Q
INNER JOIN Answers AS A ON Q.ID = A.QuestionID) QA
PIVOT
(
MAX(AText)
FOR ->AnswerNr<-
IN ([1], [2], [3], [4])
) AS PV

To get the Question with all it's answers on single row Use COALESCE:
DECLARE #Answer VARCHAR(8000)
SELECT Questions.ID, Questions.QText, #Answer = COALESCE(#Answer + ', ', '') + AText
FROM Questions INNER JOIN Answers ON Questions.ID=Answers.QuestionID
WHERE AText IS NOT NULL
If you're using SQL Server 2005, you could use the FOR XML PATH command.
SELECT Questions.ID, Questions.QText,
(STUFF((SELECT CAST(', ' + [AText] AS VARCHAR(MAX))
FROM Answers
WHERE Questions.ID = Answers.QuestionID
FOR XML PATH ('')), 1, 2, '')) AS Answers
FROM Questions

Related

SQL Server : incorrect syntax near '('. Expecting ID, QUOTED_ID Error with SQL Pivot [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 2 years ago.
Improve this question
I have used CTE and getting compilation error for last CTE. long time search google but still not understand where I made the mistake in code. so please some one tell me what to change in code to fix the error message
Incorrect syntax near '('. Expecting ID, QUOTED_ID
This CTE is throwing the error and this is last CTE in my code.
,Cte2 AS
(
SELECT *
FROM
(SELECT
EarningID, Section, LineItem, DisplayInCSM, Type,
Broker, ItemValue, Period, hierarchy
FROM
Cte1) t
PIVOT
(MAX(ItemValue)
FOR Broker IN ([5W],[8K],[CL],[DA],[EQ],[FA],[GS],[HM],[HQ],[JY],[KW],[ML],[MS],[MV],[SL],[UA],[WB])
) AS P
)
My full code
DECLARE #Columns as VARCHAR(MAX)
DECLARE #Ticker VARCHAR(20),
#TickerID VARCHAR(20),
#ClientCode VARCHAR(20)
DECLARE #CSM_ID INT
SET #TickerID='ADS'
SET #ClientCode='ADS'
IF OBJECT_ID(N'tempdb..#Brokers') IS NOT NULL
BEGIN
DROP TABLE #Brokers
END
SELECT DISTINCT #Ticker=Ticker FROM tblTickerMasterId WHERE MasterId=#TickerID
SELECT TOP 1 #CSM_ID=CSM_ID FROM tblCSM_Tuner_Client WHERE TickerID=#TickerID
SELECT * Into #Brokers FROM
(
Select A.BrokerCode, B.BrokerName
From tblClientBroker_Earnings A
Join tblBroker B ON SUBSTRING(A.BrokerCode,1,len(A.BrokerCode)-charindex('-',A.BrokerCode))=B.Brokercode
Where A.ClientCode=#ClientCode And A.Ticker=#Ticker
/*AND A.BrokerCode IN (SELECT [DATA] FROM SplitStringToTable(#SelectedBrokers,',') WHERE TRIM([DATA])<>'')*/
) x
SELECT #Columns = COALESCE(#Columns + ', ','') + QUOTENAME(BrokerCode)
FROM
(
SELECT DISTINCT BrokerCode
FROM #Brokers where TRIM(BrokerCode) <> ''
) AS B
ORDER BY B.BrokerCode
;WITH DirectReports as
(
SELECT CSM_ID,
ID,
ParentID,
DisplayInCSM,
Type,
FontName,
FontStyle,
FontSize,
UnderLine,
BGColor,
LineItemID,
Presentation,
BrokerOrientation,
AnnualFormat,
CalculationMethod,
Indent,
FGColor,
Box,
HeadingSubHeading,
ColOrder,
#TickerID AS TickerID,
hierarchy = FORMAT(ID,'0000'),
level = 0
FROM tblCSM_ModelDetails
WHERE ISNULL(ParentID, 0) = 0
AND Type<>'BM'
AND CSM_ID=#CSM_ID
UNION ALL
SELECT e.CSM_ID,
e.ID,
e.ParentID,
e.DisplayInCSM,
e.Type,
e.FontName,
e.FontStyle,
e.FontSize,
e.UnderLine,
e.BGColor,
e.LineItemID,
e.Presentation,
e.BrokerOrientation,
e.AnnualFormat,
e.CalculationMethod,
e.Indent,
e.FGColor,
e.Box,
e.HeadingSubHeading,
e.ColOrder,
#TickerID AS TickerID,
hierarchy = d.hierarchy + '.' + FORMAT(e.id,'0000'),
level = level + 1
FROM tblCSM_ModelDetails e
JOIN DirectReports d on e.ParentID = d.ID
WHERE e.Type<>'BM'
AND e.CSM_ID=#CSM_ID
)
,Cte1 as
(
SELECT AA.EarningID,AA.Section,AA.LineItem,AA.Ticker, r.DisplayInCSM, r.Type,r.hierarchy, AA.Broker, AA.ItemValue, AA.Period,r.ColOrder
FROM DirectReports r
LEFT OUTER JOIN
(
Select b.*,L.ID AS LineItemID,L.TickerID
From tblOutputDetl_CSMTuner b
INNER JOIN TblLineItemTemplate L
ON b.LineItem= L.LineItem
WHERE b.Ticker=#Ticker AND L.TickerID=#TickerID
) AA
ON (AA.LineItemID=r.LineItemID
)
,Cte2 as
(
SELECT *
FROM
(
SELECT EarningID,Section,LineItem, DisplayInCSM, Type, Broker, ItemValue, Period,hierarchy
from Cte1
) t
PIVOT
(
MAX(ItemValue)
FOR Broker IN ([5W],[8K],[CL],[DA],[EQ],[FA],[GS],[HM],[HQ],[JY],[KW],[ML],[MS],[MV],[SL],[UA],[WB])
) AS P
)
SELECT * FROM Cte2 Order BY hierarchy
IF OBJECT_ID(N'tempdb..#Brokers') IS NOT NULL
BEGIN
DROP TABLE #Brokers
END
You're missing a closing parenthesis here
ON (AA.LineItemID=r.LineItemID

SQL Server : UNION, Columns with Data, Drop the Columns Without

I have two tables, LYEAR and CYEAR:
[SKU],[Title],[1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12]
Columns [SKU],[Title],[1],[2],[3],[4],[5],[6],[7],[8] are populated with information from the CYEAR table and [SKU],[Title],[9],[10],[11],[12] from the LYEAR table.
How would I merge the two tables, so that there are columns with NULL values are dropped, leaving me with one row per SKU?
I have got this far:
WITH LYEAR_ORG ([SKU],[Title],[QTY],[DATE]) AS
(
SELECT
T1.ItemNumber, T1.ItemTitle, (SUM(T2.nqty)) AS [UNITS],
CONVERT(VARCHAR(2), (MONTH(T3.dProcessedOn)))
FROM
StockItem T1
LEFT OUTER JOIN
OrderItem T2 ON T1.pkstockItemId = T2.fkStockItemID_processed
LEFT JOIN
[Order] T3 ON T3.pkOrderID = T2.fkOrderID
WHERE
(YEAR(T3.dProcessedOn)) = (YEAR(getdate())-1)
AND (MONTH(T3.dProcessedOn)) > (MONTH(getdate())-1)
GROUP BY
T1.ItemNumber, T1.ItemTitle,
CONVERT(VARCHAR(2), (MONTH(T3.dProcessedOn)))
),
CYEAR_ORG ([SKU],[Title],[QTY],[DATE]) AS
(
SELECT T1.ItemNumber, T1.ItemTitle, (SUM(T2.nqty)) AS [UNITS], CONVERT(varchar(2),(MONTH(T3.dProcessedOn)))
FROM StockItem T1
LEFT OUTER JOIN OrderItem T2 ON T1.pkstockItemId = T2.fkStockItemID_processed
LEFT JOIN [Order] T3 ON T3.pkOrderID = T2.fkOrderID
WHERE (YEAR(T3.dProcessedOn)) = (YEAR(getdate())-1)
AND (MONTH(T3.dProcessedOn)) < (MONTH(getdate()))
GROUP BY T1.ItemNumber, T1.ItemTitle, CONVERT(varchar(2),(MONTH(T3.dProcessedOn)))
),
LYEAR ([SKU],[Title],[1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12]) AS (
SELECT *
FROM LYEAR_ORG
PIVOT ( MAX(QTY) FOR DATE in ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12])) as LYEAR_ORDERS
),
CYEAR ([SKU],[Title],[1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12]) AS (
SELECT *
FROM CYEAR_ORG
PIVOT ( MAX(QTY) FOR DATE in ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12])) as CYEAR_ORDERS
)
SELECT * FROM LYEAR
UNION ALL
SELECT * FROM CYEAR
I am unable to use INSERT INTO as this is a limitation on the Linnworks platform I am working on, it is SQL Server.
On the assumption that LYEAR columns 1-8 are all NULL, and so are CYEAR 9-12, a JOIN with a ton of COALESCEs, rather than a UNION will get you where you want to be. If, though, there are values for both years in any columns, this will go sideways.
SELECT
l.[SKU]
,l.[Title]
,COALESCE(l.[1], c.[1]) AS [1]
,COALESCE(l.[2], c.[2]) AS [2]
,COALESCE(l.[3], c.[3]) AS [3]
,COALESCE(l.[4], c.[4]) AS [4]
,COALESCE(l.[5], c.[5]) AS [5]
,COALESCE(l.[6], c.[6]) AS [6]
,COALESCE(l.[7], c.[7]) AS [7]
,COALESCE(l.[8], c.[8]) AS [8]
,COALESCE(l.[9], c.[9]) AS [9]
,COALESCE(l.[10], c.[10]) AS [10]
,COALESCE(l.[11], c.[11]) AS [11]
,COALESCE(l.[12], c.[12]) AS [12]
FROM
LYEAR AS l
JOIN
CYEAR AS c
ON
c.SKU = l.SKU
AND c.Title = l.Title;
Here's a solution that will allow for there to be data in both LYEAR and CYEAR, and to switch from one to the other based on the month of the year:
SELECT SKU,
Title,
CASE WHEN DATEPART(MM, GETDATE()) > 1
THEN LYEAR.1
ELSE CYEAR.1
END,
CASE WHEN DATEPART(MM, GETDATE()) > 2
THEN LYEAR.2
ELSE CYEAR.2
END,
CASE WHEN DATEPART(MM, GETDATE()) > 3
THEN LYEAR.3
ELSE CYEAR.3
END,
CASE WHEN DATEPART(MM, GETDATE()) > 4
THEN LYEAR.4
ELSE CYEAR.4
END
--Add rest of CASE statements for remaining months
FROM LYEAR AS L
JOIN CYEAR AS C
ON L.SKU = C.SKU
AND L.Title = C.Title

Unable concate NULL value in SQL using CONCAT, COALESCE and ISNULL

I have a query with multiple joins where I want to combine records from two columns into one. If one column is empty then I want to show one column value as result. I tried with CONCAT, COALEASE and ISNULL but no luck. What am I missing here?
My objective is, create one column which has combination of s.Script AS Original and FromAnotherTable from query. Below query runs but throws Invalid column name 'Original' and Invalid column name 'FromAnotherTable'. when I try to use CONCAT, COALEASE or ISNULL .
SQL Query:
SELECT DISTINCT
c.Name AS CallCenter,
LTRIM(RTRIM(s.Name)) Name,
d.DNIS,
s.ScriptId,
s.Script AS Original,
(
SELECT TOP 5 CCSL.Line+'; '
FROM CallCenterScriptLine CCSL
WHERE CCSL.ScriptId = s.ScriptId
ORDER BY ScriptLineId FOR XML PATH('')
) AS FromAnotherTable,
--CONCAT(s.Script, SELECT TOP 5 CCSL.Line+'; ' FROM dbo.CallCenterScriptLine ccsl WHERE ccsl.ScriptId = s.ScriptId ORDER BY ccsl.ScriptLineId xml path(''))
--CONCAT(Original, FromAnotherTable) AS Option1,
--COALESCE(Original, '') + FromAnotherTable AS Option2,
--ISNULL(Original, '') + FromAnotherTable AS Option3,,
r.UnitName AS Store,
r.UnitNumber
FROM CallCenterScript s WITH (NOLOCK)
INNER JOIN CallCenterDNIS d WITH (NOLOCK) ON d.ScriptId = s.ScriptId
INNER JOIN CallCenter c WITH (NOLOCK) ON c.Id = s.CallCenterId
INNER JOIN CallCenterDNISRestaurant ccd WITH (NOLOCK) ON ccd.CallCenterDNISId = d.CallCenterDNISId
INNER JOIN dbo.Restaurant r WITH (NOLOCK) ON r.RestaurantID = ccd.CallCenterRestaurantId
WHERE c.Id = 5
AND (1 = 1)
AND (s.IsDeleted = 0 OR s.IsDeleted IS NULL)
ORDER BY DNIS ASC;
Output:
This works:
DECLARE #Column1 VARCHAR(50) = 'Foo',
#Column2 VARCHAR(50) = NULL;
SELECT CONCAT(#Column1,#Column2);
SELECT COALESCE(#Column2, '') + #Column1
SELECT ISNULL(#Column2, '') + #Column1
So I am not sure what I am missing in my original query.
Look at row 3 in the results you are getting. In your concatenated columns (Option1, 2, 3) you are getting the first script column twice. Not the first one + the second one like you expect.
The reason is because you've aliased your subquery "script" which is the same name as another column in your query, which makes it ambiguous.
Change the alias of the subquery and the problem should go away. I'm frankly surprised your query didn't raise an error.
EDIT: You can't use a column alias in another column's definition in the same level of the query. In other words, you can't do this:
SELECT
SomeColumn AS A
, (Subquery that returns a column) AS B
, A + B --this is not allowed
FROM ...
You can either create a CTE that returns the aliased columns and then concatenate them in the main query that selects from the CTE, or you have to use the original sources of the aliases, like so:
SELECT
SomeColumn AS A
, (Subquery that returns a column) AS B
, SomeColumn + (Subquery that returns a column) --this is fine
FROM ...
I took another approach where instead on creating separate column, I used ISNULL in my subQuery which returns my desired result.
Query:
SELECT DISTINCT
c.Name AS CallCenter,
LTRIM(RTRIM(s.Name)) Name,
d.DNIS,
s.ScriptId,
s.Script AS Original,
(
SELECT TOP 5 ISNULL(CCSL.Line, '')+'; ' + ISNULL(s.Script, '')
FROM CallCenterScriptLine CCSL
WHERE CCSL.ScriptId = s.ScriptId
ORDER BY ScriptLineId FOR XML PATH('')
) AS FromAnotherTable,
r.UnitName AS Store,
r.UnitNumber
FROM CallCenterScript s WITH (NOLOCK)
INNER JOIN CallCenterDNIS d WITH (NOLOCK) ON d.ScriptId = s.ScriptId
INNER JOIN CallCenter c WITH (NOLOCK) ON c.Id = s.CallCenterId
INNER JOIN CallCenterDNISRestaurant ccd WITH (NOLOCK) ON ccd.CallCenterDNISId = d.CallCenterDNISId
INNER JOIN dbo.Restaurant r WITH (NOLOCK) ON r.RestaurantID = ccd.CallCenterRestaurantId
WHERE c.Id = 5
AND (1 = 1)
AND (s.IsDeleted = 0 OR s.IsDeleted IS NULL)
ORDER BY DNIS ASC;
Here's a simplified example using table variables.
Instead of using a subquery for a field, it uses a CROSS APPLY.
And CONCAT in combination with STUFF is used to glue the strings together.
declare #Foo table (fooID int identity(1,1) primary key, Script varchar(30));
declare #Bar table (barID int identity(1,1) primary key, fooID int, Line varchar(30));
insert into #Foo (Script) values
('Test1'),('Test2'),(NULL);
insert into #Bar (fooID, Line) values
(1,'X'),(1,'Y'),(2,NULL),(3,'X'),(3,'Y');
select
f.fooID,
f.Script,
x.Lines,
CONCAT(Script+'; ', STUFF(x.Lines,1,2,'')) as NewScript
from #Foo f
cross apply (
select '; '+b.Line
from #Bar b
where b.fooID = f.fooID
FOR XML PATH('')
) x(Lines)
Result:
fooID Script Lines NewScript
----- ------- ------- -----------
1 Test1 ; X; Y Test1; X; Y
2 Test2 NULL Test2;
3 NULL ; X; Y X; Y

Create View - Declare a variable

I am creating a view that is using that STUFF function. I want to put the result of STUFF in a variable for my view. The problem I am having is declaring my variable. It gives me the message "Incorrect Syntax near 'DECLARE'. Expecting '(' or SELECT." I already have the '(' in there. I have tried putting a BEGIN before it. I have tried putting it after the SELECT word. But nothing seems to work and I cannot find a solution in my search. I am using SQL Server 2012
CREATE VIEW [AQB_OB].[GISREQUESTEDBURNS]
AS
(DECLARE #CONDITIONS AS varchar(20)
SET #CONDITIONS = (SELECT DISTINCT BD.[RequestedBurnsID]
,[ConditionsReasonsID] = STUFF((SELECT ', ' + CONVERT(VARCHAR (20),[ConditionsReasonsID]) FROM [AQB_OB].[BurnDecisions] WHERE [RequestedBurnsID]= BD.[RequestedBurnsID] ORDER BY [RequestedBurnsID] ASC
FOR XML PATH ('')) , 1 , 1, '') FROM
[AQB_OB].[BurnDecisions] BD)
SELECT RB.[RequestedBurnsID] AS REQUESTEDBURNID
,BUY.[BurnYear] AS BURNYEAR
,CY.[CurrentYear] AS CURRENTYEAR
,RB.[BurnSitesID] AS BURNSITESID
,[BurnerID] AS BURNERID
,[Contact] AS CONTACT
,[BurnDecision] AS BURNDECISION
,RB.[Comment] AS COMMENT
,#CONDITIONS AS CONDITIONS
FROM [AQB_MON].[AQB_OB].[RequestedBurns] RB
LEFT join AQB_MON.[AQB_OB].[PileDryness] PD on RB.[PileDrynessID] = PD.[PileDrynessID]
inner join AQB_MON.[AQB_OB].[BurnYear] BUY on BUY.BurnYearID = BP.BurnYearID
inner join AQB_MON.[AQB_OB].[CurrentYear] CY on CY.CurrentYearID = BUY.CurrentYearID
GO
You can't declare variables in a view. Could you make it into a function or stored procedure?
Edit - you might also be able to put something into a CTE (Common Table Expression) and keep it as a view.
e.g.
WITH conditions as
(
... do the STUFF here
)
SELECT blah
FROM blah
INNER JOIN conditions
(or CROSS JOIN conditions if its just one row, I can't quite decipher what your data is like)
Here is a sample query that uses a CTE (Common Table Expression) to nicely emulate internal variable construction, as described by James Casey. You can test-run it in your version of SQL Server.
CREATE VIEW vwImportant_Users AS
WITH params AS (
SELECT
varType='%Admin%',
varMinStatus=1)
SELECT status, name
FROM sys.sysusers, params
WHERE status > varMinStatus OR name LIKE varType
SELECT * FROM vwImportant_Users
yielding output:
status name
12 dbo
0 db_accessadmin
0 db_securityadmin
0 db_ddladmin
also via JOIN
WITH params AS ( SELECT varType='%Admin%', varMinStatus=1)
SELECT status, name
FROM sys.sysusers INNER JOIN params ON 1=1
WHERE status > varMinStatus OR name LIKE varType
also via CROSS APPLY
WITH params AS ( SELECT varType='%Admin%', varMinStatus=1)
SELECT status, name
FROM sys.sysusers CROSS APPLY params
WHERE status > varMinStatus OR name LIKE varType
Or use a CTE (common table expression) as subselect like:
WITH CTE_Time(Clock)
AS(
SELECT 11 AS [Clock] -- set var
)
SELECT
DATEPART(HOUR, GETDATE()) AS 'actual hour',
CASE
WHEN DATEPART(HOUR, GETDATE()) >= (SELECT [Clock] FROM CTE_Time) THEN 'after'
ELSE 'before'
END AS [Data]
Try put the condition subquery directly inside the the view select statement. you may CAST the XML to VARCHAR(20).
CREATE VIEW [AQB_OB].[GISREQUESTEDBURNS]
AS
SELECT RB.[RequestedBurnsID] AS REQUESTEDBURNID
,BUY.[BurnYear] AS BURNYEAR
,CY.[CurrentYear] AS CURRENTYEAR
,RB.[BurnSitesID] AS BURNSITESID
,[BurnerID] AS BURNERID
,[Contact] AS CONTACT
,[BurnDecision] AS BURNDECISION
,RB.[Comment] AS COMMENT,
(
SELECT DISTINCT BD.[RequestedBurnsID],
[ConditionsReasonsID] = STUFF((SELECT ', ' + CONVERT(VARCHAR (20), [ConditionsReasonsID]) FROM [AQB_OB].[BurnDecisions]
WHERE [RequestedBurnsID]= BD.[RequestedBurnsID] ORDER BY [RequestedBurnsID] ASC
FOR XML PATH ('')) , 1 , 1, '') FROM
[AQB_OB].[BurnDecisions] BD
) AS CONDITIONS
FROM [AQB_MON].[AQB_OB].[RequestedBurns] RB
LEFT join AQB_MON.[AQB_OB].[PileDryness] PD on RB.[PileDrynessID] = PD.[PileDrynessID]
inner join AQB_MON.[AQB_OB].[BurnYear] BUY on BUY.BurnYearID = BP.BurnYearID
inner join AQB_MON.[AQB_OB].[CurrentYear] CY on CY.CurrentYearID = BUY.CurrentYearID

Join the table valued function in the query

I have one table vwuser. I want join this table with the table valued function fnuserrank(userID). So I need to cross apply with table valued function:
SELECT *
FROM vwuser AS a
CROSS APPLY fnuserrank(a.userid)
For each userID it generates multiple records. I only want the last record for each empid that does not have a Rank of Term(inated). How can I do this?
Data:
HistoryID empid Rank MonitorDate
1 A1 E1 2012-8-9
2 A1 E2 2012-9-12
3 A1 Term 2012-10-13
4 A2 E3 2011-10-09
5 A2 TERM 2012-11-9
From this 2nd record and 4th record must be selected.
In SQL Server 2005+ you can use this Common Table Expression (CTE) to determine the latest record by MonitorDate that doesn't have a Rank of 'Term':
WITH EmployeeData AS
(
SELECT *
, ROW_NUMBER() OVER (PARTITION BY empId, ORDER BY MonitorDate DESC) AS RowNumber
FROM vwuser AS a
CROSS APPLY fnuserrank(a.userid)
WHERE Rank != 'Term'
)
SELECT *
FROM EmployeeData AS ed
WHERE ed.RowNumber = 1;
Note: The statement before this CTE will need to end in a semi-colon. Because of this, I have seen many people write them like ;WITH EmployeeData AS...
You'll have to play with this. Having trouble mocking your schema on sqlfiddle.
Select bar.*
from
(
SELECT *
FROM vwuser AS a
CROSS APPLY fnuserrank(a.userid)
where rank != 'TERM'
) foo
left join
(
SELECT *
FROM vwuser AS b
CROSS APPLY fnuserrank(b.userid)
where rank != 'TERM'
) bar
on foo.empId = bar.empId
and foo.MonitorDate > bar.MonitorDate
where bar.empid is null
I always need to test out left outers on dates being higher. The way it works is you do a left outer. Every row EXCEPT one per user has row(s) with a higher monitor date. That one row is the one you want. I usually use an example from my code, but i'm on the wrong laptop. to get it working you can select foo., bar. and look at the results and spot the row you want and make the condition correct.
You could also do this, which is easier to remember
SELECT *
FROM vwuser AS a
CROSS APPLY fnuserrank(a.userid)
) foo
join
(
select empid, max(monitordate) maxdate
FROM vwuser AS b
CROSS APPLY fnuserrank(b.userid)
where rank != 'TERM'
) bar
on foo.empid = bar.empid
and foo.monitordate = bar.maxdate
I usually prefer to use set based logic over aggregate functions, but whatever works. You can tweak it also by caching the results of your TVF join into a table variable.
EDIT:
http://www.sqlfiddle.com/#!3/613e4/17 - I mocked up your TVF here. Apparently sqlfiddle didn't like "go".
select foo.*, bar.*
from
(
SELECT f.*
FROM vwuser AS a
join fnuserrank f
on a.empid = f.empid
where rank != 'TERM'
) foo
left join
(
SELECT f1.empid [barempid], f1.monitordate [barmonitordate]
FROM vwuser AS b
join fnuserrank f1
on b.empid = f1.empid
where rank != 'TERM'
) bar
on foo.empId = bar.barempid
and foo.MonitorDate > bar.barmonitordate
where bar.barempid is null

Resources