将 nvarchar 转换为 datetime 时出现异常
Exception when converting nvarchar to datetime
我在 SQL Server 2014 中有这个存储过程,如果数据在第二个 table 上不存在,它基本上会将数据从一个 table 复制到另一个。复制的时候要进行一些转换,因为第一个table的所有列都是nvarchar
。
几乎每次执行此过程时,我都会收到转换错误:
The conversion of a nvarchar data type to a datetime data type resulted in an out-of-range value.
我插入了 try-catch 指令来获取错误,但它对我的帮助不大。另外,我决定使用一个辅助变量(@aux
)来帮助我检查错误发生在程序的哪个点,因为我没有在 SSMS 上调试程序的权限。
我认为我收到此错误是因为日期格式或文化。我的第一个 table 中确实有日期为“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
这是我得到的结果:
编辑
这是让我出错的寄存器之一。黄色值是我的日期列。即使它是 '0000-00-00',程序在执行 IF 语句时不应该改变它吗?
错误发生在这一行-->
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,
我在 SQL Server 2014 中有这个存储过程,如果数据在第二个 table 上不存在,它基本上会将数据从一个 table 复制到另一个。复制的时候要进行一些转换,因为第一个table的所有列都是nvarchar
。
几乎每次执行此过程时,我都会收到转换错误:
The conversion of a nvarchar data type to a datetime data type resulted in an out-of-range value.
我插入了 try-catch 指令来获取错误,但它对我的帮助不大。另外,我决定使用一个辅助变量(@aux
)来帮助我检查错误发生在程序的哪个点,因为我没有在 SSMS 上调试程序的权限。
我认为我收到此错误是因为日期格式或文化。我的第一个 table 中确实有日期为“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
这是我得到的结果:
编辑
这是让我出错的寄存器之一。黄色值是我的日期列。即使它是 '0000-00-00',程序在执行 IF 语句时不应该改变它吗?
错误发生在这一行-->
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,