SQL Server "FOR XML" encoding HTML entities? - sql-server

I am using SQL Server Management Studio. I have inherited a query that has a section that looks like:
...
ISNULL(
CASE
WHEN LOWER(PersonClass.Detail) LIKE '%student%'
THEN SUBSTRING((
SELECT DISTINCT
' / '+STUDENT_TERM.DEPT_NAME
FROM Warehouse.STUDENT_TERM STUDENT_TERM
INNER JOIN Warehouse.TERM TERM
ON STUDENT_TERM.TERM_CD = TERM.TERM_CD
AND TERM.TERM_START_DT <= #fyEnd
AND ISNULL(TERM.TERM_END_DT, GETDATE()) >= #fyStart
WHERE Persons.DWPersonId = STUDENT_TERM.DWPERSID FOR
XML PATH('')
), 4, 100000)
END, '') AS StudentHome,
...
This is finding a student's "home department". There is the possibility that a student could have more than one home so the above works a bit like MySQL's group_concat.
My question is about an unintended artifact of the query. Several departments have names in the data warehouse that have embedded ampersands & in them like:
A & B
The result of the query though is "HTML encoded" turning "A & B" into "A & B".
If I run the inner query the result is as expected with a simple ampersand and not the encoded form. I am guessing that the FOR XML is doing the encoding.
Is there a way to do the group_concat without having the result encoded?

You can get the value from the xml instead of cast to string:
ISNULL(
CASE
WHEN LOWER(PersonClass.Detail) LIKE '%student%'
THEN SUBSTRING((
SELECT DISTINCT
' / '+STUDENT_TERM.DEPT_NAME
FROM Warehouse.STUDENT_TERM STUDENT_TERM
INNER JOIN Warehouse.TERM TERM
ON STUDENT_TERM.TERM_CD = TERM.TERM_CD
AND TERM.TERM_START_DT <= #fyEnd
AND ISNULL(TERM.TERM_END_DT, GETDATE()) >= #fyStart
WHERE Persons.DWPersonId = STUDENT_TERM.DWPERSID FOR
XML PATH(''),TYPE
).value(N'.','nvarchar(max)') , 4, 100000)
END, '') AS StudentHome,

Related

Proc SQL not returning any columns. Innerjoin

I am trying to gather the information on which store is receiving which SKU along with some other relevant info. The data is in multiple tables so i am trying innerjoin the info. I am using SAS and it runs in SQL Server via passthrough. Below is the query i tried. I have confirmed that || works in the pass through. The issue seems to start in the from statement
connect to odbc (dsn='X' uid='X' pwd='XY');
create table School.TRANS_INFO as SELECT * from connection to odbc
(SELECT Distinct
S.Schd_t AS Schd_Date format MMDDYY10.,
S.otb As Ship_Loc,
W.store_NUMBER AS store,
S.SHP_ID AS SHIP_ID,
W.store_CITY_STATE,
Q.Stat_CD AS Status,
(S.PROD_CD || S.plt_CD) AS SKU,
W.ACCOUNT_TYPE as Location
FROM
SHPMT_DTL S
INNER JOIN store W ON W.store_NUMBER = S.Otb_DEST_store_NBR,
INNER JOIN SHP_LEG Q ON Q.SHPMT_ID = S.SHP_ID
WHERE
W.ACCOUNT_TYPE = 'I'
AND S.Schd_t <= Sysdate
AND Q.Stat_CD IN ('S','P')
ORDER BY Schd_Date);
disconnect from odbc;
QUIT;
However, after i run this i get an error saying "PROC SQL requires any created table to have at least 1 column". Any help to diagnose this issue would be appreciated.
Move the SAS syntax to the SAS side of the query. You also had an extra comma in the middle of the FROM clause. Note if you get in the habit of putting the commas (or any other continuation characters) at the beginning of the line instead of the end they will be easier for the programmers to scan and be sure they are done correctly.
create table School.TRANS_INFO as
SELECT Distinct
Schd_t AS Schd_Date format MMDDYY10.
, otb As Ship_Loc
, store_NUMBER AS store
, SHP_ID AS SHIP_ID
, store_CITY_STATE
, Stat_CD AS Status
, (PROD_CD || plt_CD) AS SKU
, ACCOUNT_TYPE as Location
from connection to odbc
(SELECT Distinct
S.Schd_t
, S.otb
, W.store_NUMBER
, S.SHP_ID
, W.store_CITY_STATE
, Q.Stat_CD
, S.PROD_CD
, S.plt_CD
, W.ACCOUNT_TYPE
FROM SHPMT_DTL S
INNER JOIN store W ON W.store_NUMBER = S.Otb_DEST_store_NBR
INNER JOIN SHP_LEG Q ON Q.SHPMT_ID = S.SHP_ID
WHERE W.ACCOUNT_TYPE = 'I'
AND S.Schd_t <= Sysdate
AND Q.Stat_CD IN ('S','P')
ORDER BY S.Schd_t
);

Select where in subquery from one row with CSV values

I'm trying to do a subquery where the value returned is a CSV list of values I want to use for the SELECT WHERE IN clause
SELECT *
FROM Facility.FacilityIO f
where f.FacilityID in (
select Facilities
from FacilityListView
where FacilityID = 'PSY35'
)
FacilityListView looks like this:
FacilityID Facilities
SOL1 SOL1,
PSY35 PSY3,PSY5
SOL1W SOL1,WSR1,
I get 0 results since SQL server is looking for a dataset and not an individual value but I don't know how to tell SQL server to select where f.FacilityID in ('PSY3','PSY5')
Join the tables and use the LIKE operator:
SELECT f.*
FROM Facility.FacilityIO f INNER JOIN FacilityListView v
ON ',' + v.Facilities + ',' LIKE '%,' + f.FacilityID + ',%'
WHERE v.FacilityID = 'PSY35'

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

How to write the mdx equivalent to following sql

I have the following SQL code in the Stored procedure in SQL server which feeds data to the reports. Now we are implementing the SSAS cube to process the data. I have a Fact table which has all the measures and degenerate dimensions. We are facing issues while converting below calculation into the MDX. This calculation purely depends on the Start Date and End Date parameters so it can not be done at the ETL time. It has to be performed when the client selects the Start and End date on the report.
Can any one help/ guide me how i should convert below code into MDX? As a novice in MDX world, i am facing following issues
a. Lack of temp table like structure which help storing the temp data during processing.
b. Stored procedure are supported as the CLR or COM objects. Why SQL/ MDX procedure are missing?
Is it possible to perform the following calculations from the cube data?
Select
rundate ,Entity ,MasterEntity ,TransactionDate ,BuyOrSell ,Quantity2 ,Quantity1 ,Quantity3 ,Quantity4 ,Profit1
,Profit2 ,Profit3 ,transactionId ,closingtransactionId
into #TempData from [Fact_Test]
Where datediff(d,#StartDate,rundate)>=0 and datediff(d,rundate,#EndDate )>=0 order by rundate
Select Rundate,TransactionDate,BuyOrSell,Quantity2,transactionId,closingtransactionId
into #ClosedTransactions from #TempData Where BuyOrSell = 'C'
Select
affected.Rundate AS 'OpenTransactionDate', affected.BuyOrSell as 'OpenTransaction_BuyOrSell',
affected.Quantity3 as 'OpenTransaction_Quantity1' , affected.Quantity1 as 'OpenTransaction_Quantity2',
affected.Profit2 as 'OpenTransaction_Profit2', affected.transactionId as 'OpenTransaction_transactionId',
affected.closingtransactionId as 'ClosedTaxlot_ClosedingtransactionId'
into #AffectedOpenTransaction from #TempData affected
where affected.transactionId in (select distinct transactionId from #ClosedTransactions)
and affected.rundate between #StartDate and #PreviousDateFromEndDate and affected.BuyOrSell = 'O'
select
CLOSED.Rundate as 'ClosingDate', CLOSED.Quantity2 as 'ClosedQuantity',
CLOSED.transactionId as 'closingtransactionId', AFFECTED.OpenTransaction_transactionId as 'OpeningtransactionId',
AFFECTED.OpenTransaction_Quantity2 as 'AffectedQuantity', AFFECTED.OpenTransaction_Profit2 as 'Affected_Profit2',
AFFECTED.OpenTransactionDate as 'AffectedTransactionDate',Convert(float,0) as 'Profit2_Adjusted'
into #TempProfit2
from #ClosedTransactions CLOSED
inner join #AffectedOpenTransaction AFFECTED
on ( CLOSED.transactionId = AFFECTED.OpenTaxlot_transactionId and datediff(d,AFFECTED.OpenTransactionDate,CLOSED.Rundate)>0 )
update #TempProfit2
set Profit2_Adjusted = case when AffectedQuantity <>0 then(ClosedQuantity * 1.0/(AffectedQuantity*1.0)) * Affected_Profit2 else 0.0 end
select
closingtransactionId, ClosingDate,
Sum( Case When datediff(d,AffectedTransactionDate,ClosingDate)> 0 Then Convert(float,Profit2_Adjusted) else 0.0 End ) as UnrealizedPNL_Adjusted
into #Profit2_Adjusted
from
#TempProfit2
group by closingtransactionId,ClosingDate
select
MasterEntity,Entity, sum(Profit1 + isnull(Profit2_Adjusted,0)) as FinalProfit1,
sum(Profit2 - isnull(Profit2_Adjusted,0)) as FinalProfit12,sum(Profit3) as Profit3,
sum(Profit1 + isnull(Profit2_Adjusted,0)) + sum(Profit2 - isnull(Profit2_Adjusted,0)) + sum(Profit3) as TotalMTMPNL
from #TempData
left outer join #Profit2_Adjusted
on (#TempData.transactionId = #Profit2_Adjusted.closingtransactionId
and datediff(d, #Profit2_Adjusted.ClosingDate, #TempData.Rundate) = 0 and #TempData.BuyOrSell = 'C' )
group by MasterEntity,Entity
order by MasterEntity,Entity

SQL Subquery Select Table based on Outer Query

I have a general query that looks like this:
SELECT DISTINCT pb.id, pb.last, pb.first, pb.middle, pb.sex, pb.phone, pb.type,
specialties = substring(
SELECT ('|' + cs.specialty )
FROM CertSpecialty AS cs
INNER JOIN CertSpecialtyIndex AS csi on cs.specialty = csi.specialty
WHERE cs.id = pb.id
ORDER BY cs.sequence_no
FOR XML path(''),2,500)
FROM table AS pb
WHERE etc etc etc
The issue is this:
The "type" column that I'm selecting is an integer - types 1-4.
In the subquery, see where I am querying from the table CertSpecialty right now.
What I actually need to do is, if the type field comes back as a 1 or a 3, that's the table I need to query. But if the row's result is a type 2 or 4 (i.e., an ELSE), I need to be querying the same column in the table CertSpecialtyOther.
So it'd need to look something like this (though this obv doesn't work):
SELECT DISTINCT pb.id, pb.last, pb.first, pb.middle, pb.sex, pb.phone, pb.type,
specialties =
IF type in (1,3)
substring((SELECT ('|' + cs.specialty )
FROM CertSpecialty AS cs
INNER JOIN CertSpecialtyIndex AS csi on cs.specialty = csi.specialty
WHERE cs.id = pb.id
ORDER BY cs.sequence_no
FOR XML path(''),2,500)
ELSE
substring((SELECT ('|' + cs.specialty )
FROM CertSpecialtyOther AS cs
INNER JOIN CertSpecialtyIndex AS csi on cs.specialty = csi.specialty
WHERE cs.id = pb.id
ORDER BY cs.sequence_no
FOR XML path(''),2,500)
end
FROM table AS pb
WHERE etc etc etc
Is this possible? If so, what is the correct syntax? Is there a simpler way to write it where I'm switching which table I query without completely duplicating the subquery?
Also, does anyone have a good resource they could link me for this sort of thing to learn more besides?
Thanks in advance.
Use a CTE.
;WITH cs AS
(
SELECT 'A' SpecialtyCategory, phy_key, specialty
FROM CertSpecialty
UNION ALL
SELECT 'B' SpecialtyCategory, phy_key, specialty
FROM CertSpecialtyOther
)
SELECT csi.id, cs.specialty
FROM cs
INNER JOIN CertSpecialtyIndex AS csi on cs.specialty = csi.specialty
WHERE cs.phy_key = pb.phy_key
AND cs.SpecialtyCategory = (CASE WHEN type in (1,3) THEN 'A' ELSE 'B' END)

Resources