Pesquisar este blog

domingo, 26 de junho de 2011

Automação de impressoras térmicas diretamente pelo SQL Server

*Este artigo se aplica a versões 2005 ou superior do SQL Server. Na versão 2000, haverá restrições de 8000 caracteres na geração de arquivos, devido a limitação do varchar(max) do SQL 2000.

       O título pode soar um tanto estranho. Mas o fato é que esta se revelou uma grande solução “surpresa” durante o desenvolvimento de um projeto de automação através de coletores de dados.

       Para explicar melhor o contexto onde isto foi adotado, tudo começou durante a implantação de um projeto de automação na conferência de mercadorias, confecção de embalagens e expedição de volumes. Adotamos 3 coletores ARGOX PT-60 (fig.1) com Windows CE 5.0 e conexão wireless e 3 impressoras ZEBRA GK420t (fig.2) instaladas em um único computador dedicado, compartilhando as impressoras pela rede.                      

Fig.1 Coletor Argox PT-60 Fig.2 Impressora Térmica ZEBRA GK420t

       O sistema, nomeado ARKAB, foi desenvolvido em vb.net utilizando o MS Compact framework. Basicamente, o sistema atuava de forma on-line com o servidor SQL, buscando dados referente os pedidos de venda, e alimentando tabelas durante a conferência, possibilitando que dois operadores pudessem conferir o mesmo pedido.

        Este sistema permite conferir as mercadorias que estão no pedido de venda. O separador pega todos os produtos utilizando o romaneio de separação (fig.3), e entrega em um carrinho para o conferente. Este identifica o pedido no coletor através de código de barras (fig.3), identifica-se através do seu crachá pessoal e também identifica qual impressora irá utilizar (código de barras na impressora, conf. fig.4).

 

image image
Fig.3 Romaneio de Separação Fig.4 Identificação da impressora

     Mas aí surgiram problemas, que prejudicaram o funcionamento do projeto. Durante o final do mês, a empresa realiza muito processamento no servidor na geração de lotes contábeis, fechamentos fiscais, emissão de DREs pesadas e abarrotadas de dados. E os coletores começaram a ficar muito lentos, prejudicando significativamente a performance da equipe de separação.

         Outro problema que ocorria sempre era ao enviar uma impressão pela rede. De alguma forma, o Windows CE exibe uma messagebox com o resultado do comando de impressão ao usuário, o que atrapalha (e muito!) durante a conferência. A mensagem aparece na tela, o usuário não percebe, e ele bipa um produto. Como no final do comando sempre tem um ENTER, a tela de mensagem é fechada, e o usuário nem teria percebido que aquele produto bipado somente fechou a mensagem, e não foi processado pelo software. Isto acontecia por que eu gerava um arquivo texto temporário no coletor, e o copiava pela rede diretamente para a impressora, e o próprio Windows CE gerencia esta mensagem, o que parece não ser possível desativar.

image

          Para resolver isto, modifiquei o sistema do coletor, fazendo com que carregasse em DATASET todos os dados necessários para realizar a conferência, de forma que acessasse o banco de dados duas vezes (na abertura e no fechamento da conferência), e não mais em cada operação. O aumento de performance foi absoluto, o coletor não dependia mais da rede para ter um bom desempenho ou não. Mas ainda restava a etiqueta. Como fazer a impressão de forma que não aparecesse esta mensagem de status de impressão ao usuário?

Resolvi então fazer a impressão da etiqueta térmica utliizando o próprio SQL Server, de forma que o servidor enviasse o comando para a impressora, e não mais o coletor. A solução aparentemente muito simples e funcional me fez perceber que podemos fazer qualquer sistema que utilize base SQL Server imprimir diretamente em impressoras térmicas de linguagem específica (PPLA, PPLB, ZPL, etc).

Para isso, vamos dividir esta informação em três partes fundamentais: geração dos dados da etiqueta, salvar estes dados em um arquivo texto e finalmente copiar este arquivo diretamente à impressora desejada pela rede.

1. Geração dos dados da etiqueta

O primeiro procedimento que montei é o que realiza a busca de todas as informações no banco de dados para a impressão da etiqueta, e monta dinamicamente todos os comandos ZPL necessários para a impressão da etiqueta:

Code Snippet
  1. -- set nocount on
  2. -- exec spArkabEtiqueta 9
  3. create proc  [dbo].[spArkabEtiqueta]
  4.   @id_volume int
  5. , @cd_impressora int
  6. as
  7.  
  8.   /*
  9.   Autor: Fabiano Cores
  10.   Data : 06/2011
  11.   Objetivo: Gera a etiqueta através de comandos ZPL, salva em arquivo
  12.   através de automação OLE e lança o arquivo diretamente para a impressora
  13.   térmica na rede através de simples compartilhamento, somente copiando
  14.   o arquivo para o dispositivo (como \\pc-na-rede\nome_imp_zebra)
  15.   */
  16.  
  17.   declare @t table (texto varchar(8000) null, ordem int not null identity)
  18.   
  19.   declare @cd_empresa     int
  20.   declare @nr_pedido      int
  21.   declare @nr_volume      int
  22.   declare @qt_volume      int
  23.   declare @cd_usuario     int
  24.   declare @qt_pecas       int
  25.   declare @cliente        varchar(60)
  26.   declare @transportadora varchar(60)
  27.   declare @endereco       varchar(200)
  28.   declare @complemento    varchar(200)
  29.   declare @pedido         varchar(20)
  30.   declare @volume         varchar(20)
  31.   declare @responsavel    varchar(50)
  32.   declare @data           varchar(20)
  33.   declare @quantidade     varchar(20)
  34.   declare @cdb            varchar(50)
  35.   declare @vtexto         varchar(8000)
  36.   declare @texto          varchar(max)
  37.   declare @diretorio      varchar(255)
  38.   declare @arquivo        varchar(100)
  39.   declare @origem         varchar(500)
  40.   declare @destino        varchar(500)
  41.   
  42.   select @cd_empresa = cd_empresa
  43.        , @nr_pedido  = nr_pedido
  44.        , @nr_volume  = nr_volume
  45.        , @cd_usuario = cd_usuario
  46.        , @cdb        = cdb
  47.     from ArkabVolume
  48.    where id_volume   = @id_volume
  49.    
  50.   select @qt_pecas = sum(qt_item)
  51.     from arkabvolumeitem
  52.    where id_Volume = @id_volume
  53.   
  54.   select @qt_volume = count(*)
  55.     from ArkabVolume
  56.    where cd_empresa = @cd_empresa
  57.      and nr_pedido  = @nr_pedido
  58.    
  59.   select @cliente = rtrim(cadastro.razao)
  60.        , @transportadora = isnull(rtrim(transp.razao),'')
  61.        , @endereco = rtrim(cadastro.endereco)
  62.        , @complemento = rtrim(ltrim( rtrim(isnull(cadastro.complemento, ''))
  63.            + ' ' + rtrim(cidade.nome) + '/' + rtrim(cidade.cd_estado)
  64.            + ' - ' + left(rtrim(cadastro.cep),5) + '-' + right(rtrim(cadastro.cep),3)))
  65.        , @pedido = right('000000' + rtrim(@nr_pedido), 6)
  66.        , @volume = right('000' + rtrim(@nr_volume),3)--  + '/' + right('00' + rtrim(@qt_volume),2)
  67.        , @responsavel = rtrim(usuario.login)
  68.        , @data = convert(char(10), getdate(), 103) + ' '
  69.          + right('00' + rtrim(datepart(hour, getdate())),2) + 'h'
  70.        , @quantidade = rtrim(@qt_pecas) + ' PC'
  71.        
  72.     from cadastro, cidade, usuario, pedidovenda, cadastro transp
  73.    where pedidovenda.cd_cadastro = cadastro.cd_cadastro
  74.      and cidade.cd_Cidade = cadastro.cd_cidade
  75.      and pedidovenda.cd_empresa = @cd_empresa
  76.      and pedidovenda.nr_pedido  = @nr_pedido
  77.      and usuario.cd_usuario = @cd_usuario
  78.      and pedidovenda.cd_transportador *= transp.cd_cadastro
  79.      
  80.   select @texto = '
  81. ^XA
  82. ^MD10
  83. ^LT0
  84. ^JMA^FS
  85. ^MUd,200,200
  86. ^LH6,0
  87. ^FO20,7
  88. ^GB780,625,5,,0
  89. ^FS
  90. ^FO20,70
  91. ^GB645,120,5,,0
  92. ^FS
  93. ^FO20,7
  94. ^GB780,70,70,,0
  95. ^FS
  96. ^FO660,70
  97. ^GB140,562,5,,0
  98. ^FS
  99. ^FO20,275
  100. ^GB235,160,5,,0
  101. ^FS
  102. ^FO30,305
  103. ^GB215,120,120,,0
  104. ^FS
  105. ^FO250,275
  106. ^GB180,160,5,,0
  107. ^FS
  108. ^FO260,305
  109. ^GB160,120,120,,0
  110. ^FS
  111. ^FO425,275
  112. ^GB240,85,5,,0
  113. ^FS
  114. ^FO425,355
  115. ^GB240,80,5,,0
  116. ^FS
  117. ^FO425,430
  118. ^GB240,75,5,,0
  119. ^FS
  120. ^FO425,500
  121. ^GB240,132,5,,0
  122. ^FS
  123. ^FO90,20,0
  124. ^ATN,30,20
  125. ^FR
  126. ^FD
  127. DECORLUX MATERIAL ELETRICO LTDA
  128. ^FS
  129. ^FO30,80,0
  130. ^AQN,20,10
  131. ^FD
  132. CLIENTE
  133. ^FS
  134. ^FO30,103,0
  135. ^ATN,30,20
  136. ^FD
  137. ' + left(rtrim(@cliente), 29) + '
  138. ^FS
  139. ^FO30,138,0
  140. ^ATN,30,20
  141. ^FD
  142. ' + substring(@cliente, 30, 29) + '
  143. ^FS
  144. ^FO30,138,0
  145. ^ASN,30,20
  146. ^FD
  147. ^FS
  148. ^FO30,200,0
  149. ^AQN,20,10
  150. ^FD
  151. TRANSPORTADORA
  152. ^FS
  153. ^FO30,223,0
  154. ^ASN,30,20
  155. ^FD
  156. ' + rtrim(@transportadora) + '
  157. ^FS
  158. ^FO30,280,0
  159. ^AQN,20,10
  160. ^FD
  161. PEDIDO DE VENDA
  162. ^FS
  163. ^FO40,290,0
  164. ^AVN,120,100
  165. ^FR
  166. ^FD
  167. ' + rtrim(@pedido) + '
  168. ^FS
  169. ^FO265,280,0
  170. ^AQN,20,10
  171. ^FD
  172. VOLUME
  173. ^FS
  174. ^FO290,290,0
  175. ^AVN,120,100
  176. ^FR
  177. ^FD
  178. ' + rtrim(@volume) + '
  179. ^FS
  180. ^FO435,280,0
  181. ^AQN,20,10
  182. ^FD
  183. RESPONSAVEL
  184. ^FS
  185. ^FO435,310,0
  186. ^ASN,20,10
  187. ^FD
  188. ' + rtrim(@responsavel) + '
  189. ^FS
  190.  
  191. ^FO435,360,0
  192. ^AQN,20,10
  193. ^FD
  194. DATA
  195. ^FS
  196.  
  197. ^FO435,385,0
  198. ^ASN,30,20
  199. ^FD
  200. ' + rtrim(@data) + '
  201. ^FS
  202.  
  203. ^FO435,435,0
  204. ^AQN,20,10
  205. ^FD
  206. QUANTIDADE
  207. ^FS
  208.  
  209. ^FO435,460,0
  210. ^ASN,30,20
  211. ^FD
  212. ' + rtrim(@quantidade) + '
  213. ^FS
  214.  
  215. ^FO30,435,0
  216. ^AQN,20,10
  217. ^FD
  218. NOTA FISCAL E VISTO
  219. ^FS
  220.  
  221. ^FO690,97
  222. ^BY2
  223. ^BCR,100,Y,N,N
  224. ^FD
  225. ' + rtrim(@cdb) + '
  226. ^FS
  227. ^XZ'
  228.  
  229.   -- Diretorio para gravar o arquivo temporário
  230.   set @diretorio = 'D:\Arkab\impressoes\'
  231.   
  232.   -- Definição do nome do arquivo, coloca dia, mes, ano,
  233.   -- hora, minuto, segundo e ID do volume.
  234.   select @arquivo = 'tmp'
  235.                   + right('00' + rtrim(datepart(day, getdate())),2)
  236.                   + right('00' + rtrim(datepart(month, getdate())),2)
  237.                   + rtrim(datepart(year, getdate()))
  238.                   + right('00' + rtrim(datepart(hour, getdate())),2)
  239.                   + right('00' + rtrim(datepart(minute, getdate())),2)
  240.                   + right('00' + rtrim(datepart(second, getdate())),2)
  241.                   + '_vol_' + rtrim(@id_volume) + '.txt'
  242.                   
  243.   -- Gravo o arquivo
  244.   exec spArkabGravaArquivo
  245.     @texto, @diretorio, @arquivo
  246.     
  247.   -- Definição da origem e destino do arquivo salvo.
  248.   select @origem = rtrim(@diretorio) + rtrim(@arquivo)
  249.  
  250.   -- Algo como '\\PC-CONF01\ZEBRA-SEP1'
  251.   select @destino = caminho_de_rede
  252.     from ArkabImpressora
  253.    where cd_impressora = @cd_impressora
  254.   
  255.   -- Envio o arquivo texto pela rede diretamente na impressora térmica.
  256.   exec spArkabCopiaArquivo
  257.     @origem, @destino

Este procedimento coleta todos os dados, concatena em um varchar(max), e passa esta string para a segunda etapa, que é gravar este texto em um arquivo em uma pasta específica no servidor.

Exemplo do texto gerado pelo procedimento:

^XA
^MD10
^LT0
^JMA^FS
^MUd,200,200
^LH6,0
^FO20,7
^GB780,625,5,,0
^FS
^FO20,70
^GB645,120,5,,0
^FS
^FO20,7
^GB780,70,70,,0
^FS
^FO660,70
^GB140,562,5,,0
^FS
^FO20,275
^GB235,160,5,,0
^FS
^FO30,305
^GB215,120,120,,0
^FS
^FO250,275
^GB180,160,5,,0
^FS
^FO260,305
^GB160,120,120,,0
^FS
^FO425,275
^GB240,85,5,,0
^FS
^FO425,355
^GB240,80,5,,0
^FS
^FO425,430
^GB240,75,5,,0
^FS
^FO425,500
^GB240,132,5,,0
^FS
^FO90,20,0
^ATN,30,20
^FR
^FD
DECORLUX MATERIAL ELETRICO LTDA
^FS
^FO30,80,0
^AQN,20,10
^FD
CLIENTE
^FS
^FO30,103,0
^ATN,30,20
^FD
TORNADO INDUSTRIA E PECAS LTD
^FS
^FO30,138,0
^ATN,30,20
^FD
A
^FS
^FO30,138,0
^ASN,30,20
^FD
^FS
^FO30,200,0
^AQN,20,10
^FD
TRANSPORTADORA
^FS
^FO30,223,0
^ASN,30,20
^FD
NATALIN DA SILVA RAMOS
^FS
^FO30,280,0
^AQN,20,10
^FD
PEDIDO DE VENDA
^FS
^FO40,290,0
^AVN,120,100
^FR
^FD
056783
^FS
^FO265,280,0
^AQN,20,10
^FD
VOLUME
^FS
^FO290,290,0
^AVN,120,100
^FR
^FD
009
^FS
^FO435,280,0
^AQN,20,10
^FD
RESPONSAVEL
^FS
^FO435,310,0
^ASN,20,10
^FD
AUTOMATICO
^FS

^FO435,360,0
^AQN,20,10
^FD
DATA
^FS

^FO435,385,0
^ASN,30,20
^FD
26/06/2011 21h
^FS

^FO435,435,0
^AQN,20,10
^FD
QUANTIDADE
^FS

^FO435,460,0
^ASN,30,20
^FD
1 PC
^FS

^FO30,435,0
^AQN,20,10
^FD
NOTA FISCAL E VISTO
^FS

^FO690,97
^BY2
^BCR,100,Y,N,N
^FD
00020567830099699335
^FS
^XZ

Veja que depois defino qual o destino final do arquivo (no caso, uma impressora zebra na rede). No caso do sistema Arkab, a definição da impressora é dinâmica, no momento da abertura da conferência o usuário seleciona qual irá utilizar. Ao imprimir a etiqueta, o sistema passa para o procedimento como parâmetro (@cd_impressora) qual será a impressora que deverá enviar o comando. Uma simples tabela permite referenciar o código desta impressora ao seu caminho de rede.

E logo no final, temos o procedimento spArkabCopiaArquivo, que faz a cópia do arquivo do servidor para a impressora utilizando a rede. Vamos então falar de cada um deles agora.

 

2. spArkabGravaArquivo - Este procedimento grava o texto desejado em um arquivo em disco:

Code Snippet
  1. create proc spArkabGravaArquivo
  2.   @texto varchar(max), --8000 in SQL Server 2000
  3.   @diretorio varchar(255),
  4.   @arquivo varchar(100)
  5.  
  6. as
  7.  
  8.   /*
  9.   Autor: Fabiano Cores
  10.   Data : 06/2011
  11.   Objetivo: Permite gravar arquivos de texto em disco diretamente
  12.   através do T-SQL.
  13.  
  14.   Observação importante: pode haver a necessidade de ativar a
  15.   opção 'Ole Automation Procedures' no SQL Server através do comando
  16.   sp_reconfigure. Para isto, utilize o script abaixo:
  17.   
  18.   -- Mostrar opções avançadas.
  19.   exec sp_configure 'show advanced options', 1
  20.   GO
  21.   -- Ativar a opção anterior
  22.   reconfigure
  23.   GO
  24.   -- Ativa a automação OLE
  25.   exec sp_configure 'Ole Automation Procedures', 1
  26.   GO
  27.   -- Reconfigura para aceitar a modificação
  28.   reconfigure
  29.   GO
  30.   */
  31.  
  32.   declare @objFileSystem   int
  33.   declare @objTextStream   int
  34.   declare @hr              int
  35.   declare @fileAndPath     varchar(80)
  36.  
  37.   exec @hr = sp_OACreate 'Scripting.FileSystemObject'
  38.                        , @objFileSystem output
  39.  
  40.   select @FileAndPath = @diretorio + '\' + @arquivo
  41.   
  42.   if @hr = 0
  43.     exec @hr = sp_OAMethod @objFileSystem
  44.                          , 'CreateTextFile'
  45.                          , @objTextStream output
  46.                          , @FileAndPath
  47.                          , 2
  48.                          , True
  49.  
  50.   if @hr=0
  51.     exec @hr = sp_OAMethod @objTextStream
  52.                          , 'Write'
  53.                          , Null
  54.                          , @texto
  55.  
  56.   if @hr = 0
  57.     exec @hr = sp_OAMethod @objTextStream, 'Close'
  58.  
  59.   exec sp_OADestroy @objTextStream
  60.   exec sp_OADestroy @objTextStream

 

3. spArkabCopiaArquivo – Realiza a cópia do arquivo da etiqueta diretamente para a impressora:

  1. /*
  2. -- Para testar, copia o arquivo direto para impressora SEP1.
  3. exec spArkabCopiaArquivo
  4.     'D:\Arkab\Impressoes\tmp26062011030828_vol_4.txt'
  5.   , '\\PC-CONF01\ZEBRA-SEP1'
  6. */
  7. create proc spArkabCopiaArquivo
  8.   @origem varchar(200)
  9. , @destino varchar(200)
  10.  
  11. as
  12.  
  13.   /*
  14.   Autor: Fabiano Cores
  15.   Data : 06/2011
  16.   Objetivo: Permite copiar arquivos, informando origem e destino.
  17.  
  18.   Observação importante: pode haver a necessidade de ativar a
  19.   opção 'xp_cmdshell' no SQL Server através do comando
  20.   sp_reconfigure. Para isto, utilize o script abaixo:
  21.   
  22.   -- Mostrar opções avançadas.
  23.   exec sp_configure 'show advanced options', 1
  24.   GO
  25.   -- Ativar a opção anterior
  26.   reconfigure
  27.   GO
  28.   -- Ativa o comando
  29.   exec sp_configure 'xp_cmdshell', 1
  30.   GO
  31.   -- Reconfigura para aceitar a modificação
  32.   reconfigure
  33.   GO
  34.   */
  35.  
  36.   declare @string varchar(400)
  37.   
  38.   select @string = 'copy ' + rtrim(@origem) + ' ' + rtrim(@destino)
  39.  
  40.   exec master.dbo.xp_cmdshell @string, no_output

 

O resultado, é uma etiqueta saindo pela impressora, como esta daqui de exemplo (exatamente a mesma do procedimento acima):

2406201168624062011683 

24062011685 24062011684

 

Uma solução interessante…

sexta-feira, 17 de junho de 2011

SPLIT STRING – Função para dividir uma string por um caracter de controle

Imagine a seguinte situação: você possui uma string, separada por ponto e vírgula, e você deseja separar estas strings para realizar um tratamento. Vamos ver um exemplo abaixo:

 

string1; string2; "string 3 com ; no meio"; string4

 

Então nós temos quatro valores concatenados em uma única string. Observe que o terceiro valor utiliza o ponto e vírgula como texto da própria string, porém a sentença toda está entre aspas (“), o que determina que o ponto e virgula desta frase faz parte da string, e não é um caracter separador.

Para resolver esta questão, eu desenvolvi o seguinte procedimento:

 

  1. -- exec spSplit 'string1; string2; "string3 com ; no meio"; string4', ';'
  2. alter proc spSplit
  3.   @grupo varchar(8000),
  4.   @caracter char(1) = NULL
  5. as
  6.  
  7. begin
  8.  
  9.   -- ***************
  10.   -- SQL Burger 2011
  11.   -- Função SPLIT, separa string dividida por
  12.   -- caracter de controle. Esta função só pode ser
  13.   -- utilizada e distribuída caso os créditos ao autor
  14.   -- sejam citados.
  15.   -- ***************
  16.   
  17.   if @caracter is null set @caracter = ','
  18.  
  19.   declare @pos int
  20.   declare @buffer varchar(8000)
  21.   declare @buffer2 varchar(8000)
  22.  
  23.   create table #ret (texto varchar(8000) null, ordem int not null identity(1,1))
  24.  
  25.   while charindex('"', @grupo) > 0
  26.   begin
  27.  
  28.     select @pos = charindex('"', @grupo)
  29.  
  30.     select @buffer = left(@grupo, @pos)
  31.  
  32.     select @grupo = substring(@grupo, @pos + 1, len(@grupo))
  33.  
  34.     select @pos = charindex('"', @grupo)
  35.  
  36.     select @buffer2 = left(@grupo, @pos)
  37.  
  38.     select @grupo = substring(@grupo, @pos + 1, len(@grupo))
  39.  
  40.     select @buffer = replace(@buffer, '"','')
  41.          , @buffer2 = replace(@buffer2, '"', '')
  42.  
  43.     select @buffer2 = replace(@buffer2, @caracter, char(254))
  44.     
  45.     select @buffer2 = replace(@buffer2, ';', char(253))
  46.  
  47.     select @grupo = rtrim(@buffer) + rtrim(@buffer2) + rtrim(@grupo)
  48.  
  49.   end
  50.   
  51.   while charindex(@caracter,@grupo) > 0
  52.   begin
  53.     select @pos = charindex(@caracter,@grupo)
  54.     select @buffer = left(@grupo,@pos - 1)
  55.     select @grupo = right(@grupo,len(rtrim(@grupo)) - @pos)
  56.     
  57.     select @buffer = replace(@buffer, char(254), @caracter)
  58.     select @buffer = replace(@buffer, char(253), ';')
  59.     
  60.     insert into #ret (texto)
  61.       select rtrim(ltrim(@buffer))
  62.   end
  63.  
  64.   if @grupo <> ''
  65.   begin
  66.     select @buffer =replace(@grupo,@caracter,'')
  67.  
  68.     insert into #ret (texto)
  69.       select rtrim(ltrim(@buffer))
  70.   end
  71.  
  72.   select texto from #ret order by ordem
  73.  
  74. end

 

O procedimento recebe dois parâmetros: @grupo (que é string a ser tratada) e @caracter (o caracter de controle a ser utilizado para separar a string). O resultado é o seguinte:

 

  1. exec spSplit 'string1; string2; "string3 com ; no meio"; string4', '!'

 

 image

 

A procedure irá retornar cada string em uma linha, permitindo tratá-las da maneira como quiser. Uma dica, utilize uma tabela temporária com uma coluna auto-numérica, e você saberá exatamente qual linha ler de acordo com a posição desejada:

 

  1. set nocount on
  2.  
  3. create table #split (
  4.   texto varchar(100) null
  5. , ordem int not null identity )
  6.  
  7. insert into #split (texto)
  8.   exec spSplit 'string1; string2; "string3 com ; no meio"; string4', ';'
  9.   
  10. select texto as 'Primeiro parametro' from #split where ordem = 1
  11. select texto as 'Segundo parametro' from #split where ordem = 2
  12. select texto as 'Terceiro parametro' from #split where ordem = 3
  13. select texto as 'Quarto parametro' from #split where ordem = 4
  14.  
  15.  
  16. drop table #split

 

Desta forma, o número da linha corresponderá ao parâmetro:

 

 image

 

Outros caracteres de controle poderão ser utilizados, trazendo o mesmo resultado:

 

  1. exec spSplit 'string1! string2! "string3 com ; no meio"! string4', '!'

 

image

 

  1. exec spSplit 'string1! string2! "string3 com ! no meio"! string4', '!'

 

 image

 

Espero que seja útil!