Based on this answer, I have created a function to loop through column names and return a query result into JSON format. I am using FOR XML because I am working on an SQL Server version that does not support FOR JSON.
I have the query returning valid JSON format, except where there are date fields, and although I have been searching online I think I am a bit over my head in terms of depth of SQL Server understanding. I have been playing with CAST
and CONVERT
and ISDATE
but cannot get the query to generate results. I am also a little unclear on how the value('.', 'varchar(max)')
works, even though I have read up on it.
For example, this query works perfectly.
SELECT
STUFF((
SELECT',{"account_no":"' + account_no + '"' + ',"version_num":"' + version_num + '"' + ',"user_id":"' + user_id + '"' + '}'
FROM uAccountHighLevel
WHERE account_no='3718035' and version_num='37'
FOR XML path(''), type).value('.', 'varchar(max)')
, 1, 1, '')
Returning
{"account_no":"3718035","version_num":"37","user_id":"Sholtzman"}
However, the moment I add a datetime (or date) field into the query, it fails with this message:
Conversion failed when converting date and/or time from character string.
See query with datetime field added:
SELECT
STUFF((
SELECT',{"account_no":"' + account_no + '"' + ',"version_num":"' + version_num + '"' + ',"user_id":"' + user_id + '"' + ',"time_stamp":"' + time_stamp + '"' + '}'
FROM uAccountHighLevel
WHERE account_no='3718035' and version_num='37'
FOR XML path(''), type).value('.', 'varchar(max)')
, 1, 1, '')
Here is a snapshot of the table I am working with. All the tables have similar mix of data types:
If the field values were known each time, I think I could solve it, but the function that creates this query will be re-used on many tables, so a date/datetime field can appear in any order, so I need this function to build in some way to handle datetime fields. I also have no control over changing the datatypes in the database.
Below is the vba code I use to create the JSON.
Sub querySQL()
Dim conn As ADODB.Connection
Set conn = New ADODB.Connection
conn.Open "Provider=SQLOLEDB;Data Source=DVW-SQL02;Initial Catalog=UniversalQuoteProposal;UID=SVC_UQP;PWD=$vc13#up"
'grab column names
Dim sql As String
sql = "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = N'uAccountHighLevel'"
Dim rs As ADODB.Recordset
Set rs = New ADODB.Recordset
With rs
.ActiveConnection = conn
.CursorLocation = adUseClient
.Open sql, conn, adOpenKeyset, adLockReadOnly, adCmdText
End With
sql = buildSQL("uAccountHighLevel", rs, "List")
Dim rsFinal As ADODB.Recordset
Set rsFinal = New ADODB.Recordset
With rsFinal
.ActiveConnection = conn
.CursorLocation = adUseClient
.Open sql, conn, adOpenKeyset, adLockReadOnly, adCmdText
Debug.Print .Fields(0).Value
End With
End Sub
Function buildSQL(theTable As String, rs As ADODB.Recordset, arrayOrList As String) As String
'this has to be fixed, but we can do it :)
'adjust query builder and also had a case for isdate to cast to string
Dim queryBuilder As String
queryBuilder = "SELECT "
If arrayOrList = "array" Then queryBuilder = queryBuilder & "'[' + "
queryBuilder = queryBuilder & "STUFF(("
queryBuilder = queryBuilder & "SELECT',{"
rs.MoveFirst
Dim f As Long
For f = 0 To 3 'rs.RecordCount - 1
queryBuilder = queryBuilder & """" & rs.Fields(0).Value & """:""' + " & rs.Fields(0).Value & " + '""' + ',"
'this is one of my attempts to play with isdate, cast, convert
'queryBuilder = queryBuilder & """" & rs.Fields(0).Value & """:""' + (CASE WHEN ISDATE(" & rs.Fields(0).Value & ") = 1 THEN CONVERT(datetime, cast([" & rs.Fields(0) & "] AS CHAR(8))) END) + '""' + ',"
rs.MoveNext
Next
queryBuilder = Left(queryBuilder, Len(queryBuilder) - 1) & "}'"
queryBuilder = queryBuilder & " FROM " & theTable & " WHERE account_no='3718035' and version_num='37' "
queryBuilder = queryBuilder & " for xml path(''), type"
queryBuilder = queryBuilder & ").value('.', 'varchar(max)'), 1, 1, '')"
If arrayOrList = "array" Then queryBuilder = queryBuilder & " + ']'"
buildSQL = queryBuilder
End Function