I'm a newbie to SQL Server. I have a table Accounts which is defined as:
OrganizationId int,
AccountDetails varchar(max)
The AccountDetails column contains XML data.
The data in the table looks like this:
1 | <Account><Id>100</Id><Name>A</Name></Account>
2 | <Account><Id>200</Id><Name>B</Name></Account>
3 | <Account><Id>300</Id><Name>C</Name></Account>
4 | <Account><Id>400</Id><Name>D</Name></Account>
I need write a SQL query to get the records from this table where AccountId is 200 or 400.
The query should return two rows (#2 and #4) in JSON format, like this:
result1 : { "account_id": 200, "account_name": B }
result2 : { "account_id": 400, "account_name": D }
I'm wondering how do I go about this?
Thank you.
For # 1 above, should I be trying to cast the AccountDetails column to XML type and then use "nodes" feature for querying/filtering?
For #2, I should be writing a SQL function to convert the XML to JSON first and querying XML to build the JSON as needed?
As already mentioned, it is much better to use a proper XML data type for the AccountDetails column.
Please try the following solution.
It will work starting from SQL Server 2016 onwards.
SQL
-- DDL and sample data population, start
DECLARE #tbl TABLE (OrganizationId INT IDENTITY PRIMARY KEY, AccountDetails NVARCHAR(MAX));
INSERT #tbl (AccountDetails) VALUES
('<Account><Id>100</Id><Name>A</Name></Account>'),
('<Account><Id>200</Id><Name>B</Name></Account>'),
('<Account><Id>300</Id><Name>C</Name></Account>'),
('<Account><Id>400</Id><Name>D</Name></Account>');
-- DDL and sample data population, end
;WITH rs AS
(
SELECT t.OrganizationId
, account_id = x.value('(/Account/Id/text())[1]', 'INT')
, account_name = x.value('(/Account/Name/text())[1]', 'VARCHAR(20)')
FROM #tbl AS t
CROSS APPLY (VALUES(TRY_CAST(AccountDetails AS XML))) AS t1(x)
)
SELECT *
, JSONData = (SELECT rs.account_id, rs.account_name FOR JSON PATH,WITHOUT_ARRAY_WRAPPER)
FROM rs
WHERE rs.account_id IN (200, 400);
Output
OrganizationId
account_id
account_name
JSONData
2
200
B
{"account_id":200,"account_name":"B"}
4
400
D
{"account_id":400,"account_name":"D"}
I have three variables:
"v_LocationsByCode" with value of below.
Code1="location1";Code2="location2";
"v_Code" with value of either Code1 or Code2 (or Code3 if v_LocationsByCode has it, etc)
"v_Location" this is a variable with expression, and its value will be used depending on value of "v_Code"
So:
If v_Code is "Code1" then v_Location should be "location1"
Else If v_Code is "Code2" then v_Location should be "location2"
Else If ...
Else ""
Can you help me with the expression (without hardcoding)?
I was able to do this in sql using a bunch of substring(), charindex() and len(), however SSIS-expression does not have charindex(). It has findstring() but it's missing "starting location".
Your expression in v_Location should be like below :
#[User::v_Code]=="location1"? "location1" : "location2"
I posted a question about this yesterday, which was very helpfully answered by solutionist, but I now have a follow up question along the same lines.
I want to get two sets of data out from the JSON.
I have three data sets, one is the header, one is a set of customer records and the last is an error object.
The structure I am looking to try and get is:
Header
Customers
Error
but what I'm getting is:
Header
Customer, Error
Customer, Error
Now in this example, the error is null so I'm happy either with the error being omitted because it's null, or coming back as an empty object, but I want a single one, not one per customer.
This is what I currently get:
select isjson('{"APIResult":[{"ID":200,
"Status_Message":"Success",
"Developer_Message":"Customers found",
"User_Message":"Customers found",
"Return_Code":0,
"Customer":[{"ID":"A6B10FA0-85AD-422D-8A7E-07EEA541593E",
"First_Name":"Bbb",
"Paternal_Last_Name":"Bbbbb",
"Email_Address":"bbbb#example.com",
"Error":[{}]
},
{"ID":"91EE2FD6-2C40-4CFD-ABB7-2CDAE3624487",
"First_Name":"Aaaa",
"Paternal_Last_Name":"Aaaaa",
"Email_Address":"aaaaa#example.com",
"Error":[{}]
}]
}]
}')
And this is what I am trying to get:
select isjson('{"APIResult":[{"ID":200,
"Status_Message":"Success",
"Developer_Message":"Customers found",
"User_Message":"Customers found",
"Return_Code":0,
"Customer":[{"ID":"A6B10FA0-85AD-422D-8A7E-07EEA541593E",
"First_Name":"Bbb",
"Paternal_Last_Name":"Bbbbb",
"Email_Address":"bbbb#example.com"
},
{"ID":"91EE2FD6-2C40-4CFD-ABB7-2CDAE3624487",
"First_Name":"Aaaa",
"Paternal_Last_Name":"Aaaaa",
"Email_Address":"aaaaa#example.com"
}],
"Error":[{}]
}]
}')
Both are valid JSON (I have tested this this time, as you can see), but I can't work out how to get the second format.
This is the query I am running to get the output:
declare #returncode int = 0
,#VerboseMsg nvarchar(4000) = 'Customers found'
,#DisplayMsg nvarchar(4000) = 'Customers found'
CREATE TABLE #Customers (CustomerID UNIQUEIDENTIFIER DEFAULT(NEWID()), FirstName NVARCHAR(50), PaternalLastName NVARCHAR(50), EmailAddress NVARCHAR(250))
INSERT INTO #Customers (FirstName, PaternalLastName, EmailAddress)
VALUES ('Aaaa', 'Aaaa', 'aaaa#example.com'), ('Bbbb', 'Bbbb', 'bbbb#example.com')
SELECT st.APIStatus AS 'ID'
,st.StatusMessage AS 'Status_Message'
,#VerboseMsg AS 'Developer_Message'
,#DisplayMsg AS 'User_Message'
,st.ReturnCode AS 'Return_Code'
,[Customer].CustomerID AS 'ID'
,[Customer].FirstName AS 'First_Name'
,[Customer].PaternalLastName AS 'Paternal_Last_Name'
,[Customer].EmailAddress AS 'Email_Address'
,[Error].ErrorCode AS 'Error_Code'
,[Error].ErrorMsg AS 'Error_Message'
FROM (SELECT 200 AS APIStatus, 'Success' AS StatusMessage, #ReturnCode AS ReturnCode) st
LEFT JOIN (SELECT CustomerID
,FirstName
,PaternalLastName
,EmailAddress
,#ReturnCode AS ReturnCode
FROM #Customers
) As [Customer]
ON st.ReturnCode = [Customer].ReturnCode
LEFT JOIN (SELECT #ReturnCode AS ErrorCode, #DisplayMsg AS ErrorMsg WHERE #returncode != 0) AS [Error]
ON [Error].ErrorCode = st.ReturnCode
FOR JSON AUTO, ROOT('APIResult')
Is it the case that the only way I can get this output is by stitching things together myself? JSON is still quite new to me, and I am struggling to get to grips with the makeup of it.
In this setup I would place error code after return code and would use subqueries with JSON PATH like this:
SELECT st.APIStatus AS 'ID'
,st.StatusMessage AS 'Status_Message'
,#VerboseMsg AS 'Developer_Message'
,#DisplayMsg AS 'User_Message'
,st.ReturnCode AS 'Return_Code'
, (SELECT #ReturnCode AS ErrorCode, #DisplayMsg AS ErrorMsg FOR JSON PATH) AS [Error]
,[Customer].CustomerID AS 'ID'
,[Customer].FirstName AS 'First_Name'
,[Customer].PaternalLastName AS 'Paternal_Last_Name'
,[Customer].EmailAddress AS 'Email_Address'
FROM (SELECT 200 AS APIStatus, 'Success' AS StatusMessage, #ReturnCode AS ReturnCode) st
LEFT JOIN (SELECT CustomerID
,FirstName
,PaternalLastName
,EmailAddress
,#ReturnCode AS ReturnCode
FROM #Customers
) As [Customer]
ON st.ReturnCode = [Customer].ReturnCode -- why?
FOR JSON AUTO, ROOT('APIResult')
Note that if you don't have any record in Error it will be omitted, but you can use null for that case, also I have noticed that you used #ReturnCode twice and I don;t know if that is intentionally or mistake.
I have this legacy code that started failing…
UPDATE B2C
SET B2C.dborderid = A.order_number__c
FROM b2csf B2C
JOIN Alemania A ON B2C.actualid = A.salesforce_id
I get this error:
Msg 245, Level 16, State 1, Line 1
Conversion failed when converting the nvarchar value '7201799-' to data type int.
I went ahead and changed it to:
UPDATE B2C
SET B2C.dborderid = (CASE
WHEN Isnumeric (a.order_number__c) = 1
THEN CAST(a.order_number__c AS INT)
END)
FROM b2csf B2C
JOIN Alemania A ON B2C.actualid = A.salesforce_id
And now I get
Msg 245, Level 16, State 1, Line 1
Conversion failed when converting the nvarchar value '7575932.' to data type int.
My questions now are:
how can I avoid this error? I don’t mind for example losing '7575932.' value.(Ideally I would like to discard '7575932.' value)
I am trying my best to follow best practices... is changing the column DBorderid to nvarchar the only "best practice" alternative?
(I am using SQL Server 2008)
Instead of ... WHEN Isnumeric (a.order_number__c) = 1 ... use ... WHEN Isnumeric (a.order_number__c + '.0e0') = 1 ...
I have a procedure named dbo.CLRSPTest which i have encrypted. When I execute the procedure it gets executed but throws an error when I use sp_helptext CLRSPTest to view the code i.e Msg 15197, Level 16, State 1, Procedure sp_helptext, Line 107
There is no text for object 'CLRSPTest'.
Can anyone please help me out??? I am getting puzzled.
This error is raised by the following code in sp_helptext
if (select count(*) from syscomments c, sysobjects o where o.xtype not in ('S', 'U')
and o.id = c.id and o.id = #objid) = 0
begin
raiserror(15197,-1,-1,#objname) b
return (1)
end
This simply means that any object (not a table or system object) which does not have a line in syscomments will return this error.
Encrypted objects have a record in the syscomments table with NULL in the xtext field so they don't get caught by the earlier code. The message you get for those object comes from this query.
if (select count(*) from syscomments where id = #objid and encrypted = 0) = 0
begin
raiserror(15471,-1,-1,#objname)
return (0)
end
Now why do we get an error from the first one and no error for the second one... That can be explained by checking the data in master..sysmessages.
select error, severity, description
from master..sysmessages
where error in (15197, 15471)
and msglangid = 1033
This query returns:
error severity description
15197 16 There is no text for object '%s'.
15471 10 The text for object '%ls' is encrypted.
Here we see that error 15197 has severity 16 and error 15471 has severity 10. On msdn it is explained that error levels 0-9 are not "raised" and that error level 10 gets converted to error level 0 for compatibility reasons.
So to conclude it all. You get this error message because your procedure is a SQL CLR procedure (which don't get any records in the syscomments table)