将 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,