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 / 54353
Accepted
Taryn
Taryn
Asked: 2013-12-04 06:11:52 +0800 CST2013-12-04 06:11:52 +0800 CST 2013-12-04 06:11:52 +0800 CST

Por que o SQL Server exige que o comprimento do tipo de dados seja o mesmo ao usar o UNPIVOT?

  • 772

Ao aplicar a UNPIVOTfunção a dados não normalizados, o SQL Server exige que o tipo de dados e o comprimento sejam iguais. Entendo por que o tipo de dados deve ser o mesmo, mas por que o UNPIVOT exige que o comprimento seja o mesmo?

Digamos que eu tenha os seguintes dados de amostra que preciso desfazer:

CREATE TABLE People
(
    PersonId int, 
    Firstname varchar(50), 
    Lastname varchar(25)
)

INSERT INTO People VALUES (1, 'Jim', 'Smith');
INSERT INTO People VALUES (2, 'Jane', 'Jones');
INSERT INTO People VALUES (3, 'Bob', 'Unicorn');

Se eu tentar UNPIVOT as colunas Firstnamee semelhantes a:Lastname

select PersonId, ColumnName, Value  
from People
unpivot
(
  Value 
  FOR ColumnName in (FirstName, LastName)
) unpiv;

O SQL Server gera o erro:

Msg 8167, Nível 16, Estado 1, Linha 6

O tipo de coluna "Sobrenome" está em conflito com o tipo de outras colunas especificadas na lista UNPIVOT.

Para resolver o erro, devemos usar uma subconsulta para primeiro converter a Lastnamecoluna para ter o mesmo comprimento que Firstname:

select PersonId, ColumnName, Value  
from
(
  select personid, 
    firstname, 
    cast(lastname as varchar(50)) lastname
  from People
) d
unpivot
(
  Value FOR 
  ColumnName in (FirstName, LastName)
) unpiv;

Consulte SQL Fiddle com demonstração

Antes de o UNPIVOT ser introduzido no SQL Server 2005, eu usaria um SELECTwith UNION ALLpara desdinamizar as colunas firstname/ lastnamee a consulta seria executada sem a necessidade de converter as colunas para o mesmo comprimento:

select personid, 'firstname' ColumnName, firstname value
from People
union all
select personid, 'LastName', LastName
from People;

Consulte SQL Fiddle com demonstração .

Também podemos desativá-los com sucesso usando CROSS APPLYsem ter o mesmo comprimento no tipo de dados:

select PersonId, columnname, value
from People
cross apply
(
    select 'firstname', firstname union all
    select 'lastname', lastname
) c (columnname, value);

Consulte SQL Fiddle com demonstração .

Eu li através do MSDN, mas não encontrei nada explicando o raciocínio para forçar o comprimento do tipo de dados a ser o mesmo.

Qual é a lógica por trás de exigir o mesmo comprimento ao usar o UNPIVOT?

sql-server unpivot
  • 2 2 respostas
  • 18731 Views

2 respostas

  • Voted
  1. Best Answer
    Paul White
    2013-12-06T02:28:06+08:002013-12-06T02:28:06+08:00

    Qual é a lógica por trás de exigir o mesmo comprimento ao usar o UNPIVOT?

    Esta questão só pode ser verdadeiramente respondida pelas pessoas que trabalharam na implementação do UNPIVOT. Você pode obter isso entrando em contato com eles para obter suporte . O seguinte é o meu entendimento do raciocínio, que pode não ser 100% preciso:


    T-SQL contém qualquer número de instâncias de semântica estranha e outros comportamentos contra-intuitivos. Alguns deles acabarão desaparecendo como parte dos ciclos de descontinuação, mas outros podem nunca ser 'melhorados' ou 'consertados'. Além de qualquer outra coisa, existem aplicativos que dependem desses comportamentos, portanto, a compatibilidade com versões anteriores deve ser preservada.

    As regras para conversões implícitas e derivação de tipo de expressão respondem por uma proporção significativa da estranheza mencionada acima. Não invejo os testadores que precisam garantir que os comportamentos estranhos (e muitas vezes não documentados) sejam preservados (sob todas as combinações de SETvalores de sessão e assim por diante) para novas versões.

    Dito isso, não há um bom motivo para não fazer melhorias e evitar erros do passado ao introduzir novos recursos de linguagem (obviamente sem bagagem de compatibilidade com versões anteriores). Novos recursos como expressões de tabela comuns recursivas (como mencionado por Andriy M em um comentário) e UNPIVOTestavam livres para ter uma semântica relativamente sã e regras claramente definidas.

    Haverá uma variedade de pontos de vista sobre se incluir o comprimento no tipo está levando a digitação explícita longe demais, mas pessoalmente eu a acolho. Na minha opinião, os tipos varchar(25)e nãovarchar(50) são os mesmos, não mais do que e são. A conversão especial do tipo de cadeia de revestimento complica as coisas desnecessariamente e não agrega valor real, na minha opinião.decimal(8)decimal(10)

    Pode-se argumentar que apenas as conversões implícitas que podem perder dados devem ser declaradas explicitamente, mas também existem casos extremos. Em última análise, uma conversão será necessária, portanto, podemos torná-la explícita.

    Se a conversão implícita de varchar(25)para varchar(50)fosse permitida, seria apenas outra conversão implícita (provavelmente oculta), com todos os casos extremos estranhos usuais e SETsensibilidades de configuração. Por que não tornar a implementação o mais simples e explícita possível? (Nada é perfeito, no entanto, e é uma pena que esconder varchar(25)e varchar(50)dentro de um sql_variantseja permitido.)

    Reescrever o UNPIVOTcom APPLYe UNION ALLevita o (melhor) tipo de comportamento porque as regras para UNIONestão sujeitas à compatibilidade com versões anteriores e estão documentadas nos Manuais Online como permitindo tipos diferentes, desde que sejam comparáveis ​​usando conversão implícita (para a qual as regras misteriosas de precedência de tipo de dados são usados, e assim por diante).

    A solução envolve ser explícito sobre os tipos de dados e adicionar conversões explícitas quando necessário. Isso parece um progresso para mim :)

    Uma maneira de escrever a solução alternativa digitada explicitamente:

    SELECT
        U.PersonId,
        U.ColumnName,
        U.Value
    FROM dbo.People AS P
    CROSS APPLY
    (
        VALUES (CONVERT(varchar(50), Lastname))
    ) AS CA (Lastname)
    UNPIVOT
    (
        Value FOR
        ColumnName IN (P.Firstname, CA.Lastname)
    ) AS U;
    

    Exemplo de CTE recursivo:

    -- Fails
    WITH R AS
    (
        SELECT Dummy = 'A row'
        UNION ALL
        SELECT 'Another row'
        FROM R
        WHERE Dummy = 'A row'
    )
    SELECT Dummy
    FROM R;
    
    -- Succeeds
    WITH R AS
    (
        SELECT Dummy = CONVERT(varchar(11), 'A row')
        UNION ALL
        SELECT CONVERT(varchar(11), 'Another row')
        FROM R
        WHERE Dummy = 'A row'
    )
    SELECT Dummy
    FROM R;
    

    Por fim, observe que reescrever usando CROSS APPLYna pergunta não é exatamente o mesmo que UNPIVOT, porque não rejeita NULLatributos.

    • 27
  2. dev_etter
    2013-12-04T14:05:11+08:002013-12-04T14:05:11+08:00

    O UNPIVOToperador utiliza o INoperador. As especificações para o operador IN (captura de tela abaixo) indicam que tanto o test_expression(neste caso, à esquerda do IN) quanto cada expression(no lado direito do IN) devem ser do mesmo tipo de dados. Graças à propriedade transitiva de igualdade, cada expressão também deve ser do mesmo tipo de dados.

    insira a descrição da imagem aqui

    • 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

    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

    Conceder acesso a todas as tabelas para um usuário

    • 5 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
    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
    pedrosanta Listar os privilégios do banco de dados usando o psql 2011-08-04 11:01:21 +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