Inserting, updating, and deleting data with the Easysoft Xero ODBC driver
We're currently adding INSERT
, UPDATE
, and DELETE
support to the Xero ODBC driver. For a pre-release version of the read-write Xero ODBC driver, contact the Easysoft Support team ().
Contents
- Which tables support
INSERT
,UPDATE
, andDELETE
statements? - Special tables
- Attachments
-
Accounts
table -
BankTransactions
table -
BankTransfers
table -
BatchPayments
table -
BrandingThemes
table -
Contacts
tables -
ContactGroups
table -
CreditNotes
table -
Currencies
table -
Employees
table -
ExpenseClaims
table -
Invoices
tables -
Items
table -
LinkedTransactions
table -
ManualJournals
table -
PurchaseOrders
table -
Quotes
tables -
Receipts
table -
TaxRates
table -
TrackingCategories
table - Formating XML
- Using the Xero ODBC driver with SQL Server
- HTTP 400 Bad Request
- SQL format and function support
Which tables support INSERT
, UPDATE
, and DELETE
statements?
You can query any table exposed by the Xero ODBC driver. For INSERT
, UPDATE
, or DELETE
support, refer to this table:
Table Name |
INSERT
|
UPDATE
|
DELETE
|
---|---|---|---|
Accounts
|
✓ | ✓ | ✓ |
BankTransactions
|
✓ | ✓ | ✕ |
BankTransfers
|
✓ | ✕ | ✕ |
BatchPayments
|
✕ | ✕ | ✓ 2 |
BrandingThemes
|
✕ | ✓ 3 | ✕ |
Contacts
|
✓ | ✓ | ✕ |
ContactGroups
|
✓ | ✓ 1 | ✕ |
CreditNotes
|
✓ | ✓ | ✓ 2 |
Currencies
|
✓ | ✕ | ✕ |
Employees
|
✓ | ✕ | ✕ |
ExpenseClaims
|
✓ | ✕ | ✕ |
Invoices
|
✓ | ✓ | ✕ |
Items
|
✓ | ✓ | ✓ |
LinkedTransactions
|
✓ | ✓ | ✓ |
ManualJournals
|
✓ | ✓ | ✕ |
Payments
|
✓ | ✓ | ✕ |
PurchaseOrders
|
✓ | ✓ | ✕ |
Quotes
|
✓ | ✓ | ✕ |
Receipts
|
✓ | ✓ | ✕ |
RepeatingInvoices
|
✓ | ✓ | ✕ |
TaxRates
|
✓ | ✓ | ✕ |
TrackingCategories
|
✓ | ✓ | ✓ |
Notes
- You can't currently update the
Contacts
column in theContactGroup
tables. - You can't delete
BatchPayments
orCreditNotes
records but you can change their status toDELETED
. - You can use the Xero XPI to apply
BrandingThemes
records to aPaymentServices
record.
Special tables
LastId
table
Use the LastId
table to find out the status of your most recent INSERT
, UPDATE
, or DELETE
statement.
Column Name | Description |
---|---|
LastID
|
The ID of the last Xero record to be affected by an INSERT , UPDATE , or DELETE statement.
|
Status
|
XML status response. |
LastHTTPCode
|
HMTL response code. For example:
200: OK 404: Not Found |
LastHTTPMessage
|
HTTP message. |
For example:
UPDATE Contacts SET EmailAddress='example_user@example.com' WHERE [Name]='example_customer' SELECT LastID FROM LastId LastID: a166e4c6-1a89-4d5e-acf3-939a9f82e23c
Note INSERT
s always update the LastID
table. UPDATE
s and DELETE
s only change the LastID
table if a record is succesfully updated or deleted. For example, if you ran the UPDATE
statement shown earlier twice, the second UPDATE
would not alter the data and therefore not update LastID
.
The LastId
table and columns only apply to the current connection. For example, if you connect, insert a record, disconnect, and then re-connect, the LastID
table is empty.
If your SQL statement contains a value that's not valid, LastID
contains the reason why the statement failed. For example:
UPDATE BankTransactions SET LineItems = replace(LineItems, '<Quantity>1.0000</Quantity>', '<Quantity>2</Quantity>') WHERE BankTransactionId = '737982b0-2811-44c9-bdb3-3b26a3a6ef8c' -- invalid BankTransactionId SELECT * from LastId
produces this output:
Column Name | Value returned | Description |
---|---|---|
LastID
|
NULL
|
Nothing has been updated. |
Status
|
NULL
|
|
LastHTTPCode
|
404 | Xero API says your query did not work. |
LastHTTPMessage
|
Last HTTP message. |
The BankTransactionId was not valid.
|
History
table
Use the History
table to query the Xero history for:
BankTransactions
BatchPayments
BankTransfers
Contacts
Creditnotes
Invoices
Items
ManualJournals
Overpayments
Payments
Prepayments
PurchaseOrders
- Repeating
Invoices
Quotes
The History
table contains these columns:
Column Name | Description |
---|---|
Endpoint
|
The History endpoint.
|
Guid
|
The ID of the record being read. |
Changes
|
The change made. For example, "Created" or "Edited." |
DateUTCString
|
Timestamp in a string format. |
DateUTC
|
Timestamp in an ODBC SQL_TYPE_TIMESTAMP format.
|
User
|
The Xero user who made the changes. |
Details
|
Futher information about what changes were made. |
Pass the endpoint and GUID
in your WHERE
clause. For example:
SELECT * FROM history WHERE endpoint = 'Contacts' AND guid = '9ce626d2-14ea-463c-9fff-6785ab5f9bfb'
The Details
column is a LONGVARCHAR
type. To sort the results by Details
, convert the column to a VARCHAR
type. For example:
SELECT Changes, DateUTC, CAST(Details as varchar(512)) AS & quot; Desc & quot; FROM history WHERE endpoint = 'Contacts' AND guid = '9ce626d2-14ea-463c-9fff-6785ab5f9bfb' ORDER BY DateUTC DESC
How do I get the GUID
?
The GUID
is the same as the ID of the primary key in the table, so, for example:
SELECT QuoteId from Quotes
returns all the GUID
s from the Quotes
table.
API
table
Use this table to query the Xero API.
Column Name | Direction | Reguired | Description |
---|---|---|---|
URL
|
Input | Yes |
A Xero API endpoint. For example, Invoices or Accounts .
|
Method
|
Input | Yes |
GET , PUT , POST , or DELETE depending on which Xero API you are calling.
|
Code
|
Output | Not applicable |
HMTL response code. For example:
200: OK 404: Not Found |
XMLRequestBody
|
Input | No | The XML to send to the Xero API. Use URL encoded strings. |
JSONRequestBody
|
Input | No | The JSON to send to the Xero API. |
Response
|
Output | Not applicable | HTML response text. |
XMLResponseBody
|
Output | Not applicable | The XML response from the Xero API. |
Example queries:
SELECT * FROM api WHERE url = 'Currencies' AND Method = 'GET'; SELECT * FROM api WHERE url = 'Accounts/524c9f2d-e680-4861-82f6-4ad171b51de5' AND Method = 'GET'; SELECT * FROM api WHERE url = 'Currencies' AND Method = 'PUT' AND XMLRequestBody = '<Currency><Code>SGD</Code></Currency>'; SELECT * FROM api WHERE url = 'ContactGroups/fd33e5d2-3f95-4b1b-a405-7ed7067b9c22/Contacts' AND Method = 'DELETE'
If you send invalid XML in the XMLRequestBody
:
SELECT * FROM api WHERE url = 'Currencies' AND Method = 'PUT' AND XMLRequestBody = '<Currency2><Code>SGD</Code></Currency>'
the Xero API return code is 400, the response is "Bad Request" and the XMLResponseBody is the relevant API error response:
<ApiException xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <ErrorNumber>14</ErrorNumber> <Type>PostDataInvalidException</Type> <Message>Xml for post data was invalid, The 'Currency2' start tag on line 1 position 2 does not match the end tag of 'Currency'. Line 1, position 30.</Message> </ApiException>
Warning PUT
and POST
work in different ways in the Xero API. Check the Xero XPI documentation carefully to be absolutely sure that you are using the correct method when inserting or updating records.
JSONRequestBody
columns
From the Xero API Development team:
"At Xero we use .NET, and used the Microsoft .NET JSON date format available at the time of original development. We know it's ugly but not something we can fix without a breaking change or a new version of the API. We're really sorry about this. To help you along, below we explain how to handle this date format. An example date/time in JSON is returned like this: https://developer.xero.com/documentation/api/accounting/requests-and-responses."
Here is an example query that uses JSON in the WHERE
clause:
SELECT * FROM api WHERE url = 'TrackingCategories/201a3021-77de-495d-a233-1faaa40e2f64/Options' AND Method = 'PUT' AND JSONRequestBody = '{ "Name": "New Track 5" }'
Note You can't update the BankTransfer table.
XML format columns
Some Xero columns need to be in XML format. For example, invoice line items:
<LineItems> <LineItem> <Description>Retainer for consulting work</Description> <UnitAmount>500.00</UnitAmount> <AccountCode>200</AccountCode> <Quantity>3</Quantity> <AccountID>c563b607-fb0e-4d06-9ddb-76fdeef20ae3</AccountID> </LineItem> </LineItems>
You can use spaces and newlines in your XML to improve readability if you prefer, but you don't need to.
You don't need to include all XML fields. In the example, the field <LineAmount>
is missing. Xero automatically calculates the <LineAmount>
value and puts that in for you using the formula:
LineAmount = Quantity * Unit Amount * ((100 – DiscountRate)/100)
Encode reserved charaters within your XML tags. For example:
Not encoded | This & that value are < the other. |
URL encoded | This%20%26%20that%20value%20are%20%3C%20the%20other%2E |
HTML entities | This & that value are < the other. |
The Xero API always replaces reserved characters with HTML entities when returning data. For INSERT
s and UPDATE
s, use either URL encoding, entities, or a combination of both.
If you get the error "[Easysoft ODBC-Xero Driver]Invalid XML detected," check your data for reserved characters.
XML element names are case sensitive. For example, <ContactId>
is not valid, <ContactID>
is. If you don't use the correct case, Xero returns an error similar to the following:
"PostDataInvalidException: The element 'ContactId' was not recognised. Ensure the element name has the correct case and that there are no duplicate elements of the same name."
Using Microsoft Visual Basic for Applications (VBA) to URL encode data
Public Function EncodeHex(byVal sInput As String) As String Dim TempAns As String Dim CurChr As Long Dim x As Variant CurChr = 1 Do Until CurChr - 1 = Len(sInput) Select Case Asc(Mid(sInput, CurChr, 1)) Case 48 To 57, 65 To 90, 97 To 122 TempAns = TempAns & Mid(sInput, CurChr, 1) Case Else x = Hex(Asc(Mid(sInput, CurChr, 1))) If Len(CStr(x)) = 1 Then x = "0" & x TempAns = TempAns & "%" & x End Select CurChr = CurChr + 1 Loop EncodeHex = TempAns End Function
Using VBA to replace reserved characters with HTML entities
To run this code, add a reference to the "Microsoft HTML Object Library" in the VBA Editor.
Public Function EncodeHTML(ByVal sInput As String) As String On Error GoTo ErrHandle Dim HTMLDoc As New MicrosoftHTML.HTMLDocument HTMLDoc.Body.innerText = sInput EncodeHTML = HTMLDoc.Body.innerHTML GoTo AllDone ErrHandle: MsgBox "URLEncodeHTML error has occurred" & vbCrLf & vbCrLf & _ "Error Source: EncodeHTML " & vbCrLf & _ "Error Number: " & Err.Number & vbCrLf & _ "Error Description: " & Err.Description, vbCritical, "An Error has Occurred!" AllDone: On Error Resume Next Set oHTMLFile = Nothing End Function
Using SQL Server to replace reserved characters with HTML entities
SELECT 'This & that value are < the other.' FOR XML PATH('')
Returns:
This & that value are < the other.
Tables with XML format columns
Table | Column |
---|---|
BankTransactions
|
LineItems
|
Contacts
|
Addresses
|
Phones
|
|
Persons
|
|
ContactGroups
|
Contacts
|
CreditNotes
|
LineItems
|
Allocations
|
|
ExpenseClaims
|
Receipts
|
Payments
|
|
Invoices
|
LineItems
|
Payments
|
|
CreditNotes
|
|
Prepayments
|
|
Overpayments
|
|
ManualJournals
|
JournalLines
|
Organisation
|
Addresses
|
Phones
|
|
ExternalLinks
|
|
Prepayments
|
LineItems
|
Allocations
|
|
PurchaseOrders
|
LineItems
|
Quotes
|
LineItems
|
Receipts
|
LineItems
|
RepeatingInvoices
|
LineItems
|
TaxRates
|
TaxComponents
|
TrackingCategories
|
Options
|
Attachments
Use the Xero ODBC driver to retrieve attachments from these tables:
Accounts
BankTransactions
BankTransfers
Contacts
CreditNotes
Invoices
ManualJournals
PurchaseOrders
Quotes
Receipts
RepeatingInvoices
Example: downloading an attachment
This VBA code sample downloads an invoice attachment. The attachment is a JPEG file.
Sub GETInvoiceImage() Dim c As New ADODB.Connection Dim r As New ADODB.Recordset Dim st As New ADODB.Stream Dim arInputByte() As Byte Dim FName As String Dim i As Integer FName = "c:\l\WindMill3.jpg" c.Open "XeroDemo" r.Open "SELECT Code, RAWResponseBody from api where url = " _ & "'Invoices/4953d237-6cf2-4ef4-8f37-044aada0d594/Attachments/WindMill3.jpg'" _ & "and Method = 'GET'", c If Not r.EOF And r("Code") = 200 Then st.Type = adTypeBinary st.Open st.Write r(1) st.SaveToFile FName st.Close Debug.Print "File Saved" Else Debug.Print "File not found." End If r.Close c.Close Set r = Nothing Set c = Nothing End Sub
Example: uploading an attachment
Use the API
table to upload files. This VBA code sample uploads an invoice attachment.
Sub PUTInvoiceImage() Dim c As New ADODB.Connection Dim cm As New ADODB.Command Dim st As New ADODB.Stream Dim SQL As String Dim FName As String Dim pos As Long FName = "c:\l\WindMill8.jpg" SQL = "INSERT INTO api ( url, method, rawrequestbody ) " _ & " VALUES( 'Invoices/4953d237-6cf2-4ef4-8f37-044aada0d594/Attachments/" pos = 0 Do While InStr(pos + 1, FName, "\", vbBinaryCompare) > 0 pos = InStr(pos + 1, FName, "\", vbBinaryCompare) Loop SQL = SQL & Right(FName, Len(FName) - pos) SQL = SQL & "', 'PUT', ? )" Debug.Print SQL c.Open "XeroDemo" st.Type = adTypeBinary st.Open st.LoadFromFile FName With cm .ActiveConnection = c .CommandText = SQL .Parameters.Append .CreateParameter("RawRequestBody", adLongVarBinary, _ adParamInput, st.Size, st.Read) .Execute End With Debug.Print "Uploaded" c.Close st.Close Set c = Nothing End Sub
Online invoice and credit note attachments
Use this query string:
?IncludeOnline=true
to include your attachment in online invoices and credit notes. For example:
SQL = " INSERT INTO api ( url, method, rawrequestbody ) VALUES ( 'Invoices/4953d237-6cf2-4ef4-8f37-044aada0d594/Attachments/WindMill8.jpg?IncludeOnline=true' ) "
Further information
The Xero Invoice documentation says:
"You can upload up to 10 attachments (each up to 3 MB in size) per invoice, once the invoice has been created in Xero."
Exceeding this limit generates the error:
"[Easysoft ODBC-Xero Driver]ValidationException: A validation exception occurred. The file couldn't be uploaded because the API limit of 10 attachments has been exceeded for the document."
You can upload files that are greater than 3 MB in size (in our test, WindMill.jpg
was 5.5 MB). However, if you try to do this you may get:
"[Easysoft ODBC-Xero Driver]PayloadOversizeException: This request exceeds the maximum size limit. Refer to the documentation at https://developer.xero.com/documentation/oauth2/limits"
Or, if the Xero API ignores the request and returns a NULL
response to the Xero ODBC driver:
"[Easysoft ODBC-Xero Driver]server response 0 (null)"
Example: listing all invoice attachments
Sub GetListOfAttachmentsForAllInvoices() Dim c As New ADODB.Connection Dim i As New ADODB.Recordset Dim r As New ADODB.Recordset Dim SQL As String Dim RB As String Dim XMLDoc As New MicrosoftXML2.DOMDocument60 Dim XMLNode Dim XMLNodes Dim XMLString As String c.Open "XeroDevDemo" i.Open "SELECT InvoiceId from Invoices where HasAttachments <> 0", c Do While Not i.EOF SQL = "SELECT Code, XMLResponseBody FROM API WHERE URL='Invoices/" & i("InvoiceID") _ & "/Attachments/' AND Method='GET'" r.Open SQL, c If r("Code") = 200 Then XMLString = r("XMLResponseBody") XMLDoc.LoadXML XMLString If XMLDoc.parseError <> 0 Then Debug.Print XMLDoc.parseError.reason Else Set XMLNodes = XMLDoc.getElementsByTagName("FileName") If XMLNodes.length <> 0 Then Debug.Print "Invoice Id: " & i("InvoiceID") For Each XMLNode In XMLNodes Debug.Print " " & XMLNode.Text DoEvents Next End If End If r.Close i.MoveNext Loop i.Close c.Close Set r = Nothing Set i = Nothing Set c = Nothing End Sub
If you have a lot of invoice attachments, this code could take some time to complete.
Accounts
table
Supports INSERT
, UPDATE
, and DELETE
statements.
Microsoft SQL Server linked server examples: INSERT
, UPDATE
, and DELETE
statements
This SQL statement updates an accounts description:
EXEC('UPDATE Accounts SET Description=''Expenses incurred in relation to training staff2'' WHERE AccountId=''87e2c007-4a7c-43d7-a19d-b82dcf529313''') AT Xero
To check whether the update succeeded, run this query straight after:
EXEC('SELECT * FROM LastId') AT Xero
This statement creates a new account:
EXEC('INSERT INTO Accounts ( Code, Name, Type, Description, TaxType ) VALUES (''007'', ''Buchanan'' ,''OVERHEADS'', ''Steven Buchanan'', ''NONE'')') AT Xero
This statement deletes the account:
EXEC('DELETE FROM Accounts WHERE Code=''007''') AT Xero
BankTransactions
table
Supports INSERT
and UPDATE
statements.
SQL INSERT
example
INSERT INTO BankTransactions ( Type, BankAccount_Code, Contact_Name, [Date], CurrencyCode, LineItems ) values ( 'SPEND', '090', 'Espresso 31', '2024-02-08', 'USD', '<LineItems><LineItem><UnitAmount>50.00</UnitAmount> <TaxType>INPUT2</TaxType><TaxAmount>8.33</TaxAmount><LineAmount >50.00</LineAmount><AccountCode>429</AccountCode><Quantity> 1.0000</Quantity><LineItemID>e8059c2b-8fe5-4522-9a2f-40d352c4a80f</LineItemID> <AccountID>f96c9458-d724-47bf-8f74-a9d5726465ce</AccountID></LineItem></LineItems>' )
If the currency code you specify does not match that of the underlying bank account, it will be ignored. In the example, "USD" was specifed but the record's currency code is "GBP."
BankTransactionID", "Type", "ModifiedAfter", "BankAccount_AccountID", "BankAccount_Code", "BankAccount_Name", "Contact_ContactID", "Contact_Name", "Contact_Status", "Date", "Status", "LineAmountTypes", "LineItemCount", "SubTotal", "TotalTax", "Total", "UpdatedDateUTC", "CurrencyCode", "IsReconciled", "HasAttachments", "LineItems" "db19b6bf-a278-41ff-a0a8-438dd4aa338d", "SPEND", <Null>, "bd9e85e0-0478-433d-ae9f-0b3c4f04bfe4", "090", "Business Bank Account", "c82900a5-064c-46e1-9d8b-86404c6bfd01", "Espresso 31", "ACTIVE", 2024-02-08, "AUTHORISED", "Inclusive", 1, 41.67, 8.33, 50, 2024-02-08 08:42:43, "GBP", 0, 0, "<LineItems><LineItem><UnitAmount>50.00</UnitAmount><TaxType>INPUT2</TaxType> <TaxAmount>8.33</TaxAmount><LineAmount>50.00</LineAmount><AccountCode>429</AccountCode> <Quantity>1.0000</Quantity><LineItemID>ee0ad9fe-6c0f-40d5-a1f0-4578540af34c</LineItemID> <AccountID>f96c9458-d724-47bf-8f74-a9d5726465ce</AccountID></LineItem></LineItems>"
SQL UPDATE
example
UPDATE BankTransactions SET LineItems='<LineItems><LineItem><Description>Petrol in company car</Description><UnitAmount>59.00</UnitAmount> <TaxType>INPUT2</TaxType><TaxAmount>11.80</TaxAmount> <AccountCode>449</AccountCode><Quantity>2.0000</Quantity> <LineItemID>283b0044-7ebc-482e-b3b7-b58ef6812226</LineItemID> <AccountID>0be1631e-cc7e-4c27-951f-308c3307c0fe</AccountID></LineItem> </LineItems>' WHERE BankTransactionId='db7dcb47-4fb1-4190-9f56-911d7ee5c560'
Note You can't update BankTransactions
that have the DELETED
status or that have not been reconciled.
BankTransfers
table
Supports INSERT
statements.
SQL INSERT
example
INSERT INTO BankTransfers ( [Date], FromBankAccountCode, ToBankAccountCode, Amount, CurrencyRate ) values ( '2024-02-07', '091', '090', 1, 1 )
This example transfers 1 GBP from Account 091 to 090 at a rate of 1.
BatchPayments
table
Supports UPDATE
statements. Use this to set Xero batch payment status to DELETED
.
SQL UPDATE
example
Sets the specified batch payment status to DELETED
:
UPDATE BatchPayments SET Status='DELETED' WHERE BatchPaymentId= '4f7d624a-1899-469e-8121-2dc739fda3f7'
BrandingThemes
table
Supports INSERT
statements.
Example: apply branding theme to a payment service by using JSON
SELECT * FROM api WHERE url = 'BrandingThemes/201a3021-77de-495d-a233-1faaa40e2f64/PaymentService' AND Method = 'PUT' AND JSONRequestBody = ' { "PaymentServices": [{ "PaymentServiceID": "de5c978d-3cbf-4ebb-9ca9-20d7cb196ab1" }] }'
Contacts
tables
Supports INSERT
and UPDATE
statements.
Example: adding a contact
This sample code inserts a single contact who has one address and two phone numbers. Use XML to specify the address and phone number.
Sub AddContact() Dim c As New ADODB.Connection Dim r As New ADODB.Recordset Dim e As ADODB.Error Dim cmdADO As New ADODB.Command Dim prmText As New ADODB.Parameter Dim i As Integer Dim SQL As String Dim Phones As String Dim Addresses As String Addresses = "<Addresses><Address><AddressType>POBOX</AddressType><" _ & "AddressLine1>P O Box 3955</AddressLine1><AddressLine2>South Mailing Centre" _ & "</AddressLine2><City>Oaktown</City><PostalCode>OK12 3TN</PostalCode>" _ & "<AttentionTo>Human Resources Manager</AttentionTo></Address><Address><AddressType" _ & ">STREET</AddressType></Address></Addresses>" Phones = "<Phones><Phone><PhoneType>DDI</PhoneType></Phone><Phone><PhoneType>DEFAULT" _ & "</PhoneType><PhoneNumber>9191</PhoneNumber><PhoneAreaCode>555</PhoneAreaCode>" _ & "<PhoneCountryCode>01</PhoneCountryCode></Phone><Phone><PhoneType>FAX</PhoneType>" _ & "</Phone><Phone><PhoneType>MOBILE</PhoneType></Phone></Phones>" SQL = "INSERT INTO Contacts ( Name, Addresses, Phones ) VALUES ('example_customer',?,?)" On Error GoTo ErrHandle c.Open XeroDemo cmdADO.ActiveConnection = c cmdADO.CommandText = SQL Set prmText = cmdADO.CreateParameter(Addresses, adVarWChar, adParamInput, Len(Addresses), Addresses) cmdADO.Parameters.Append prmText Set prmText = cmdADO.CreateParameter(Phones, adVarWChar, adParamInput, Len(Phones), Phones) cmdADO.Parameters.Append prmText cmdADO.Execute r.Open "SELECT * FROM LastId", c If Not r.EOF Then Debug.Print "Inserted Contact ID: & r(0)" SQL = "SELECT * FROM Contacts WHERE ContactID='" & r(0) & "'" r.Close r.Open SQL, c ' Workaround for ADOdb LONGNVARCHAR issue. For i = 0 To r.Fields.Count - 1 If Not IsNull(r(i)) Then Debug.Print "r(i).Name & : & r(i) " Else Debug.Print "r(i).Name & : NULL " End If Next End If r.Close Set r = Nothing GoTo AllDone ErrHandle: For Each e In c.Errors Debug.Print " ADODB Error: & e.Description " Next AllDone: c.Close Set c = Nothing Debug.Print AddContact; Finished End Sub
Example: update a contact's primary email address
Sub UpdateContactEmailAddress() Dim c As New ADODB.Connection Dim r As New ADODB.Recordset Dim e As ADODB.Error Dim cmdADO As New ADODB.Command Dim prmText As New ADODB.Parameter Dim rc As Long Dim i As Integer Dim SQL As String SQL = "UPDATE Contacts SET EmailAddress='my_user@example.com' WHERE [Name]='example_customer'" ' On Error GoTo ErrHandle c.Open XeroDemo c.Execute SQL, rc Debug.Print "Records affected: & rc" r.Open "SELECT LastID from LastId ", c If Not r.EOF Then Debug.Print "UPDATE Contact ID: & r(0)" SQL = "SELECT [Name], EmailAddress FROM Contacts WHERE ContactID='" & r(0) & "'" r.Close r.Open SQL, c For i = 0 To r.Fields.Count - 1 If Not IsNull(r(i)) Then Debug.Print "r(i).Name & : & r(i) " Else Debug.Print "r(i).Name & : NULL " End If Next End If r.Close Set r = Nothing GoTo AllDone ErrHandle: For Each e In c.Errors Debug.Print "ADODB Error: & e.Description " Next AllDone: c.Close Set c = Nothing Debug.Print "UpdateContactEmailAddress; Finished " End Sub
ContactGroups
table
Supports INSERT
and UPDATE
statements.
SQL INSERT
example
This SQL statement inserts a contact into a contact group.
INSERT INTO ContactGroups ( Name, Contacts ) VALUES ( 'New Contact Group' , '<Contacts><Contact> <ContactID>af0091a9-82ef-4cac-9fd6-22c095ac6a58</ContactID> <Name>Hamilton Smith Ltd</Name></Contact></Contacts>' )
If you create a contact group without specifying any contacts, Xero automatically adds all contacts.
SQL UPDATE
example
This SQL statement updates a contact group's name.
UPDATE ContactGroups SET Name = 'Training 2' WHERE ContactGroupID = '91dbdc3f-86c5-4bfe-b227-5d1735945cea'
You can't currently update the Contacts
column by using the Xero ODBC driver.
Note: SELECT
queries
If you run:
SELECT * FROM ContactGroups
the Contacts
column is blank. This is a limitation in the Xero API. If you include a valid ContactGroupId
:
SELECT * FROM ContactGroups WHERE ContactGroupId='91dbdc3f-86c5-4bfe-b227-5d1735945cea'
your result set will be similar to:
"ContactGroupID", "ModifiedAfter", "Name", "Status", "Contacts" 91dbdc3f-86c5-4bfe-b227-5d1735945cea, <Null>, Training, ACTIVE, <Contacts><Contact><ContactID>af0091a9-82ef-4cac-9fd6-22c095ac6a58</ContactID> <Name>Hamilton Smith Ltd</Name></Contact> <Contact><ContactID>c523e12f-8b74-4d3a-bbd8-32d7a2f598b4</ContactID> <Name>City Limousines</Name></Contact> <Contact><ContactID>a852a44c-3d8f-4c4b-a628-3a2c2121b9b1</ContactID> <Name>Bank West</Name></Contact> <Contact><ContactID>847933f0-7c35-4e5b-b884-5f9df64c8e4b</ContactID> <Name>Port & Philip Freight</Name></Contact> <Contact><ContactID>94a82e91-53da-4f87-a417-63d6a1607ced</ContactID> <Name>Young Bros Transport</Name></Contact> <Contact><ContactID>a871a956-05b5-4e2a-9419-7aeb478ca647</ContactID> <Name>Ridgeway University</Name></Contact><Contact> <ContactID>2dd82f49-e818-4dd0-955b-b637ccaa5597</ContactID> <Name>City Agency</Name></Contact> <Contact><ContactID>b2c1f980-96c9-45ff-a42b-dca141936c6c</ContactID> <Name>Rex Media Group</Name></Contact></Contacts>
CreditNotes
table
Supports INSERT
and UPDATE
statements.
SQL INSERT
example
INSERT INTO CreditNotes ( [Date], ContactName, Type, CurrencyCode, CurrencyRate, LineItems ) values ( '2024-02-07', 'PowerDirect', 'ACCRECCREDIT', 'GBP', 1, '<LineItems><LineItem> <Description>Monthly electricity</Description><UnitAmount>105.75</UnitAmount> <TaxType>RRINPUT</TaxType><TaxAmount>5.04</TaxAmount><LineAmount>105.75</LineAmount> <AccountCode>445</AccountCode><Quantity>1.0000</Quantity> <LineItemID>79393360-50bb-467f-a552-dd2be361201d</LineItemID> <AccountID>d50842c3-af67-4233-b8c9-df3180f5b7bd</AccountID> </LineItem></LineItems>' )
SQL UPDATE
examples
This example changes the credited line to be half the amount credited.
UPDATE CreditNotes set SubTotal = 52.88, TotalTax = 2.52, Total = 52.88 + 2.52, LineItems = replace(replace(replace(LineItems, '<Quantity>1.0000</Quantity>', '<Quantity>0.5</Quantity>'), '<LineAmount>105.75</LineAmount>', '<LineAmount>52.88</LineAmount>'), '<TaxAmount>5.04</TaxAmount>', '<TaxAmount>2.52</TaxAmount>') WHERE CreditNoteId = '3812831b-b189-46e2-b8cc-3fee508aad83'
You can't delete a credit note but you can change its status to DELETED
:
UPDATE CreditNotes SET Status = 'DELETED' WHERE CreditNoteID = '75e794a1-d09b-46c9-9ef7-bd749a5f8028'
Currencies
table
Supports INSERT
statements.
The following SQL statements both insert the speoified currency code.
SQL INSERT
example
INSERT INTO Currencies ( Code ) VALUES ('USD')
SQL SELECT
example that calls Xero API
SELECT * FROM api WHERE url = 'Currencies' AND Method = 'PUT' AND XMLRequestBody = '<Currency><Code>EUR</Code></Currency>'
Employees
table
Supports: INSERT
statements.
Example: adding employees
This VBA example checks worksheet cells for employees who don't have a Xero ID. Such employees are then added to Xero and the cells are updated with the relevant employee ID. The spreadsheet contents are:
Employee Id | First Name | Surname | Xero ID |
---|---|---|---|
100 | Andrew | Fuller | |
101 | Janet | Leverling | |
102 | Margaret | Peacock |
After running the VBA, the spreadsheet contents become:
Employee Id | First Name | Surname | Xero ID |
---|---|---|---|
100 | Andrew | Fuller | 5faffe3f-f4d0-49b4-8f97-2840206de7aa |
101 | Janet | Leverling | 49e761e6-b4f0-4919-beca-5aee296c385f |
102 | Margaret | Peacock | ea61757f-0c98-4113-9941-e3920befa614 |
Only new employees (spreadsheet entries without an Employee ID) are added on subsequent runs.
Sub SendEmployeeToXero() Dim c As New ADODB.Connection Dim r As New ADODB.Recordset Dim rPos As Long Dim rc As Long Dim SQL As String Dim rInserted As Long c.Open "XeroDemo" rPos = 2 ' Walk down the sheet collecting the rows data rInserted = 0 Do While Not IsNull(Cells(rPos, 2)) And Cells(rPos, 2) <> "" If Not IsNull(Cells(rPos, 2)) And Cells(rPos, 2) <> "" _ And (IsNull(Cells(rPos, 4)) Or Cells(rPos, 4) = "") Then SQL = "INSERT INTO Employees ( FirstName, LastName ) VALUES " & _ "('" & Replace(Cells(rPos, 2), "'", "''") & "', '" & _ Replace(Cells(rPos, 3), "'", "''") & "')" c.Execute SQL, rc If rc <> 0 Then r.Open "select LastID from LastId", c If Not IsNull(r(0)) Then Cells(rPos, 4) = r(0) End If r.Close rInserted = rInserted + 1 End If End If rPos = rPos + 1 Loop MsgBox "Insert rows : " & rInserted c.Close Set r = Nothing Set c = Nothing End Sub
ExpenseClaims
table
Supports INSERT
statements.
Although ExpenseClaims
was deprecated in 2018 by Xero, the endpoint is still available.
SQL INSERT
example
INSERT INTO ExpenseClaims ( UserId, Receipts ) values ( '73f0cf2f-ede4-49ea-b93e-6723d9dfca32', '<Receipts> <ReceiptID> 7b67f5d8-bee4-42a2-a184-6742a2f79df1 </ReceiptID> </Receipts>' )
Note Not all Xero accounts have access to ExpenseClaims
.
Invoices
tables
Supports INSERT
and UPDATE
statements.
Example: adding a new invoice
This VBA code sample adds a new invoice. The invoice line items are added into the LineItems
in the XML format.
Sub CreateBasicInvoice() Dim c As New ADODB.Connection Dim r As New ADODB.Recordset Dim e As ADODB.Error Dim i As Integer Dim SQL As String ' This is a basic invoice insert. Notes: ' Date needs to be enclosed in [] as it is a reserved word ' Date format must be yyyy-mm-dd ' InvoiceNumber must be unique SQL = "INSERT INTO Invoices (InvoiceNumber, Type, ContactID, ContactName, [Date], LineItems ) " & _ "VALUES ( 'INV-0346', 'ACCREC', '9ce626d2-14ea-463c-9fff-6785ab5f9bfb', " & _ "'Boom FM', '2024-01-31', '<LineItems><LineItem>" & _ "<Description>Retainer for consulting work</Description><UnitAmount>500.00</UnitAmount>" & _ "<AccountCode>200</AccountCode><Quantity>3</Quantity>" & _ "<AccountID>c563b607-fb0e-4d06-9ddb-76fdeef20ae3</AccountID></LineItem></LineItems>')" c.Open XeroDemo On Error GoTo ErrHandle ' Insert the invoice c.Execute SQL ' If the INSERT succeeds, fetch all the columns. r.Open "SELECT * FROM LastId", c If Not r.EOF Then Debug.Print "Inserted Invoice ID: & r(0)" SQL = "SELECT * FROM Invoices WHERE InvoiceID='" & r(0) & "'" r.Close r.Open SQL, c ' Workaround for ADOdb LONGNVARCHAR issue. For i = 0 To r.Fields.Count - 1 If Not IsNull(r(i)) Then Debug.Print "r(i).Name & : & r(i)" Else Debug.Print "r(i).Name & : NULL" End If Next End If r.Close Set r = Nothing GoTo AllDone ErrHandle: For Each e In c.Errors Debug.Print "ADODB Error: & e.Description" Next AllDone: c.Close Set c = Nothing Debug.Print "CreateBasicInvoice Finished." End Sub
Example: adding an invoice line to the end of an invoice
Sub AddAdditionalLineToInvoice() Dim c As New ADODB.Connection Dim r As New ADODB.Recordset Dim e As ADODB.Error Dim cmdADO As New ADODB.Command Dim prmText As New ADODB.Parameter Dim li As String Dim SQL As String Dim AddItem As String ' Add a line to an existing invoice. AddItem = "<LineItem><ItemCode>BOOK</ItemCode><Description>Fish out of Water: " & _ "Finding Your Brand</Description><UnitAmount>19.95</UnitAmount><Item>" & _ "<ItemID>5b27339e-ecc8-40b6-ace3-0f25bdf5fd63</ItemID><Name>Fish out of Water:" & _ "Finding Your Brand</Name><Code>BOOK</Code></Item><Quantity>2</Quantity>" & _ "<AccountID>c563b607-fb0e-4d06-9ddb-76fdeef20ae3</AccountID></LineItem>" c.Open XeroDemo SQL = "SELECT LineItems FROM Invoices WHERE InvoiceNumber='INV-0346'" r.Open SQL, c If r.EOF Then Debug.Print "Invoice; missing" r.Close GoTo AllDone Else li = r(0) r.Close SQL = "UPDATE Invoices SET LineItems=? WHERE InvoiceNumber='INV-0346'" ' This puts the new line at the end of the items list. li = Replace(li, "</LineItems>, AddItem & </LineItems>") On Error GoTo ErrHandle cmdADO.ActiveConnection = c cmdADO.CommandText = SQL Set prmText = cmdADO.CreateParameter(LineItems, adVarWChar, adParamInput, Len(li), li) cmdADO.Parameters.Append prmText cmdADO.Execute End If GoTo AllDone ErrHandle: For Each e In c.Errors Debug.Print "ADODB Error: & e.Description" Next AllDone: c.Close Set c = Nothing Debug.Print "AddAdditionalLineToInvoice Finished." End Sub
Items
table
Supports INSERT
, UPDATE
, and DELETE
statements.
This table has one row per item.
Example: copying items
This VBA code sample copies items from a Microsoft Access table to Xero. The table structure is:
LocalProducts | |||
---|---|---|---|
Code | Name | Description | Price |
0017-99-9999-99-31-12-01 | Easysoft ODBC-Oracle Driver | 1 Machine | 999.99 |
0020-99-9999-99-31-12-01 | Easysoft dbExpress-ODBC Gateway | 1 Machine | 225 |
0022-99-9999-99-31-12-01 | Easysoft ODBC-Interbase Driver | 1 Machine | 750 |
0026-99-9999-99-31-12-01 | Easysoft ODBC-JDBC Gateway | 1 Machine | 6498 |
0028-99-9999-99-31-12-01 | Easysoft ODBC-Sybase Driver | 1 Machine | 1099 |
0039-99-9999-99-31-12-01 | Easysoft ODBC-Firebird Driver | 1 Machine | 450 |
0044-99-9999-99-31-12-01 | Easysoft ODBC-LINC Developer Driver | 1 Machine | 3199 |
The example inserts all items as if they are untracked and not purchased from a third party.
Sub LocalItemsIntoXero() Dim db As DAO.Database Dim rs As DAO.Recordset Dim c As New ADODB.Connection Dim r As New ADODB.Recordset Dim e As ADODB.Error Dim SQL As String ' Insert Access table data (LocalProducts) as Xero items Set db = CurrentDb Set rs = db.OpenRecordset(LocalProducts) c.Open XeroDemo Do While Not rs.EOF ' Check that the item does not already exist r.Open "SELECT COUNT(*) FROM Items WHERE Code='" & rs(Code) & "'", c If r(0) = 0 Then r.Close SQL = "insert into Items ( Code, Name, Description, SalesUnitPrice, IsPurchased, " & _ "SalesTaxType, SalesAccountCode, IsTrackedAsInventory ) values ( " & _ "'" & rs("Code") & "', '" & rs("Name") & "', '" & rs("Description") & "', " & _ rs("Price") & ", 0, 'OUTPUT2', '200', 0 )" c.Execute SQL r.Open "SELECT * FROM LastId", c If Not r.EOF Then Debug.Print Item ' & rs(Name) & ' insert as Item Id: & r(0) End If End If r.Close rs.MoveNext Loop rs.Close db.Close Set rs = Nothing Set db = Nothing c.Close Set c = Nothing End Sub
SQL UPDATE
example
UPDATE Items SET SalesUnitPrice=1000 WHERE ItemID='2033478a-79d4-409d-bfee-c3cc23c15884'
SQL DELETE
example
DELETE FROM Items WHERE ItemID='2033478a-79d4-409d-bfee-c3cc23c15884'
LinkedTransactions
table
Supports INSERT
, UPDATE
, and DELETE
statements.
SQL INSERT
example
INSERT INTO LinkedTransactions ( Type, SourceTransactionId, SourceLineItemId, SourceTransactionTypeCode, ContactId ) VALUES ( 'BILLABLEEXPENSE', 'b1b4f969-a6e3-478c-b0e9-e232d6d81724', '3e50e9ff-49da-4fc3-8f80-99f97248fef1', 'ACCPAY', '9ce626d2-14ea-463c-9fff-6785ab5f9bfb' )
SQL UPDATE
example
UPDATE LinkedTransactions SET ContactId='6f5b2926-224f-4ac5-9632-c0cd1e5551c5' WHERE LinkedTransactionId='70ce9c5d-790a-41f8-9695-079cd143de82'
SQL DELETE
example
DELETE FROM LinkedTransactions WHERE LinkedTransactionId='25977bea-2ed6-404c-b770-6c5e00176ac7'
ManualJournals
table
Supports INSERT
and UPDATE
statements.
SQL INSERT
example
INSERT INTO ManualJournals ( [Date], Narration, JournalLines ) VALUES ( '2024-02-06', 'This is a test', '<JournalLines><JournalLine> <Description>Coded incorrectly Computer Equipment should be Office Equipment</Description> <TaxType>NONE</TaxType><TaxAmount>0.00</TaxAmount><LineAmount>2569.00</LineAmount> <AccountCode>710</AccountCode><AccountID>a4602fb6-2e9d-4064-b318-c409032692ba </AccountID></JournalLine><JournalLine> <Description>Coded incorrectly Office Equipment should be Computer Equipment</Description> <TaxType>NONE</TaxType><TaxAmount>0.00</TaxAmount><LineAmount>-2569.00</LineAmount> <AccountCode>720</AccountCode><AccountID>8d1ae68b-1251-4b44-9d7a-639b3976935c</AccountID> </JournalLine></JournalLines>' )
Date is a reserved word, so enclose this value with square brackets.
SQL UPDATE
example
UPDATE ManualJournals SET Narration = 'Narration Updated' WHERE ManualJournalID = '1811d1fa-fa76-41a2-a0f5-1fa982017591'
PurchaseOrders
table
Supports INSERT
and UPDATE
statements.
SQL INSERT
example
INSERT INTO PurchaseOrders ( ContactID, [Date], Reference, CurrencyCode, CurrencyRate, LineItems) VALUES ( '699f0091-b127-4796-9f15-41a2f42abeb2', '2023-02-07', 'POTest 1', 'USD', 0.725361, '<LineItems><LineItem><ItemCode>GB9-White</ItemCode> <Description>Golf balls - white - 9-pack</Description> <UnitAmount>25.0000</UnitAmount><TaxType>INPUT2</TaxType> <TaxAmount>41.67</TaxAmount><LineAmount>250.00</LineAmount> <AccountCode>300</AccountCode><Quantity>10.0000</Quantity> <LineItemID>6a2045bd-c21c-454b-8e99-540ec96748f6</LineItemID> </LineItem></LineItems>' )
SQL UPDATE
example
UPDATE PurchaseOrders SET LineItems = REPLACE(LineItems, '<Quantity>10.0000</Quantity>', '<Quantity>2</Quantity>') WHERE PurchaseOrderId = 'd646f075-6bec-47a9-a59c-fe6e97c4f849'
Quotes
tables
Supports INSERT
and UPDATE
statements.
SQL INSERT
example
INSERT INTO Quotes ( [Date], ExpiryDue, CurrencyCode, CurrencyRate, ContactId, LineItems ) values ( '2024-02-01', '2024-03-01', 'USD', 1.3, '9ce626d2-14ea-463c-9fff-6785ab5f9bfb', '<LineItems><LineItem><LineItemID>2ce92ec0-a1bd-4782-8cdd-5edbfe498f90</LineItemID> <AccountCode>200</AccountCode><Description>Unlimited Clients LAN - 1 Server LAN</Description><UnitAmount>4800.0000</UnitAmount><DiscountRate>0.42</DiscountRate> <DiscountAmount>20.00</DiscountAmount><LineAmount>4780.00</LineAmount> <ItemCode>0017-99-9999-99-37-12-01</ItemCode><Quantity>1.0000</Quantity> <TaxAmount>0.00</TaxAmount><TaxType>NONE</TaxType></LineItem><LineItem> <LineItemID>51ec56a4-9663-475e-a6b9-1a93b484b0ef</LineItemID><AccountCode>200 </AccountCode><Description>Unlimited Machines on LAN</Description> <UnitAmount>12499.0000</UnitAmount><DiscountRate>0.16</DiscountRate> <DiscountAmount>20.00</DiscountAmount><LineAmount>12479.00</LineAmount> <ItemCode>0026-99-9999-99-32-12-01</ItemCode><Quantity>1.0000</Quantity> <TaxAmount>0.00</TaxAmount><TaxType>NONE</TaxType></LineItem></LineItems>' )
The previous example inserts a two-line quote for a customer referenced by the CustomerId
only. If you send a quote that uses an existing quote number, Xero will generate a new quote number for the quote.
Receipts
table
Supports INSERT
and UPDATE
statements.
Although Receipts
was deprecated in 2018 by Xero, the endpoint is still available.
SQL UPDATE
example
UPDATE Receipts SET LineItems = '<LineItems><LineItem><Description>Drinks & snacks for staff meeting</Description> <UnitAmount>35.20</UnitAmount><TaxType>INPUT2</TaxType> <TaxAmount>5.87</TaxAmount><LineAmount>35.20</LineAmount> <AccountCode>429</AccountCode><Quantity>1.0000</Quantity> <AccountID>f96c9458-d724-47bf-8f74-a9d5726465ce</AccountID> <DiscountEnteredAsPercent>true</DiscountEnteredAsPercent></LineItem></LineItems>' where ReceiptId = '7b67f5d8-bee4-42a2-a184-6742a2f79df1'
TaxRates
table
Supports INSERT
and UPDATE
statements.
SQL UPDATE
example
UPDATE TaxRates SET TaxComponents = replace(TaxComponents, '<Rate>17.5000</Rate>', '<Rate>1.7500</Rate>') WHERE Name = '17.5% (VAT on Income)'
TrackingCategories
table
Supports: INSERT
and UPDATE
statements.
SQL INSERT
example
INSERT INTO TrackingCategories ( Name ) VALUES ('Van Deliveries')
To create a new option for these tracking categories, get the TrackingCategoryID
:
SELECT LastID from LastId
then use the ID in a query similar to:
SELECT * FROM api WHERE url = 'TrackingCategories/201a3021-77de-495d-a233-1faaa40e2f64/Options' AND Method = 'PUT' AND XMLRequestBody = '<Name>TrackOpt 1</Name>'
which returns::
"URL", "Method", "Code", "XMLRequestBody", "Response", "XMLResponseBody" "TrackingCategories/201a3021-77de-495d-a233-1faaa40e2f64/Options", "PUT", 200, "<Name>TrackOpt 1</Name>", "OK", "<Response xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <Id>57a11291-f2b2-49fe-84f2-b8370af16278</Id> <Status>OK</Status> <ProviderName>Easysoft</ProviderName> <DateTimeUTC>2024-02-07T14:13:28.6181931Z</DateTimeUTC> </Response>"
to fetch the new tracking category option:
SELECT * FROM api WHERE url = 'TrackingCategories/201a3021-77de-495d-a233-1faaa40e2f64/Options' AND Method = 'PUT' AND JSONRequestBody = '{ "Name": "New Track 5" }'
Formatting XML
This VBA function formats XML to improve readability. Use the code with the other VBA samples in this guide.
Add a reference to the "Microsoft XML, v6.0" library before running the code.
Public Function PrettyPrintXML(ByRef xml As String, ByRef RemoveXMLFirstLine As Boolean) As String Dim Reader As New SAXXMLReader60 Dim Writer As New MXXMLWriter60 Dim blHasError As Boolean Dim XMLData As String On Error GoTo ErrHandle XMLData = xml Writer.Indent = True Writer.standalone = False Writer.omitXMLDeclaration = False Writer.Encoding = "utf-8" Set Reader.contentHandler = Writer Set Reader.dtdHandler = Writer Set Reader.ErrorHandler = Writer Call Reader.parse(XMLData) GoTo Finished ErrHandle: blHasError = True Finished: If blHasError Then PrettyPrintXML = "ERROR: " & vbCrLf & vbCrLf & XMLData Else XMLData = Writer.output If RemoveXMLFirstLine Then XMLData = Right(XMLData, Len(XMLData) - InStr(1, XMLData, ">", vbBinaryCompare) - 2) PrettyPrintXML = XMLData End If End Function
Using the Xero ODBC driver with SQL Server
To run INSERT
, UPDATE
, or DELETE
statements with a Xero ODBC driver-based linked server, set both these linked server properties to True
: Server Options > RPC and Server Options > RPC Out. If you are only using the API
table, leave these properties set to False
.
HTTP 400 Bad Request
If you execute multiple INSERT
, UPDATE
, or DELETE
statements in quick succession, the Xero API may return the 400 status and "Bad Request <no further details>." This seems to be a limitation of the Xero API. We worked around this by using a 0.5 second pause between statements.
If you get this error, contact the Easysoft Support team ().
SQL format and function support
The Easysoft ODBC-Xero driver supports the SQL-92 syntax:
- Use the
'yyyy-mm-dd'
or the{d 'yyyy-mm-dd'}
format if you send a date as a string. - Enclose column names that are reserved words with square brackets round the column name or quotation marks. For example,
"Name"
or[Date]
.
Supported string functions
Function | Description |
---|---|
ASCII(string_exp)
|
Returns the ASCII code value of the leftmost character of string_exp as an integer.
|
BIT_LENGTH(string_exp)
|
Returns the length in bits of the string expression. |
CHAR(code)
|
Returns the character that has the ASCII code value specified by code . The value of code should be between 0 and 255, otherwise the return value is data source-dependent.
|
CHAR_LENGTH(string_exp)
|
Returns the length in characters of the string expression, if the string expression is of a character data type, otherwise returns the length in bytes of the string expression (the smallest integer not less than the number of bits divided by 8). This is the same function as CHARACTER_LENGTH .
|
CHARACTER_LENGTH
|
Refer to CHAR_LENGTH
|
CONCAT(string_exp1, string_exp2)
|
Returns a character string that is the result of concatenating string_exp2 to string_exp1 . The resulting string is DBMS-dependent.
|
DIFFERENCE(string_exp1, string_exp2)
|
Returns an integer value that indicates the difference between the values returned by the SOUNDEX function for string_exp1 and string_exp2 .
|
INSERT(string_exp1, start, length, string_exp2)
|
Returns a character string where length characters have been deleted from string_exp1 beginning at start and where string_exp2 has been inserted into string_exp , beginning at start .
|
LCASE(string_exp)
|
Returns a string equal to that in string_exp with all uppercase characters converted to lowercase.
|
LEFT(string_exp, count)
|
Returns the leftmost count characters of string_exp .
|
LENGTH(string_exp)
|
Returns the number of characters in string_exp , excluding trailing blanks.
|
LOCATE(string_exp1, string_exp2[,start])
|
Returns the starting position of the first occurrence of string_exp1 within string_exp2 . The search for the first occurrence of string_exp1 begins with the first character position in string_exp2 unless the optional argument, start , is specified. If start is specified, the search begins with the character position indicated by the value of start . The first character position in string_exp2 is indicated by the value1. If string_exp1 is not found within string_exp2 , the value 0 is returned.
|
LTRIM(string_exp)
|
Returns the characters of string_exp , with leading blanks removed.
|
OCTET_LENGTH(string_exp)
|
Returns the length in bytes of the string expression. The result is the smallest integer not less than the number of bits divided by 8. |
POSITION(char_exp IN char_exp)
|
Returns the position of the first character expression in the second character expression. The result is an exact numeric with an implementation-defined precision and a scale of 0. |
REPEAT(string_exp, count)
|
Returns a character string composed of string_exp repeated count times.
|
REPLACE(string_exp1, string_exp2, string_exp3)
|
Search string_exp1 for occurrences of string_exp2 and replace with string_exp3 .
|
RIGHT(string_exp, count)
|
Returns the rightmost count characters of string_exp .
|
RTRIM(string_exp)
|
Returns the characters of string_exp with trailing blanks removed.
|
SOUNDEX(string_exp)
|
Returns a data source-dependent character string representing the sound of the words in string_exp .
|
SPACE(count)
|
Returns a character string consisting of count spaces.
|
SUBSTRING(string_exp, start, length)
|
Returns a character string that is derived from string_exp beginning at the character position specified by start for length characters.
|
TRIM
|
This is an SQL-92 version of the ODBC LTRIM and RTRIM functions.
|
UCASE(string_exp)
|
Returns a string equal to that in string_exp with all lowercase characters converted to uppercase.
|
Supported numeric functions
Function | Description |
---|---|
ABS(numeric_exp)
|
Returns the absolute value of numeric_exp .
|
ACOS(float_exp)
|
Returns the arccosine of float_exp as an angle, expressed in radians.
|
ASIN(float_exp)
|
Returns the arcsine of float_exp as an angle, expressed in radians.
|
ATAN(float_exp)
|
Returns the arctangent of float_exp as an angle, expressed in radians.
|
ATAN2(float_exp1, float_exp2) |
Returns the arctangent of the x and y coordinates, specified by float_exp1 and float_exp2 respectively, as an angle expressed in radians.
|
CEILING(numeric_exp)
|
Returns the smallest integer greater than or equal to numeric_exp .
|
COS(float_exp)
|
Returns the cosine of float_exp where float_exp is an angle expressed in radians.
|
COT(float_exp)
|
Returns the cotangent of float_exp where float_exp is an angle expressed in radians.
|
DEGREES(numeric_exp)
|
Returns the number of degrees converted from numeric_exp radians.
|
EXP(float_exp)
|
Returns the exponential value of float_exp .
|
FLOOR(numeric_exp)
|
Returns the largest integer less than or equal to numeric_exp .
|
LOG(float_exp)
|
Returns the natural logarithm of float_exp .
|
LOG10(float_exp)
|
Returns the base 10 logarithm of float_exp .
|
MOD(integer_exp1, integer_exp2)
|
Returns the remainder (modulus) of integer_exp1 divided by integer_exp2 .
|
PI()
|
Returns the constant value of pi as a floating point value. |
POWER(numeric_exp, integer_exp)
|
Returns the value of numeric_exp to the power of integer_exp .
|
RADIANS(numeric_exp)
|
Returns the number of radians converted from numeric_exp degrees.
|
RAND([integer_exp])
|
Returns a random floating point value using integer_exp as the optional seed value.
|
ROUND(numeric_exp, integer_exp)
|
Returns numeric_exp rounded to integer_exp places right of the decimal point. If integer_exp is negative, numeric_exp is rounded to integer_exp places to the left of the decimal point.
|
SIGN(numeric_exp)
|
Returns an indicator of the sign of numeric_exp . If numeric_exp is less than zero, -1 is returned. If numeric_exp equals zero, 0 is returned. If numeric_exp is greater than zero, 1 is returned.
|
SIN(float_exp)
|
Returns the sine of float_exp , where float_exp is an angle expressed in radians.
|
SQRT(float_exp)
|
Returns the square root of float_exp .
|
TAN(float_exp)
|
Returns the tangent of float_exp where float_exp is an angle expressed in radians.
|
TRUNCATE(numeric_exp, integer_exp)
|
Returns numeric_exp truncated to integer_exp places right of the decimal point. If integer_exp is negative, numeric_exp is truncated to integer_exp places to the left of the decimal point.
|
Supported date and time functions
Function | Description |
---|---|
CURRENT_DATE()
|
Returns the current date. |
CURRENT_TIME[(time-precision)]
|
Returns the current local time. The time-precision argument determines the seconds precision of the returned value.
|
CURRENT_TIMESTAMP[(timestamp-precision)]
|
Returns the current local date and local time as a timestamp value. The timestamp-precision argument determines the seconds precision of the returned timestamp.
|
CURDATE()
|
Returns the current date. |
CURTIME()
|
Returns the current local time. |
DAYNAME(date_exp)
|
Returns a character string containing the data source-specific name of the day for the day portion of date_exp .
|
DAYOFMONTH(date_exp)
|
Returns the day of the month based on the month field in date_exp as an integer value in the range 1-31.
|
DAYOFWEEK(date_exp)
|
Returns the day of the week based on the week field in date_exp as an integer value in the range of 1–7 where 1 represents Sunday.
|
DAYOFYEAR(date_exp)
|
Returns the day of the year based on the year field in date_exp as an integer value in the range of 1–366.
|
EXTRACT(extract-field FROM extract-sourc)
|
Returns the extract-field portion of the extract-source . The extract-source argument is a datetime or interval expression. The extract-field argument can be one of the YEAR , MONTH , DAY , HOUR , MINUTE , or SECOND keywords. The precision of the returned value is implementation-defined. The scale is 0 unless SECOND is specified, in which case the scale is not less that the fractional seconds precision of the extract-source field.
|
HOUR(time_exp)
|
Returns the hour based on the hour field in time_exp as an integer value in the range of 0–23.
|
MINUTE(time_exp)
|
Returns the minute based on the minute field in time_exp as an integer value in the range of 0–59.
|
MONTH(date_exp)
|
Returns the month based on the month field in date_exp as an integer value in the range 1–12.
|
MONTHNAME(date_exp)
|
Returns a character string containing the data source-specific name of the month for the month portion of date_exp .
|
NOW()
|
Returns the current date and time as a timestamp value. |
QUARTER(date_exp)
|
Returns the quarter in date_exp as an integer value in the range of 1–4.
|
SECOND(time_exp)
|
Returns the second based on the second field in time_exp as an integer value in the range of 0–59.
|
TIMESTAMPADD(interval, integer_exp, timestamp_exp)
|
Returns the timestamp calculated by adding integer_exp intervals of type interval to timestamp_exp . Valid values of interval are the following keywords: SQL_TSI_FRAC_SECOND , SQL_TSI_SECOND , SQL_TSI_MINUTE , SQL_TSI_HOUR , SQL_TSI_DAY , SQL_TSI_WEEK , SQL_TSI_MONTH , SQL_TSI_QUARTER , or SQL_TSI_YEAR where fractional seconds are expressed in billionths of a second. If time_stamp is a time value and interval specifies days, weeks, months, quarters, or years, the date portion of timestamp_exp is set to the current date before calculating the resulting timestamp. If timestamp_exp is a date value and interval specifies fractional seconds, seconds, minutes, or hours, the time portion of timestamp_exp is set to 0 before calculating the resulting timestamp. An application determines which intervals a data source supports by calling SQLGetInfo with the SQL_TIMEDATE_ADD_INTERVALS option.
|
TIMESTAMPDIFF(interval, timestamp_exp1, timestamp_exp2)
|
Returns the integer number of intervals of type interval by which timestamp_exp2 is greater than timestamp_exp1 . The keywords SQL_TSI_FRAC_SECOND , SQL_TSI_SECOND , SQL_TSI_MINUTE , SQL_TSI_HOUR , SQL_TSI_DAY , SQL_TSI_WEEK , SQL_TSI_MONTH , SQL_TSI_QUARTER , or SQL_TSI_YEAR are valid values of interval , where fractional seconds are expressed in billionths of a second. If either timestamp expression is a time value and interval specifies days, weeks, months, quarters, or years, the date portion of that timestamp is set to the current date before calculating the difference between timestamps. If either timestamp expression is a date value and interval specifies fractional seconds, seconds, minutes, or hours, the time portion of that timestamp is set to 0 before calculating the difference between timestamps. An application determines which intervals a data source supports by calling SQLGetInfo with the SQL_TIMEDATE_DIFF_INTERVALS option.
|
WEEK(date_exp)
|
Returns the week of the year based on the week field in date_exp as an integer value in the range of 1–53.
|
YEAR(date_exp)
|
Returns the year based on the year field in date_exp as an integer value. The range is data source-dependent.
|