Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

Съвети за използване на SQL Server със Salesforce

Съдържание

  1. Общ преглед
  2. Клауза WHERE
  3. Съединения на множество таблици
  4. Локална таблица, прикачена към отдалечена таблица
  5. Вмъкване, актуализиране и изтриване
  6. Актуализиране
  7. Актуализиране с параметри
  8. Вмъкване на нов запис и получаване на BLOB грешка
  9. Получаване на Salesforce Id за последния запис, който сте въвели
  10. Актуализиране на данните на SQL Server при промяна на данните на Salesforce
  11. Ленива проверка на схема
  12. Ограничения на доставчика на OLEDB за ODBC на Microsoft
  13. Как да намеря записи с емисия на ред (нов ред) в адреса за фактуриране?
  14. Мога ли да видя кои таблици са налични чрез софтуера Easysoft?
  15. Мога ли да видя кои колони са налични чрез софтуера Easysoft?
  16. Мога ли програмно да създам свързан сървър?

Общ преглед

Този документ дава някои съвети за използване на SQL Server със Salesforce. Компонентите, използвани за свързване на SQL Server към Salesforce, са свързан сървър към SQL Server и Easysoft Salesforce ODBC драйвер. Как свързвате SQL Server към Salesforce е описано в тази статия. За примерите в този документ използваното име на свързания сървър (което препращате във вашите SQL команди) е SF8.

Целият SQL в този документ е тестван срещу SQL Server 2017 и драйвера на Easysoft Salesforce ODBC версии от 2.0.0 до 2.0.7.

Функциите на SQL Server OPENQUERY и EXEC (EXECUTE ) бяха въведени в SQL Server 2008 и тези функции са съвместими с всички версии на SQL Server след 2008 г.

Написахме този документ в отговор на редица запитвания, получени от нашия екип за поддръжка относно свързването на SQL Server чрез Easysoft към Salesforce. Въпреки това, SQL примерите трябва да бъдат полезни и за връзки на свързан сървър, които използват различен ODBC драйвер и бекенд.

Ако искате да допринесете за този документ, моля, изпратете изпратеното си по имейл до .

клауза WHERE

Често срещан проблем, съобщен ни, е „Проста клауза WHERE отнема много време, за да върне само един ред“. Например:

изберете Id, First Name, LastName от SF8.SF.DBO.Contact, където Id='00346000002I95MAAS'

SQL Server преобразува горната заявка и я изпраща на Salesforce ODBC драйвера:

изберете Id, First Name, LastName от SF.DBO.Contact

Клаузата WHERE винаги се премахва, което принуждава ODBC драйвера да върне всички редове за тази таблица. След това SQL Server ги филтрира локално, за да ви даде необходимите редове. Изглежда няма значение каква клауза WHERE сте посочили, тя никога не се предава на ODBC драйвера.

Простото решение за това е да използвате SQL Server OPENQUERY функция вместо това. Например:

изберете * от OPENQUERY(SF8,'select Id, FirstName, LastName от SF.DBO.Contact, където Id=''00346000002I95MAAS'' ')

Целият SQL, който изпълнявате в OPENQUERY функцията се предава направо на драйвера, включително WHERE клауза.

Съединения на множество таблици

Ето просто свързване на две таблици, при което и двете таблици се връщат от свързания сървър.

изберете a.[Име], BillingStreet, c.[Име] от SF8.SF.DBO.Account a, SF8.SF.DBO.Contact c, където a.Id=c.AccountID и a[Name] като например a. 'United%'

SQL Server изпраща следните заявки към ODBC драйвера.

изберете * от акаунтизберете * от контакт

SQL Server прави това, за да получи списък с имена на колони и типове данни. След това продължава да изпраща тези заявки до ODBC драйвера.

ИЗБЕРЕТЕ "Tbl1001"."Id" "Col1042","Tbl1001"."Име" "Col1044","Tbl1001"."BillingStreet" "Col1046" ОТ "SF"."DBO"."Акаунт" "Tbl1001 " ORDER BY "Col1042" ASCSELECT "Tbl1003"."AccountId" "Col1057","Tbl1003"."Name" "Col1058" ОТ "SF"."DBO"."Contact" "Tbl1003" ORDER BY "Col<<1057" ASC /предварително> 

Данните от двете заявки се връщат в локални таблици, след което клаузата WHERE се поставя в таблицата Account и данните от двете таблици се обединяват и връщат.

Отново използването на OPENQUERY гарантира, че SQL, който пишете, се предава директно на ODBC драйвера, така че вместо това в SQL Server ще стартирате:

select * от OPENQUERY(SF8,'select a.[Име], BillingStreet, c.[Име] от SF.DBO.Account a, SF.DBO.Contact c, където a.Id=c.AccountID и a. [Име] като ''United%'' ')

Имате нужда от лека модификация, тъй като SQL Server не може да обработва множество колони с едно и също „Име“, така че трябва да преименувате една от тези колони. Например:

изберете * от OPENQUERY(SF8,'select a.[Име], BillingStreet, c.[Име] като пълно име от SF.DBO.Account a, SF.DBO.Contact c, където a.Id=c.AccountID и a.[Име] като ''United%'' ')

Това принуждава ODBC драйвера да обработва целия SQL наведнъж и да връща само необходимите резултати.

Локална таблица, прикачена към отдалечена таблица

В този пример локалната таблица е създадена чрез изпълнение.

изберете * в LocalAccount от SF8.SF.DBO.Account

Съединението на двете таблици сега изглежда така.

изберете a.[Name], BillingStreet, c.[Name] като пълно име от LocalAccount a, SF8.SF.DBO.Contact c, където a.Id=c.AccountID и a.[Name] като 'United%' 

Това кара SQL Server да изпрати следната заявка три пъти до ODBC драйвера.

изберете * от контакт

В поне една от тези заявки SQL Server иска всички данни в таблицата. След това SQL Server продължава да иска:

ИЗБЕРЕТЕ "Tbl1003"."Name" "Col1008" ОТ "SF"."DBO"."Contact" "Tbl1003" WHERE ?="Tbl1003"."AccountId"

След това SQL Server предава на ODBC драйвера списък с AccountIds от таблицата LocalAccount на мястото на "?" параметър, където колоната LocalAccount.[Name] съвпада с клаузата LIKE.

По-бърз начин, при който ODBC таблицата е втората таблица в заявката, е да получите само нужните колони от таблицата ODBC. Това може да стане с помощта на OPENQUERY функция. Например:

изберете a.[Име], BillingStreet, c.[Име] като пълно име от LocalAccount a, openquery(SF8,'select [Име], AccountId от SF.DBO.Contact') c, където a.Id=c. AccountID и [Име] като 'United%'

Докато това все още получава всички редове от таблицата с контакти, то получава само необходимите колони и следователно е по-бързо от стандартната заявка.

Друг възможен начин би бил използването на курсор и временна таблица. Например:

Започнете да декларирате @AccountId като varchar(20) да декларирате @SQL като varchar(1024) -- Създайте временна таблица за съхраняване на информацията за акаунта. Проверката на Id гарантира, че се връщат 0 реда данни, изберете * в #LocalContact от openquery(SF8,'select [Name], AccountId от SF.DBO.Contact, където Id=''000000000000000000'') -- Настройте декларирането на курсора selcur курсор за избор на отделен идентификатор от LocalAccount, където [Име] като 'United%' отваря selcur извличане следващо от selcur в @AccountId докато @@FETCH_STATUS=0 Започнете изберете @SQL ='вмъкнете в #LocalContact изберете [Име], ''' +@AccountId+'''' от OPENQUERY(SF8,''изберете [Име] от Контакт, където AccountId=''''' + @AccountId + ''''' '')' exec (@SQL) извлича следващо от selcur в @AccountId End close selcur освободи селcur -- След това се присъединете към вашите таблици и прегледайте данните, изберете a.[Name], BillingStreet, c.[Name] като пълно име от LocalAccount a, #LocalContact c, където a.Id=c.AccountID и и. a.[Име] като 'United%' -- Не забравяйте да премахнете временния раздел le drop table #LocalContact End

Този метод може да бъде няколко пъти по-бърз от OPENQUERY метод, показан в предишния пример, ако клаузата WHERE, която се предава на драйвера на Easysoft ODBC, използва индекс в Salesforce.

Вмъкване, актуализиране и изтриване

Ако изпълнявате заявка, която не е заявка SELECT, тогава най-добрият начин да направите това е да използвате SQL Server EXEC функция. Ако вашият свързан сървър не може да използва EXEC , ще получите съобщение, подобно на:

Сървърът „SF8“ не е конфигуриран за RPC.

За да използвате EXEC , щракнете с десния бутон върху вашия свързан сървър и изберете свойства. В секцията „Опции на сървъра“ задайте „RPC Out“ на „True“. След това можете да използвате EXEC функция.

Актуализиране

Да приемем, че имате това изявление в SQL Server:

АКТУАЛИЗИРАНЕ SF8.SF.DBO.Contact SET LastName='James' WHERE Id='00346000002I95MAAS'

SQL Server изпраща този SQL на ODBC драйвера.

изберете * от "SF"."DBO"."Контакт"

Всички записи се извличат и SQL Server след това изпраща това изявление на ODBC драйвера.

АКТУАЛИЗИРАНЕ "SF"."DBO"."Контакт" ЗАДАДЕТЕ "Фамилия"=? КЪДЕ "Id"=? И „Фамилия“=?

SQL Server прави това, за да гарантира, че записът няма да се промени между момента, в който сте изпълнили заявката, и момента на изпълнение на UPDATE. По-бърз метод е да използвате SQL Server EXEC функция. Например:

exec ('update SF.DBO.Contact set LastName=''James'', където Id=''00346000002I95MAAS''' ) на SF8 

SQL Server изпраща на ODBC драйвера целия низ, който сте въвели, така че заявката се изпълнява без да се избира цялата таблица.

Актуализиране с параметри

Кажете, че имате:

Begin declare @Id varchar(20)='00346000002I95MAAS' declare @LastName varchar(20)='James' update SF8.SF.DBO.Contact set LastName=@LastName, където Id=@IdEnd

Това работи точно по същия начин, както е описано в бележките за актуализиране. Синтаксисът обаче при използване на EXEC промени във функциите:

Begin declare @Id varchar(20)='00346000002I95MAAS' declare @LastName varchar(20)='James' exec ('update SF.DBO.Contact set LastName=? where Id=?', @LastName, @Id ) в SF8End

Където имате колона като LastName= сложихте ? на мястото на @LastName за да представи това, което ще предадете в параметъра. След това параметрите са изброени след израза UPDATE в реда, в който трябва да бъдат прочетени.

Вмъкване на нов запис и получаване на BLOB грешка

Да речем, че се опитвате да стартирате:

вмъкнете в SF8.SF.DBO.Contact ( FirstName, LastName ) стойности ('Easysoft','Test')

SQL Server изпраща това до ODBC драйвера:

изберете * от "SF"."DBO"."Контакт"

Това се прави два пъти. Първият път, когато се изпълнява, SQL Server проверява дали наборът от резултати може да се актуализира. При втория път, когато това се изпрати, SQL Server се премества към празен запис след връщането на последния запис и се опитва да направи позиционно INSERT, което дава грешка.

Доставчикът на OLE DB „MSDASQL“ за свързан сървър „SF8“ върна съобщение „Вмъкване или актуализиране на BLOB базирани на заявка стойности не се поддържа.“

Това съобщение се връща, тъй като позиционно вмъкване се опитва да вмъкне всички колони с NULL стойности с изключение на тези, които сте посочили във вашия израз INSERT, а в случая на таблицата с контакти има BLOB (област с дълъг текст в Salesforce), които доставчикът на OLE DB от Microsoft не поддържа. Драйверът на Easysoft Salesforce ODBC поддържа вмъкването на всички полета в Salesforce, където имате разрешение да вмъквате данни. За да заобиколите това, всичко, което трябва да направите, е да използвате EXEC.

exec ('вмъкнете в SF.DBO.Contact ( FirstName, LastName ) стойности (''Easysoft'',''Test'')') в SF8

Това просто изпраща INSERT директно до ODBC драйвера.

Получаване на Salesforce Id за последния запис, който сте вмъкнали

Няколко от нашите клиенти ни попитаха кой е най-лесният метод да получим идентификатора на реда, който току-що беше вмъкнат. Този пример показва как можете да получите идентификатора на последния запис, който сте вмъкнали в таблицата „Контакти“.

Begin declare @Id varchar(20)='00346000002I95MAAS' declare @FirstName varchar(20)='Easysoft' declare @LastName varchar(20)='Test' declare @FindTS varchar(22)(2convert ),GETUTCDATE(),120) декларира @SQL като varchar(1024) exec ('вмъкване в стойности на SF.DBO.Contact (FirstName, LastName) (?, ?)', @FirstName, @LastName) в SF8 изберете @SQL ='select Id from openquery(SF8, ''select top 1 c.Id from [User] u, Contact c, където u.Username=CURRENT_USER и c.CreatedDate>={ts '''''+@FindTS+''' ''} и c.CreatedById=u.Id подреждане по c.CreatedDate desc'')' exec (@SQL) Край

Когато се създаде запис в Salesforce, колоната „CreatedDate“ съдържа времева марка, която е UTC (координирано универсално време), записът е създаден, а не непременно текущата ви дата/час. @FindTs низът е зададен на UTC преди да се извърши INSERT, така че когато се извика SELECT за получаване на идентификатора, той разглежда само редовете, вмъкнати след @FindTS беше зададено.

По време на SELECT, Easysoft CURRENT_USER функцията се използва и за ограничаване на редовете, върнати от Salesforce само до потребителя, който е вмъкнал данните.

Актуализиране на данните на SQL Server, когато данните на Salesforce се променят

Този раздел ви показва как да създадете нова таблица на SQL Server въз основа на структурата на Salesforce таблица и да актуализирате тази таблица, когато има промени в тази таблица на Salesforce.

create процедура SFMakeLocal( @Link varchar(50), @Remote varchar(50), @Local varchar(50), @DropLocal int) като декларира @SQL като nvarchar(max) begin /* Импортира данните в локален таблица */ /* Задайте DropLocal на 1, за да премахнете локалната таблица, ако тя съществува */ ако OBJECT_ID(@Local, 'U') НЕ Е NULL започнете, ако (@DropLocal=1) започнете, задайте @SQL='DROP TABLE dbo. '+@Local exec ( @SQL) end else RAISERROR(15600,1,1, 'Локалната таблица вече съществува') RETURN крайна настройка @SQL='select * в dbo.'+@Local+' от OPENQUERY('+@Link+ ',''select * от '+@Remote+''')' exec(@SQL) изберете 'Local Table :'+@Local+' created.' end -- @Link Вашият свързан сървър със SQL Server -- @Remote Името на таблицата в Salesforce -- @Local Локалната таблица, в която искате данните да се съхраняват -- @DropLocal Задайте 1, ако таблицата съществува и искате да го пуснете

Изпълнете процедурата за копиране на структурата на записа от таблицата на Salesforce в локалната таблица и след това прехвърлете всички данни на Salesforce. Тази примерна команда използва таблицата Account. Този процес може да отнеме доста време в зависимост от количеството данни, които имате в таблицата на Salesforce.

SFMakeLocal 'SF8','Account','LocalAccount', 0

Аргументите са:

Аргумент Стойност
SF8 Името на свързания сървър на SQL Server.
Акаунт Името на таблицата в Salesforce, което искате да използвате, за да прочетете структурата и данните от тях.
LocalAccount Името на вашата таблица в SQL Server.
0 Тази стойност по подразбиране може да бъде променена на 1, ако добавите още персонализирани колони в Salesforce и искате да премахнете локалната таблица, за да я създадете отново с новите колони.

Следващата стъпка е да създадете още две процедури, които ще актуализират локалната таблица, ако някакви данни се актуализират или вмъкнат в таблицата на Salesforce:

създайте процедура SFUpdateTable ( @Link varchar(50), @Remote varchar(50), създайте процедура SFUpdateTable @Link varchar(50), @Remote varchar(50), @LocalTable varchar(50) като начало -- Актуализира данни в локална таблица въз основа на промени в Salesforce. декларирайте @TempDef като varchar(50)='##EasyTMP_' декларирайте @TempName като varchar(50) декларирайте @TempNumber като десетичен декларирайте @CTS като datetime=current_timestamp declare =@TTLimit в 100 декларира @MaxCreated като datetime declare @MaxModified като datetime декларира @SQL като nvarchar(max) декларира @RC като int -- Първата стъпка е да създадете глобална временна таблица set @TempNumber=datepart(yyyy,@000)0000 +datepart(mm,@CTS)*100000000+datepart(dd,@CTS)*1000000+datepart(hh,@CTS)*10000+datepart(mi,@CTS)*100+datepart(ss,@CTS) set @ TempName=@TempDef+cast(@TempNumber като varchar(14)) докато OBJECT_ID(@TempName, 'U') НЕ Е NULL начало RAISERROR (15600,1,1, 'Име на Temp, което вече се използва.') RETURN крайна настройка @SQL='избере * в '+@TempName+' от '+@ LocalTable+' където 1=0' създайте таблица #LocalDates ( ColName varchar(20), DTS datetime) set @sql='insert into #LocalDates изберете ''Created'', max(CreatedDate) от '+@LocalTable exec (@sql ) задайте @sql='insert into #LocalDates изберете ''Modified'', max(LastModifiedDate) от '+@LocalTable exec (@sql) изберете @MaxCreated=DTS от #LocalDates, където ColName='Created' изберете @MaxModified=DTS от #LocalDates, където ColName='Modified' падаща таблица #LocalDates задава @SQL='select * в '+@TempName+' от openquery('+@Link+',''select * от '+@Remote+', където CreatedDate>{ts '''''+convert(varchar(22),@MaxCreated,120)+''''''}'')' exec(@SQL) exec SFAppe ndFromTemp @LocalTable, @TempName set @SQL='drop table '+@TempName exec (@SQL) set @SQL='select * в '+@TempName+' от openquery('+@Link+',''select * from ' +@Remote+' където LastModifiedDate>{ts'''''+convert(varchar(22),@MaxModified,120)+'''''} и CreatedDate<={ts'''''+convert(varchar( 22),@MaxCreated,120)+''''''}'')' exec (@SQL) exec SFAppendFromTemp @LocalTable, @TempName set @SQL='drop table '+@TempName exec (@SQL) крайна процедура за създаване SFAppendFromTemp(@Local varchar(50), @TempName varchar(50)) as begin /* Използва временната таблица за импортиране на данните в локалната таблица, като се уверява, че всички дубликати са премахнати първо */ declare @Columns nvarchar(max) declare @ ColName varchar(50) декларира @SQL nvarchar(max) set @sql='delete от '+@Local+', където Id in ( изберете Id от '+@TempName+')' exec (@SQL) set @Columns='' деклариране на col_cursor cursor за избор на syscolumns.name от sysobjects вътрешно присъединяване syscolumns на sysobjects.id =syscolumns.id където sysobjects.xtype ='u' и sysobjects.name =@Local отворен col_cursor извличане на следващо от @ ColName докато @@FETCH_STATUS=0 Започнете набора @Columns=@Columns+'['+@ColName+']' извлича следващо от col_cursor в @ColName, ако (@@FETCH_STATUS=0) зададе @Columns=@Columns+', ' Край затвори col_cursor dislocate col_cursor set @sql='insert into '+@Local+' (' +@Columns+') select '+@Columns+' from '+@TempName exec (@sql) end -- Две процедури се използват за получаване на данните от отдалечена маса. 1) SFUpdateTable, който -- копира данните във временна таблица. 2) SFAppendFromTemp, който добавя -- данните от временната таблица в локалната таблица. -- @Link Вашият свързан сървър със SQL Server -- @Remote Името на таблицата в Salesforce -- @Local Локалната таблица, в която искате да се съхраняват данните -- @TempName Име на таблица, която може да се използва за временно съхраняване на данни. Не -- използвайте действително име на временна таблица като #temp, това няма да работи.

За да тествате това, стартирайте:

SFUpdateTable 'SF8', 'Account', 'LocalAccount'

Този пример може да се използва с всяка таблица на Salesforce, до която потребителят има достъп.

Лезиво валидиране на схема

В свойствата на свързания сървър на SQL Server, в секцията „Опции на сървъра“ има опция за „Ленива проверка на схемата“. По подразбиране това е зададено на FALSE, което кара SQL Server да изпраща два пъти оператори SELECT. При първото изпращане на заявката SQL Server използва данните, предадени обратно, за да натрупа метаданни за вашия набор от резултати. След това заявката се изпраща отново. Това е доста скъпо режийно, така че Easysoft би препоръчал да зададете "Lazy Schema Validation" на TRUE, което означава, че се изпраща само една заявка, извличайки както метаданните, така и набора от резултати наведнъж. Това също така спестява броя на извършените извиквания на Salesforce API.

Ограничения на OLEDB на Microsoft за доставчик на ODBC

Подробности за ограниченията на доставчика на OLEDB за ODBC можете да намерите на:

https://msdn.microsoft.com/en-us/library/ms719628(v=vs.85).aspx

Как да намеря записи с емисия на ред (нов ред) в адреса за фактуриране?

Като използвате някои от вътрешните функции на драйвера на Easysoft, можете лесно да намерите записи, където адресът за фактуриране има ред в записа. Например:

select * from openquery(sf8,'select Id, Name, {fn POSITION({fn CHAR(10)} IN BillingStreet)} LinePos from Account where {fn POSITION({fn CHAR(10)} IN BillingStreet)} >0')

POSITION(x) Тази функция търси позицията на x в посочената колона.

CHAR(X) Тази функция връща символа с ASCII стойност на x .

Повече информация за функциите, налични в нашия Salesforce ODBC драйвер, можете да намерите тук

Мога ли да видя кои таблици са налични чрез софтуера Easysoft?

За да получите списък с таблици, до които имате достъп, изпълнете:

select * from openquery(SF8,'select TABLE_NAME from INFO_SCHEMA.TABLES')

Мога ли да видя кои колони са налични чрез софтуера Easysoft?

Можете да получите списък с колони, които са в таблицата, като изпълните:

изберете * от openquery(SF8,'select * от INFO_SCHEMA.COLUMNS, където TABLE_NAME=''Account'' ')

Използвайки този метод, можете да получите само списък с колоните, които принадлежат на таблицата, която сте посочили в клаузата TABLE_NAME WHERE. Ако искате да видите пълен списък с колони за всички таблици, изпълнете:

започнете деклариране на @Table nvarchar(max) декларирайте курсора на таблица_курсор за избор на TABLE_NAME от openquery(SF8,'select TABLE_NAME от INFO_SCHEMA.TABLES') отваряне на table_cursor извличане на следващо място от table_cursor в @Table докато @@FETCH_STATUS ext. изберете * от INFO_SCHEMA.COLUMNS където TABLE_NAME=?', @Table) при SF8 извличане следващо от table_cursor в @Table End затваряне table_cursor освобождаване table_cursorend

Мога ли програмно да създам свързан сървър?

да. Има много примери за това в мрежата, например:

http://www.sqlservercentral.com/articles/Linked+Servers/142270/?utm_source=SSC


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Връщане на съхранени процедури и функции в база данни на SQL Server:РУТИНИ (T-SQL примери)

  2. Заобиколно решение за DATEDIFF() игнориране на SET DATEFIRST в SQL Server (пример за T-SQL)

  3. Как да премахнете частта от времето на стойност за дата и час (SQL Server)?

  4. Кой е най-добрият начин за пагиниране на резултатите в SQL Server

  5. Как да намерите имена на колони за всички таблици във всички бази данни в SQL Server