我在SQL Server 2014中具有此存储过程,基本上,如果第二个表中不存在该数据,则该数据将从一个表复制到另一个表。复制时,它必须进行一些转换,因为第一个表中的所有列均为nvarchar
。几乎每次执行此过程时,都会出现转换错误:
将nvarchar数据类型转换为datetime数据类型导致值超出范围。
我插入了try-catch指令来获取错误,但并没有太大帮助。另外,我决定使用辅助变量(@aux
),以帮助我检查错误发生在过程的哪一点,因为我无权在SSMS上调试过程。
我认为由于日期格式或文化原因,我收到此错误。我的第一个表中确实有行,其日期类似于'00 -00-0000',这就是为什么它是varchar
的原因,并且在复制过程中我在程序中也执行了IF语句来替换它们。
这是我的程序:
BEGIN try
DECLARE crPESSOA_MKT CURSOR FOR
SELECT DISTINCT
cpf, nome, nascimento, sexo, endereco, numero, complemento,
bairro, cidade, estado, cep, email, telefone, celular, receber_emails, qtde_codigos
FROM dbo.CLIENTESMKT2019
WHERE cpf IS NOT NULL
DECLARE @Cpf nvarchar(255), @nome nvarchar(255), @nascimento datetime,
@sexo nvarchar(255), @endereco nvarchar(255), @numero nvarchar(255),
@complemento nvarchar(255), @bairro nvarchar(255), @cidade nvarchar(255),
@estado nvarchar(255), @cep nvarchar(255), @email nvarchar(255),
@telefone nvarchar(255), @celular nvarchar(255), @receber_emails nvarchar(255),
@qtde_codigos float, @data_errada nvarchar(255), @aux varchar(50)
OPEN crPESSOA_MKT
SET @aux = 'open'
FETCH NEXT FROM crPESSOA_MKT INTO @Cpf, @nome, @nascimento, @sexo, @endereco, @numero, @complemento, @bairro, @cidade, @estado, @cep, @email, @telefone, @celular, @receber_emails, @qtde_codigos
WHILE @@FETCH_STATUS = 0
BEGIN
SET @aux = CONCAT('while ',@nascimento)
SET @nascimento = FORMAT(@nascimento, 'dd-MM-yyyy', 'pt-BR')
SET @aux = CONCAT('nascimento = ', @nascimento)
IF NOT EXISTS (SELECT PESSOA.CPF FROM PESSOA
WHERE PESSOA.CPF = LEFT(CAST(@Cpf AS VARCHAR), 11))
BEGIN
SET @aux = 'if exists'
IF ISDATE(@nascimento) = 0 OR
@nascimento = CAST('00-00-0000' AS DATE) OR
YEAR(@nascimento) < 1900
BEGIN
SET @aux = 'if isdate'
SET @nascimento = CAST('01-01-1900' AS DATE)
SET @aux = 'set @nascimento'
END
ELSE
BEGIN
SET @aux = 'else'
SET @nascimento = CAST(@nascimento AS DATE)
SET @aux = 'cast nascimento'
END
SET @data_errada = CAST(@nascimento AS NVARCHAR)
SET @aux = 'errados'
INSERT INTO dbo.PESSOA (CPF, NOME, ENDERECO, BAIRRO, CIDADE, CEP, COMPLEMENTO,
EMAIL, DATA_NASCIMENTO, FONE, ESTADO, SEXO,
CELULAR, RECEBE_EMAILSN, QTD_CUPONS, NUMERO, IDORIGEM, DATA_INCLUSAO)
VALUES (LEFT(@cpf, 11), LEFT(@nome, 50), LEFT(@endereco, 50), LEFT(@bairro, 50), LEFT(UPPER(@CIDADE), 50) COLLATE SQL_Latin1_General_CP1251_CS_AS, LEFT(@cep, 8), LEFT(@complemento, 50),
LEFT(@email, 50), @nascimento, LEFT(@telefone, 12), LEFT(@estado, 2), LEFT(@sexo, 1),
LEFT(@celular, 11), LEFT(@receber_emails, 1), @qtde_codigos, LEFT(CAST(@numero AS NVARCHAR), 15), 8, CURRENT_TIMESTAMP)
SET @aux = 'insert'
END
/* ELSE
BEGIN
IF EXISTS (SELECT PESSOA.CPF FROM PESSOA
WHERE PESSOA.CPF = LEFT(CAST(@Cpf AS VARCHAR), 11))
BEGIN
SELECT EMAIL, LEFT(@email, 50)
FROM PESSOA
WHERE PESSOA.CPF = LEFT(CAST(@Cpf AS VARCHAR), 11)
-- UPDATE PESSOA
-- SET EMAIL = LEFT(@email, 50)
-- WHERE PESSOA.CPF = LEFT(CAST(@Cpf AS VARCHAR), 11)
-- AND EMAIL IS NULL
END
END*/
FETCH NEXT FROM crPESSOA_MKT INTO @Cpf, @nome, @nascimento,@sexo,@endereco,@numero,@complemento,@bairro,@cidade,@estado,@cep,@email,@telefone,@celular,@receber_emails,@qtde_codigos
SET @aux = 'next'
END
CLOSE crPESSOA_MKT
DEALLOCATE crPESSOA_MKT
END TRY
BEGIN CATCH
SELECT
ERROR_NUMBER() AS ErrorNumber,
ERROR_SEVERITY() AS ErrorSeverity,
ERROR_STATE() AS ErrorState,
ERROR_PROCEDURE() AS ErrorProcedure,
ERROR_LINE() AS ErrorLine,
ERROR_MESSAGE() AS ErrorMessage,
@nascimento AS 'nascimento',
@data_errada AS 'data errada',
@aux AS 'aux'
END CATCH
这是我得到的结果:
编辑
此行出现错误->
FETCH NEXT FROM crPESSOA_MKT INTO @Cpf, @nome, @nascimento
[您正试图将'0000-00-00'形式的字符串强制放入DATETIME变量@nascimento中,这将导致无效的转换。
如果这是您要导入的数据中唯一的边缘情况,则作为变通方法,请检查有效性并将'000-00-00'转换为null,但我敢打赌,该值的目的还是要这样做。
SELECT DISTINCT
cpf, nome, CASE WHEN ISDATE(nascimento) THEN nascimento ELSE NULL END , sexo, endereco, numero, complemento,