AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 267843
Accepted
Nishant
Nishant
Asked: 2020-05-26 04:42:31 +0800 CST2020-05-26 04:42:31 +0800 CST 2020-05-26 04:42:31 +0800 CST

Por que o SQL Server diz que não pode converter varchar em numérico?

  • 772

Eu tenho o seguinte esquema/dados no MSSQL Server 2019 ( SQLFiddle ):

CREATE TABLE products(
    idn NUMERIC(9) PRIMARY KEY
);

CREATE TABLE sales(
    idn NUMERIC(9) PRIMARY KEY,
    pid VARCHAR(50) NOT NULL,
    type VARCHAR(10) NOT NULL
);

INSERT INTO products (idn) VALUES (1);
INSERT INTO sales (idn, pid, type) VALUES (1, 1, 'number');
INSERT INTO sales (idn, pid, type) VALUES (2, 'Colgate', 'word');

salestem dados mistos, ou seja, VARCHARe NUMERIC. O filtro de transações cuida JOINcorretamente.

Por que o seguinte SELECTfalha (por algum motivo além do meu controle, a consulta gerada tem Nliterais para strings.)?

SELECT 
    * 
FROM 
    products 
    INNER JOIN sales ON products.idn = sales.pid 
    AND sales.type = N'number' 
WHERE 
    products.idn in (1);

Não vejo por que transmitir NVARCHARpara NUMERICé um problema:

SELECT CAST (N'1' as NUMERIC);

Se eu modificar um pouco a consulta, funciona:

SELECT 
    * 
FROM 
    products 
    INNER JOIN sales ON products.idn = sales.pid 
    AND sales.type = N 'number' 
WHERE
    -- Selecting the same data from `sales`.
    sales.pid in (1);

SELECT 
    * 
FROM 
    products 
    INNER JOIN sales ON products.idn = sales.pid
    -- Dropping the `N` prefix.
    AND sales.type = 'number' 
WHERE 
    products.idn in (1);

sql-server type-conversion
  • 4 4 respostas
  • 2026 Views

4 respostas

  • Voted
  1. Best Answer
    Dan Guzman
    2020-05-26T06:06:03+08:002020-05-26T06:06:03+08:00

    Ocorrerá um erro de conversão em tempo de execução quando for feita uma tentativa de converter o sales.pidvalor 'Colgate' para numeric(9) para avaliar os critérios de junção. Se isso realmente acontece ou não, depende da ordem de avaliação no plano de execução.

    Abaixo está o predicado de verificação de índice clusterizado da tabela de vendas do plano de execução literal Unicode , mostrando que a conversão ocorre antes que a condição 'number' seja avaliada:

    CONVERT_IMPLICIT(numeric(9,0),[tempdb].[dbo].[sales].[pid],0)=(1.) AND CONVERT_IMPLICIT(nvarchar(10),[tempdb].[dbo].[sales].[type],0)=N'number'  
    

    O plano com o literal não Unicode tem a mesma forma, exceto que a ordem do predicado no operador de varredura é invertida:

    [tempdb].[dbo].[sales].[type]='number' AND CONVERT_IMPLICIT(numeric(9,0),[tempdb].[dbo].[sales].[pid],0)=(1.)
    

    Embora o literal não Unicode (ou parâmetro) possa solucionar o problema, a consulta ainda estará vulnerável a erros de tempo de execução. Isso pode ser resolvido com TRY_CAST, TRY_CONVERT, CASEexpressão etc., mas seria melhor corrigir o modelo de dados para garantir que apenas tipos de dados semelhantes ou compatíveis sejam comparados.

    • 2
  2. Dominique Boucher
    2020-05-26T05:58:12+08:002020-05-26T05:58:12+08:00

    Isso ocorre porque você está usando uma coluna que contém valores de texto (pid) para unir em uma coluna numérica

    INNER JOIN sales ON products.idn = sales.pid 
    

    Quando você faz uma junção dessas 2 tabelas, o SQL precisa comparar todas as linhas de idn com todas as linhas de pid. Para compará-los, ele precisa converter seu varchar em numérico.

    Como o SQL pode converter 'Colgate' em um número? é por isso que falha.

    Você deve ler sobre normalização de banco de dados.

    Sua coluna PID não parece boa e você provavelmente precisaria de outra tabela com um ID do produto e uma descrição do produto (onde 'Colgate' será a descrição) para que funcione como você espera.

    • 1
  3. David Browne - Microsoft
    2020-05-26T06:02:17+08:002020-05-26T06:02:17+08:00

    Por que o SELECT a seguir falha (por algum motivo além do meu controle, a consulta gerada tem N literais para strings.)?

    Porque está recebendo um plano de execução que avalia

    sales.pid=1
    

    para a linha com

    sales.pid = 'Colgate'
    

    antes de avaliar o predicado

    sales.type = N'Number'
    

    inttem uma precedência de tipo de dados mais alta do que varcharpara executar a comparação, o 'varchar' é convertido implicitamente em int. Esta conversão falha para "Colgate".

    A maneira de bloquear a ordem de avaliação para essas duas condições é com uma expressão CASE. POR EXEMPLO

    SELECT 
        * 
    FROM 
        products 
        INNER JOIN sales 
        ON  case when sales.type = N'number' and sales.pid = products.idn then 1 else 0 end = 1
    WHERE 
    products.idn = 1
    

    Isso pode causar problemas de desempenho em escala, mas esse é um dos muitos motivos pelos quais cada coluna deve ter apenas um tipo de dados.

    • 1
  4. Ronaldo
    2020-05-26T06:08:09+08:002020-05-26T06:08:09+08:00

    O otimizador de consulta pode alterar a ordem em que as coisas são feitas para obter seu resultado da maneira mais rápida entre as opções que ele apresenta (dado que o resultado da consulta não é alterado).

    Sabendo disso, se você verificar o plano de execução, isso ajudará você a entender o motivo pelo qual você obtém o erro com uma consulta e não com a outra, considerando os dados de exemplo que você forneceu:

    Pergunta 1:

    SELECT 
        * 
    FROM 
        products 
        INNER JOIN sales ON products.idn = sales.pid
        -- Dropping the `N` prefix.
        AND sales.type = 'number' 
    WHERE 
        products.idn in (1);
    

    Plano de consulta

    Pergunta 2:

    SELECT 
        * 
    FROM 
        products 
        INNER JOIN sales ON products.idn = sales.pid 
        AND sales.type = N'number' 
    WHERE 
        products.idn in (1);
    

    Plano de consulta

    Predicado do plano de consulta

    A consulta 1 funcionou porque quando você removeu o N (que é usado para converter uma string para nvarchar) o SQL Server não precisou realizar uma conversão implícita de sales.typevarchar para nvarchar. Neste caso sales.pidtem uma conversão implícita em ambas as consultas pois está sendo comparada a products.idnqual tem um tipo de dado diferente. O otimizador de consultas decide que a comparação de uma coluna sem conversão implícita é mais barata, então ele começa executando o predicado sales.type = 'number'e gera um subconjunto composto pelas linhas que contém todos os valores de sales.typecomo números (e você pode converter números reais de um string cloumn sem nenhum problema). Assim, a consulta funciona.

    A consulta 2 gera um erro porque ambos os predicados de salestêm conversões implícitas e o otimizador escolheu começar de sales.pidantes de filtrar apenas as linhas que mantêm os números. Quando ele tenta converter o valor 'Colgate'em um numeric(9,0)tipo de dados, você recebe o erro.

    • 1

relate perguntas

  • SQL Server - Como as páginas de dados são armazenadas ao usar um índice clusterizado

  • Preciso de índices separados para cada tipo de consulta ou um índice de várias colunas funcionará?

  • Quando devo usar uma restrição exclusiva em vez de um índice exclusivo?

  • Quais são as principais causas de deadlocks e podem ser evitadas?

  • Como determinar se um Índice é necessário ou necessário

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve