Related
I have a situation where an order can contain multiple license purchases - and if the order does contain multiple licenses, I want to display the license descriptions in a single cell with the values separated by commas. If we were on SQL 2017, I could use STRING_AGG but we are on SQL 2016 so I am trying the tried and true STUFF / FOR XML Path method.
From the screenshot below, Customer 4341073 had two license purchases on Order ID 18519173:
When I add the STUFF / FOR XML Path to the T-SQL, I am not able to achieve the desired result of showing the license description in the same record - each license still has it's own row.
SELECT x.CustomerID ,
x.ATOLicenseTypeID ,
x.ATOLicense ,
x.AuthorizationBeginDate ,
x.AuthorizationEndDate ,
x.OrderID ,
x.OrderDate ,
STUFF ( (
SELECT ',' + lt.description
FROM dbo.LicenseTypes AS lt
--INNER JOIN #XMLPATH ON lt.id = x.OrderLicenseTypeID
WHERE lt.id = x.OrderLicenseTypeID
--GROUP BY ',' + lt.description
FOR XML PATH ( '' )
) , 1 , 1 , '' ) AS Licenses
FROM #XMLPATH AS x
--GROUP BY x.CustomerID ,
-- x.ATOLicenseTypeID ,
-- x.ATOLicense ,
-- x.AuthorizationBeginDate ,
-- x.AuthorizationEndDate ,
-- x.OrderID ,
-- x.OrderDate ,
-- x.OrderLicenseTypeID;
I've tried different ways to join the sub-query to the outer query and added and removed GROUP BY to achieve the desired result but nothing is working for me.
Any suggestions on where I am going wrong with this query?
Sample dataset:
DROP TABLE IF EXISTS #XMLPATH;
CREATE TABLE #XMLPATH
(
CustomerID INT ,
ATOLicenseTypeID INT ,
ATOLicense VARCHAR (500) ,
AuthorizationBeginDate DATE ,
AuthorizationEndDate DATE ,
OrderID INT ,
OrderDate DATETIME ,
OrderLicenseTypeID INT
);
INSERT INTO #XMLPATH
VALUES ( 4341073, 52, 'Temporary Resident Fishing', N'2019-01-07T00:00:00', N'2019-01-07T00:00:00', 18519136, N'2019-01-07T12:01:55.317', 2141 ) ,
( 4341073, 52, 'Temporary Resident Fishing', N'2019-01-07T00:00:00', N'2019-01-07T00:00:00', 18519173, N'2019-01-07T12:34:13.107', 204 ) ,
( 4341073, 52, 'Temporary Resident Fishing', N'2019-01-07T00:00:00', N'2019-01-07T00:00:00', 18519173, N'2019-01-07T12:34:13.107', 2141 );
SELECT * FROM #XMLPATH;
SELECT x.CustomerID ,
x.ATOLicenseTypeID ,
x.ATOLicense ,
x.AuthorizationBeginDate ,
x.AuthorizationEndDate ,
x.OrderID ,
x.OrderDate ,
STUFF ( (
SELECT ',' + lt.description
FROM dbo.LicenseTypes AS lt
--INNER JOIN #XMLPATH ON lt.id = x.OrderLicenseTypeID
WHERE lt.id = x.OrderLicenseTypeID
--GROUP BY ',' + lt.description
FOR XML PATH ( '' )
) , 1 , 1 , '' ) AS Licenses
FROM #XMLPATH AS x
GROUP BY x.CustomerID ,
x.ATOLicenseTypeID ,
x.ATOLicense ,
x.AuthorizationBeginDate ,
x.AuthorizationEndDate ,
x.OrderID ,
x.OrderDate ,
x.OrderLicenseTypeID;
In order to get all rows of one OrderID as one result-row, you must not include the separating information (the OrderLicenseTypeID) into the GROUP BY. But then you have the issue you've encountered: You cannot use this ID within your FOR XML construct.
The trick is (as your out-commented trials show), to add the source table to the sub-select and filter there with a grouped column. But you have to use different aliases to deal with them as two different sets. Try this:
(I had to add one more temp table to test this...)
SELECT x.CustomerID ,
x.ATOLicenseTypeID ,
x.ATOLicense ,
x.AuthorizationBeginDate ,
x.AuthorizationEndDate ,
x.OrderID ,
x.OrderDate ,
STUFF ( (
SELECT ',' + lt.description
FROM #XMLPATH x2
INNER JOIN #LicenseTypes AS lt ON lt.id=x2.OrderLicenseTypeID
WHERE x2.OrderID = x.OrderID --you might need to add more columns here....
--in most cases we want to add an ORDER BY
FOR XML PATH ( '' )
) , 1 , 1 , '' ) AS Licenses
FROM #XMLPATH AS x
GROUP BY x.CustomerID ,
x.ATOLicenseTypeID ,
x.ATOLicense ,
x.AuthorizationBeginDate ,
x.AuthorizationEndDate ,
x.OrderID ,
x.OrderDate;
Btw: Starting with v2017 there is STRING_AGG(), which makes this much easier...
I have a table with name "PrintWord" and column name as col_letter and data in it is as follows:
"col_letter"
S
A
C
H
I
N
I would like to print the o/p from this table as:
SACHIN
Thanks!
DECLARE #t table
(
Name varchar(10)
)
INSERT INTO #t
SELECT 's' UNION ALL
SELECT 'a' UNION ALL
SELECT 'c' UNION ALL
SELECT 'h' UNION ALL
SELECT 'i' UNION ALL
SELECT 'n'
SELECT DISTINCT
stuff(
(
SELECT ' '+ [Name] FROM #t FOR XML PATH('')
),1,1,'')
FROM (SELECT DISTINCT Name FROM #t ) t
There is a hard-coded version :
SELECT col_letter
FROM PrintWord
ORDER BY
CASE col_letter
WHEN 'S' THEN 1
WHEN 'A' THEN 2
WHEN 'C' THEN 3
WHEN 'H' THEN 4
WHEN 'I' THEN 5
WHEN 'N' THEN 6
END
FOR XML PATH('')
You need an ORDER BY clause to guarantee the order of the letters.
I am having some trouble . I have been writing a SQL query that fetches 5 columns from 2 tables. In a simple join, the column named CustomerCode is displayed correctly, but in the below query, it is displayed NULL. In fact, I want to select from the two tables with a left join.
This is my query:
select fff.*,CustomerCode,SUBSTRING(( SELECT DISTINCT
RIGHT('0000'
+ LTRIM(RTRIM(CustomerCode)),
4)
+ '-'
FROM TatEstelam.dbo.CustomerInfo
WHERE ltrim(rtrim(CodeMelli)) <> '' and CodeMelli <> '0000000000' AND CODEMELLI <> '0' AND Nationalcode = fff.CodeMelli
FOR
XML PATH('')
), 0,
LEN(( SELECT DISTINCT
RIGHT('0000'
+ LTRIM(RTRIM(CustomerCode)),
4)
+ '-'
FROM TatEstelam.dbo.CustomerInfo
WHERE ltrim(rtrim(CodeMelli)) <> '' and CodeMelli <> '0000000000' AND CODEMELLI <> '0' AND Nationalcode = fff.CodeMelli
FOR
XML PATH('')
)))
AS customerNumber from ( SELECT NameOutput AS Fullname ,
shobehNew AS BRANCHNO ,
ShenaseMelli AS Nationalcode ,
[CodeMelli],
CreateDate AS RegisterDate ,
N'ساها حقوقی' as type
FROM TatEstelam.dbo.tblCodeMRequest_0 where CreateDate BETWEEN '920101' AND '930501' and CusType = 6) as fff
LEFT JOIN (select DISTINCT Nationalcode,customercode,NationalID from TatEstelam.dbo.CustomerInfo where InqueryType <> '01' ) ci ON fff.Nationalcode = ci.NationalID and ltrim(rtrim(CodeMelli)) <> '' and CodeMelli <> '0000000000' AND CODEMELLI <> '0'
ORDER BY CODEmELLI
but in this query customer code will display :
select * from TatEstelam.dbo.CustomerInfo c right join TatEstelam.dbo.tblCodeMRequest_0 m
on c.Nationalcode = m.ShenaseMelli
I have a three tables in SQL Server 2008 which are setup as follows:
EMPLOYEE TABLE
empid(PK)
1
2
joined to EMPLOYEEATTRIBUTES
dataId(PK) | empId(FK) | attributeid | attributeVal
10 | 1 | A1 | somevalue1
20 | 1 | A2 | somevalue2
30 | 2 | A1 | somevalue3
40 | 2 | A3 | somevalue4
joined to ATTRIBUTES
attributeid | attributeName
A1 | attribute1
A2 | attribute2
A3 | attribute3
I need to get the xml data out into the following format
<rows>
<row empid="1">
<attribute1>somevalue1</attribute1>
<attribute2>somevalue2</attribute1>
</row>
<row empid="2">
<attribute1>somevalue3</attribute1>
<attribute3>somevalue4</attribute1>
</row>
</rows>
Anyone know how this can be done??
If you want to skip all of the gory details and just see an answer, look at the SQL query at the bottom of this posting.
The main challenge here is that the various SQL Server FOR XML options cannot generate the dynamic element names stipulated in the desired output. Therefore, my first answer is to consider simply returning a conventional SQL result set and having the client generate the XML. It is a very simple streaming transformation. However, this might not be an option for you, so we continue on the path of having SQL Server generate the XML.
My second thought was to use SQL Server's built-in XQuery functionality to perform the transformation, thus:
/* WARNING: the following SQL does not work */
SELECT
CAST((SELECT * FROM data FOR XML RAW) AS XML)
.query('
<rows>
{
for $empId in distinct-values(/row/#empId)
return
<row empid="{$empId}">
{
for $attr in /row[#empId = $empId]
return
attribute { "attribute" } { $attr/#attributeValue }
}
</row>
}
</rows>
')
Alas, this does not work. SQL Server complains:
Msg 9315, Level 16, State 1, Line 25
XQuery [query()]: Only constant expressions are supported for the name expression
of computed element and attribute constructors.
Apparently, the XQuery implementation suffers from the same limitation as the FOR XML features. So, my second answer is to suggest generating the XML on the client side :) But if you insist on generating the XML from SQL, then fasten your seatbelts...
The overall strategy is going to be to abandon SQL Server's native facilities for SQL generation. Instead, we are going to build up the XML document using string concatenation. If this approach is offensive, you can stop reading now :)
Let's start with generating a sample dataset to play with:
SELECT NULL AS empId INTO employee WHERE 1=0
UNION SELECT 1
UNION SELECT 2
SELECT NULL AS dataId, NULL AS empId, NULL AS attributeId, NULL AS attributeVal INTO employeeAttributes WHERE 1=0
UNION SELECT 10, 1, 'A1', 'someValue1'
UNION SELECT 20, 1, 'A2', 'someValue2'
UNION SELECT 30, 2, 'A1', 'someValue3'
UNION SELECT 40, 2, 'A3', 'someValue4 & <>!'
SELECT NULL AS attributeId, NULL AS attributeName INTO attributes WHERE 1=0
UNION SELECT 'A1', 'attribute1'
UNION SELECT 'A2', 'attribute2'
UNION SELECT 'A3', 'attribute3'
Note that I have changed the value of the last attribute in the provided example to include some XML-unfriendly characters.
Now, put together a basic SQL query to perform the necessary joins:
SELECT
e.empId
, a.attributeName
, ea.attributeVal
FROM employee AS e
INNER JOIN employeeAttributes AS ea
ON ea.empId = e.empId
INNER JOIN attributes AS a
ON a.attributeId = ea.attributeId
which gives this result:
empId attributeName attributeVal
1 attribute1 someValue1
1 attribute2 someValue2
2 attribute1 someValue3
2 attribute3 someValue4 & <>!
Those funny characters in the last attribute are going to give us trouble. Let's change the query to escape them.
; WITH
cruftyData AS (
SELECT
e.empId
, a.attributeName
, (SELECT ea.attributeVal AS x FOR XML RAW) AS attributeValXml
FROM employee AS e
INNER JOIN employeeAttributes AS ea
ON ea.empId = e.empId
INNER JOIN attributes AS a
ON a.attributeId = ea.attributeId
)
, data AS (
SELECT
empId
, attributeName
, SUBSTRING(attributeValXml, 9, LEN(attributeValXml)-11) AS attributeVal
FROM cruftyData
)
SELECT * FROM data
with results:
empId attributeName attributeValXml
1 attribute1 someValue1
1 attribute2 someValue2
2 attribute1 someValue3
2 attribute3 someValue4 & <>!
This ensures that attribute values can now be safely used in an XML document. What about attribute names? The rules for XML attribute names are more strict than those for element content. We will assume that the attributes names are valid XML identifiers. If this is not true, then some scheme will need to be devised to convert the names in the database to valid XML names. This is left as an exercise to the reader :)
The next challenge is to ensure that the attributes are grouped together for each employee, and we can tell when we are at the first or last value in a group. Here is the updated query:
; WITH
cruftyData AS (
SELECT
e.empId
, a.attributeName
, (SELECT ea.attributeVal AS x FOR XML RAW) AS attributeValXml
FROM employee AS e
INNER JOIN employeeAttributes AS ea
ON ea.empId = e.empId
INNER JOIN attributes AS a
ON a.attributeId = ea.attributeId
)
, data AS (
SELECT
empId
, attributeName
, SUBSTRING(attributeValXml, 9, LEN(attributeValXml)-11) AS attributeVal
, ROW_NUMBER() OVER (PARTITION BY empId ORDER BY attributeName DESC) AS down
, ROW_NUMBER() OVER (PARTITION BY empId ORDER BY attributeName) AS up
FROM cruftyData
)
SELECT * FROM data ORDER BY 1, 2
The only change is to add the down and up columns to the result set:
empId attributeName attributeVal down up
1 attribute1 someValue1 2 1
1 attribute2 someValue2 1 2
2 attribute1 someValue3 2 1
2 attribute3 someValue4 & <>! 1 2
We can now identify the first attribute for an employee because up will be 1. The last attribute can be identified in similar fashion using the down column.
Armed with all of this, we are now equipped to perform the nasty business of building up the XML result using string concatenation.
; WITH
cruftyData AS (
SELECT
e.empId
, a.attributeName
, (SELECT ea.attributeVal AS x FOR XML RAW) AS attributeValXml
FROM employee AS e
INNER JOIN employeeAttributes AS ea
ON ea.empId = e.empId
INNER JOIN attributes AS a
ON a.attributeId = ea.attributeId
)
, data AS (
SELECT
empId
, attributeName
, SUBSTRING(attributeValXml, 9, LEN(attributeValXml)-11) AS attributeVal
, ROW_NUMBER() OVER (PARTITION BY empId ORDER BY attributeName DESC) AS down
, ROW_NUMBER() OVER (PARTITION BY empId ORDER BY attributeName) AS up
FROM cruftyData
)
, xmlData AS (
SELECT
empId
, up
, CASE WHEN up <> 1 THEN '' ELSE '<row id="' + CAST (empId AS NVARCHAR) + '">' END AS xml1
, '<' + attributeName + '>' + attributeVal + '</' + attributeName + '>' AS xml2
, CASE WHEN down <> 1 THEN '' ELSE '</row>' END AS xml3
FROM data
)
SELECT xml1, xml2, xml3
--SELECT #result = #result + 'wombat' + xmlString
FROM xmlData
ORDER BY empId, up
with the result:
xml1 xml2 xml3
<row id="1"> <attribute1>someValue1</attribute1>
<attribute2>someValue2</attribute2> </row>
<row id="2"> <attribute1>someValue3</attribute1>
<attribute3>someValue4 & <>!</attribute3> </row>
All that remains is to concatenate all of the rows together, and to add the root rows tags. Since T-SQL does not (yet) have a string concatenation aggregate function, we will resort to using a variable as an accumulator. Here is the final query, in all its hacky glory:
DECLARE #result AS NVARCHAR(MAX)
SELECT #result = '<rows>'
; WITH
cruftyData AS (
SELECT
e.empId
, a.attributeName
, (SELECT ea.attributeVal AS x FOR XML RAW) AS attributeValXml
FROM employee AS e
INNER JOIN employeeAttributes AS ea
ON ea.empId = e.empId
INNER JOIN attributes AS a
ON a.attributeId = ea.attributeId
)
, data AS (
SELECT
empId
, attributeName
, SUBSTRING(attributeValXml, 9, LEN(attributeValXml)-11) AS attributeVal
, ROW_NUMBER() OVER (PARTITION BY empId ORDER BY attributeName DESC) AS down
, ROW_NUMBER() OVER (PARTITION BY empId ORDER BY attributeName) AS up
FROM cruftyData
)
, xmlData AS (
SELECT
empId
, up
, CASE WHEN up <> 1 THEN '' ELSE '<row id="' + CAST (empId AS NVARCHAR) + '">' END AS xml1
, '<' + attributeName + '>' + attributeVal + '</' + attributeName + '>' AS xml2
, CASE WHEN down <> 1 THEN '' ELSE '</row>' END AS xml3
FROM data
)
SELECT #result = #result + xml1 + xml2 + xml3
FROM xmlData
ORDER BY empId, up
SELECT #result = #result + '</rows>'
SELECT #result
The XML ends up in the #result variable. You can check that it is well-formed XML using:
SELECT CAST(#result AS XML)
The final XML looks like this:
<rows><row id="1"><attribute1>someValue1</attribute1><attribute2>someValue2</attribute2></row><row id="2"><attribute1>someValue3</attribute1><attribute3>someValue4 & <>!</attribute3></row></rows>
You can get close - but you can't get your desired output 100%.
Using this query:
SELECT
EmpID AS '#empid',
(
SELECT
a.AttributeName AS '#name',
ea.AttributeVal
FROM dbo.EmployeeAttributes ea
INNER JOIN dbo.Attributes a ON ea.AttributeId = a.AttributeId
WHERE ea.EmpID = e.EmpID
FOR XML PATH ('attribute'), TYPE
)
FROM dbo.Employee e
FOR XML PATH('row'), ROOT('rows')
you get this output:
<rows>
<row empid="1">
<attribute name="Attribute1">
<AttributeVal>SomeValue1</AttributeVal>
</attribute>
<attribute name="attribute2">
<AttributeVal>SomeValue2</AttributeVal>
</attribute>
</row>
<row empid="2">
<attribute name="Attribute1">
<AttributeVal>SomeValue3</AttributeVal>
</attribute>
<attribute name="attribute3">
<AttributeVal>SomeValue4</AttributeVal>
</attribute>
</row>
</rows>
What you cannot do is make the inner XML nodes have tag names that match the attribute name - you have to use some fixed tag name (like <attribute> in my sample), and then apply the values that are retrieved from your tables as either attributes on those XML tags (like the name= attribute in my sample) or as XML element values.
As far as I know, there is no way to use the AttributeValue as the XML tag name....
Here's an answer, but the PIVOT command limits you in that you have to know the name of your attributes in advance. With a little tweaking, you could probably do this dynamically (try searching for dynamic pivot in SQL Server 2005):
DECLARE #Employee TABLE ( empid INT )
DECLARE #EA TABLE
(
dataid INT
, empid INT
, attributeid CHAR(2)
, AttributeVal VARCHAR(100)
)
DECLARE #Attributes TABLE
(
AttributeID CHAR(2)
, AttributeName VARCHAR(100)
)
INSERT INTO #Employee
VALUES ( 1 ),
( 2 )
INSERT INTO #EA
( dataid, empid, attributeid, AttributeVal )
VALUES ( 10, 1, 'A1', 'somevalue1' )
, ( 20, 1, 'A2', 'somevalue2' )
, ( 30, 2, 'A1', 'somevalue3' )
, ( 40, 2, 'A3', 'somevalue4' )
INSERT INTO #Attributes
( AttributeID, AttributeName )
VALUES ( 'A1', 'attribute1' )
,
( 'A2', 'attribute2' )
,
( 'A3', 'attribute3' )
SELECT empID as '#empid'
, attribute1
, attribute2
, attribute3
, attribute4
FROM ( SELECT e.empid
, a.AttributeName
, ea.AttributeVal
FROM #Employee e
JOIN #EA ea ON e.empid = ea.empid
JOIN #Attributes a ON ea.attributeid = a.attributeid
) ps PIVOT
( MIN(AttributeVal) FOR AttributeName IN ( [attribute1], [attribute2], [attribute3], [attribute4] ) ) AS pvt
FOR XML PATH('row'), ROOT('rows')
I am working with the following query.I want to use Date_Sent_to_Recorder in my other calculations which follows.I am getting an error "Invalid column name 'Date_Sent_to_Recorder'." People recommended using a CTE for this but i am not able to fit it in this scenerio.I have a correlated subquery which calculates Date_Sent_to_Recorder.Please help.
SELECT
C.Name Client ,
SecONdary_Document.Primary_Document_ID ,
SecONdary_Document.Secondary_Document_Id ,
Primary_Document.State + ',' + GB_Counties.CountyName State ,
Grantor.Name Grantor ,
Loan_Number ,
CONVERT(VARCHAR(10), Primary_Document.PIF_Date, 101) PIF_Date ,
( SELECT CASE WHEN dbo.SECONDARY_DOCUMENT.Status_ID = 21
THEN CONVERT(VARCHAR(10), dbo.SECONDARY_DOCUMENT.Updated_Dt, 101)
ELSE ( SELECT TOP 1
CONVERT(VARCHAR(10), dbo.SECONDARY_DOCUMENT_STATUS_HISTORY.Created_Dt, 101)
FROM dbo.SECONDARY_DOCUMENT_STATUS_HISTORY
WHERE dbo.SECONDARY_DOCUMENT_STATUS_HISTORY.Secondary_Document_ID = SecONdary_Document.Secondary_Document_Id
AND SECONDARY_DOCUMENT_STATUS_HISTORY.Status_ID = 21
ORDER BY dbo.SECONDARY_DOCUMENT_STATUS_HISTORY.Created_Dt DESC
)
END
) AS Date_Sent_to_Recorder ,
Satis_TimeFrame ,
CASE WHEN PIF_Date IS NULL
OR Date_Sent_to_Recorder IS NULL THEN NULL
ELSE DATEDIFF(DAY, PIF_Date,
Date_Sent_to_Recorder)
END TotalDays ,
CASE WHEN PIF_Date IS NULL
OR Date_Sent_to_Recorder IS NULL THEN NULL
ELSE CASE WHEN DATEDIFF(DAY, PIF_Date,
ISNULL(Date_Sent_to_Recorder,
GETDATE())) > Satis_TimeFrame
THEN 'N'
ELSE 'Y'
END
END InCompliance ,
Loan_Name ,
Deal_Name ,
Deal.Deal_Id ,
Loan.Loan_Id
FROM Primary_Document
INNER JOIN SecONdary_Document ON SecONdary_Document.Primary_Document_ID = Primary_Document.Primary_Document_ID
INNER JOIN Status ON Status.Status_Id = SecONdary_Document.Status_Id
INNER JOIN GB_Counties ON GB_Counties.CountyId = Primary_Document.County_Id
INNER JOIN Loan ON Loan.Loan_Id = Primary_Document.Loan_Id
EDIT------------
DECLARE #Date_Sent_to_Recorder varchar(10)
SELECT C.Name Client ,
SecONdary_Document.Primary_Document_ID ,
SecONdary_Document.Secondary_Document_Id ,
Primary_Document.State + ',' + GB_Counties.CountyName State ,
Grantor.Name Grantor ,
Loan_Number ,
CONVERT(VARCHAR(10), Primary_Document.PIF_Date, 101) PIF_Date ,
--<START>
--3021,RRaghuvansi,If current status is 21 in SECONDARY_DOCUMENT then take Updated_Dt else take Created_Dt in SECONDARY_DOCUMENT_STATUS_HISTORY with status Out For Recorder
--CONVERT(VARCHAR(20), Recording_Date, 101) AS Recording_Date ,
#Date_Sent_to_Recorder=[dbo].[GET_RecordingDate](SecONdary_Document.Secondary_Document_Id), --<END>
Satis_TimeFrame ,
Loan_Name ,
Deal_Name ,
Deal.Deal_Id ,
Loan.Loan_Id
FROM Primary_Document
Since your schema is sort of unclear, here is a brief sample for the derived table syntax and referencing values from the derived table
Declare #Sample table(id1 int, id2 int, value varchar(20))
insert into #sample values (1,1, 'this')
insert into #sample values(2,2, 'that')
insert into #sample values(3,2, 'the other')
Select t1.ID1, t1.Value, t2.RevVal,
case
when t2.RevVal = 'siht' then 1 else 0
end as RevIsThisBackwards
from #sample t1
inner join (Select id1, reverse(value) as RevVal from #sample) t2
on t1.ID1 = t2.ID1
Results
id VALUES Rev Rev Value is this backwards
1 this siht 1
2 that taht 0
3 the other rehto eht 0
So you'll want to move the calculated column, and sufficient columns to join to into a derived table, in your case it would it would look similar to the below
INNER JOIN Loan ON Loan.Loan_Id = Primary_Document.Loan_Id
INNER JOIN (Select SomPKField, CASE WHEN dbo.SECONDARY_DOCUMENT.Status_ID = 21
THEN CONVERT(VARCHAR(10), dbo.SECONDARY_DOCUMENT.Updated_Dt, 101)
ELSE ( SELECT TOP 1
CONVERT(VARCHAR(10), dbo.SECONDARY_DOCUMENT_STATUS_HISTORY.Created_Dt, 101)
FROM dbo.SECONDARY_DOCUMENT_STATUS_HISTORY
WHERE
dbo.SECONDARY_DOCUMENT_STATUS_HISTORY.Secondary_Document_ID = SecONdary_Document.Secondary_Document_Id
AND SECONDARY_DOCUMENT_STATUS_HISTORY.Status_ID = 21
ORDER BY dbo.SECONDARY_DOCUMENT_STATUS_HISTORY.Created_Dt DESC
)
END as Date_Sent_to_Recorder
) as Sub1
on SomeTable.SomePKField = Sub1.SomePKField
**I edit your edit in this edit.**
SELECT C.Name Client ,
SecONdary_Document.Primary_Document_ID ,
SecONdary_Document.Secondary_Document_Id ,
Primary_Document.State + ','
+ GB_Counties.CountyName State ,
Grantor.Name Grantor ,
Loan_Number ,
CONVERT(VARCHAR(10), Primary_Document.PIF_Date, 101) PIF_Date ,
[dbo].[GET_RecordingDate]
(SecONdary_Document.Secondary_Document_Id)
As Date_Sent_To_Recorder
Satis_TimeFrame ,
Loan_Name ,
Deal_Name ,
Deal.Deal_Id ,
Loan.Loan_Id
FROM Primary_Document
You cannot refer to a computed column in other columns of a SELECT. The simplest solution for what you are trying to achieve is to pre-calculate Date_Sent_to_Recorder and store it in a temporary table, then join to that table when doing your main query.
Protip: use proper formatting and table aliases; SQL like you posted is difficult to read, and almost impossible to understand.
Edit: something like this:
create table #temp
( Primary_Document_ID int,
Date_Sent_To_Recorder datetime )
insert #temp
select Primary_Document_ID,
CASE
WHEN dbo.SECONDARY_DOCUMENT.Status_ID = 21
THEN CONVERT(VARCHAR(10), dbo.SECONDARY_DOCUMENT.Updated_Dt, 101)
ELSE
(SELECT TOP 1
CONVERT(VARCHAR(10), dbo.SECONDARY_DOCUMENT_STATUS_HISTORY.Created_Dt, 101)
FROM dbo.SECONDARY_DOCUMENT_STATUS_HISTORY
WHERE dbo.SECONDARY_DOCUMENT_STATUS_HISTORY.Secondary_Document_ID = SecONdary_Document.Secondary_Document_Id
AND SECONDARY_DOCUMENT_STATUS_HISTORY.Status_ID = 21
ORDER BY dbo.SECONDARY_DOCUMENT_STATUS_HISTORY.Created_Dt DESC)
END
from SecONdary_Document
-- main select, joining to #temp
Because Date_Sent_to_Recorder depends only on SECONDARY_DOCUMENT & SECONDARY_DOCUMENT_STATUS_HISTORY tables, you can replace SECONDARY_DOCUMENT in the INNER JOIN by the following (which gives you Date_Sent_to_Recorder as a column):
SELECT SD.Primary_Document_ID,
SD.Secondary_Document_Id,
CASE WHEN SD.Status_ID = 21
THEN CONVERT(VARCHAR(10), SD.Updated_Dt, 101)
ELSE CONVERT(VARCHAR(10), SDSH.Created_Dt, 101)
END Date_Sent_to_Recorder
FROM SECONDARY_DOCUMENT SD
INNER JOIN dbo.SECONDARY_DOCUMENT_STATUS_HISTORY SDSH
ON SDSH.Secondary_Document_ID = SD.Secondary_Document_Id
AND SDSH.Status_ID = 21
INNER JOIN (SELECT Secondary_Document_ID, max(Created_Dt) Created_Dt
FROM dbo.SECONDARY_DOCUMENT_STATUS_HISTORY
WHERE Status_ID = 21
GROUP BY Secondary_Document_ID) SDSH2
ON SDSH.Secondary_Document_ID = SDSH2.Secondary_Document_Id
AND SDSH.Created_Dt = SDSH2.Created_Dt
and finally you have:
SELECT C.Name Client,
SecONdary_Document.Primary_Document_ID,
SecONdary_Document.Secondary_Document_Id,
Primary_Document.State + ',' + GB_Counties.CountyName State,
Grantor.Name Grantor,
Loan_Number,
CONVERT(VARCHAR(10), Primary_Document.PIF_Date, 101) PIF_Date,
SecONdary_Document.Date_Sent_to_Recorder,
Satis_TimeFrame,
CASE WHEN PIF_Date IS NULL
OR SecONdary_Document.Date_Sent_to_Recorder IS NULL
THEN NULL
ELSE DATEDIFF(DAY, PIF_Date,
SecONdary_Document.Date_Sent_to_Recorder)
END TotalDays,
CASE WHEN PIF_Date IS NULL
OR SecONdary_Document.Date_Sent_to_Recorder IS NULL THEN NULL
ELSE CASE WHEN DATEDIFF(DAY, PIF_Date,
ISNULL(SecONdary_Document.Date_Sent_to_Recorder
,GETDATE())) > Satis_TimeFrame
THEN 'N'
ELSE 'Y'
END
END InCompliance,
Loan_Name,
Deal_Name,
Deal.Deal_Id,
Loan.Loan_Id
FROM Primary_Document
INNER JOIN (SELECT SD.Primary_Document_ID,
SD.Secondary_Document_Id,
CASE WHEN SD.Status_ID = 21
THEN CONVERT(VARCHAR(10), SD.Updated_Dt, 101)
ELSE CONVERT(VARCHAR(10), SDSH.Created_Dt, 101)
END Date_Sent_to_Recorder
FROM SECONDARY_DOCUMENT SD
INNER JOIN dbo.SECONDARY_DOCUMENT_STATUS_HISTORY SDSH
ON SDSH.Secondary_Document_ID = SD.Secondary_Document_Id
AND SDSH.Status_ID = 21
INNER JOIN (SELECT Secondary_Document_ID, max(Created_Dt) Created_Dt
FROM dbo.SECONDARY_DOCUMENT_STATUS_HISTORY
WHERE Status_ID = 21
GROUP BY Secondary_Document_ID) SDSH2
ON SDSH.Secondary_Document_ID = SDSH2.Secondary_Document_Id
AND SDSH.Created_Dt = SDSH2.Created_Dt) SecONdary_Document
ON SecONdary_Document.Primary_Document_ID
= Primary_Document.Primary_Document_ID
INNER JOIN Status ON Status.Status_Id = SecONdary_Document.Status_Id
INNER JOIN GB_Counties ON GB_Counties.CountyId = Primary_Document.County_Id
INNER JOIN Loan ON Loan.Loan_Id = Primary_Document.Loan_Id