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 / 117931
Accepted
Collin Dauphinee
Collin Dauphinee
Asked: 2015-10-14 13:51:24 +0800 CST2015-10-14 13:51:24 +0800 CST 2015-10-14 13:51:24 +0800 CST

Posso criar uma coluna computada que requer entrada para selecionar?

  • 772

Tenho um cenário em uma aplicação muito antiga e muito grande, onde tenho uma tabela representando um tipo de recurso:

CREATE TABLE resource (resource_id INT, name NVARCHAR(4000))

Essa tabela é selecionada em centenas de locais diferentes, incluindo procedimentos armazenados e SQL dinâmico no código do aplicativo.

Uma equipe atualizou recentemente o nome deste recurso para ser localizado, e sua abordagem é bastante direta. Há uma nova tabela contendo os nomes localizados e um ID de idioma 'padrão' na resourcetabela, para quando o nome não estiver localizado para o idioma solicitado:

-- Foreign keys omitted
ALTER TABLE resource ADD default_language_id INT
CREATE TABLE resource_local (resource_id INT, language_id INT, name NVARCHAR(4000))

A maioria dos procs tem um @user_language_idparâmetro, portanto, a lógica para escolher o nome a ser retornado é simples: pegue resource_local.namecorrespondência language_id = @user_language_idse existir, caso contrário, resource_local.namecorresponda language_id = resource.default_language_idse existir, caso contrário pegue resource.name.

Infelizmente, isso transforma a lógica para selecionar o nome correto em algo assim:

SELECT ISNULL(ISNULL(exact.name, default.name), res.name)
FROM resource res
LEFT JOIN resource_local exact ON exact.resource_id = res.resource_id 
    AND exact.language_id = @user_language_id
LEFT JOIN resource_local default ON default.resource_id = res.resource_id
    AND default.language_id = res.default_language_id
WHERE res.resource_id = @resource_id

Todas as centenas de locais que tentam selecionar resource.nameestão tendo que ser atualizadas com essa lógica, o que tornou esse projeto um esforço massivo de toda a organização, pois cada equipe precisa atualizar seu SQL para usar essa lógica. Isso também causa problemas de manutenção, pois qualquer novo desenvolvedor que lida com essa tabela precisa saber que não pode usar apenas a namecoluna.

Agora é tarde demais, mas estou curioso: existe alguma maneira melhor de abordar isso, de modo que selecionar a namecoluna de resourceapenas 'faça a coisa certa' com base na @user_language_idvariável (se existir)?

sql-server computed-column
  • 2 2 respostas
  • 194 Views

2 respostas

  • Voted
  1. Best Answer
    Geoff Patterson
    2015-10-14T18:28:44+08:002015-10-14T18:28:44+08:00

    Não tenho certeza se é possível fazer isso para que nenhuma das referências à resourcetabela precise ser alterada. Parece que o fato de que um language_idé necessário é uma mudança fundamental que todo código de chamada precisará estar ciente.

    No entanto, é possível projetar isso de forma que o recurso possa ser consultado de uma das maneiras simples a seguir. Uma dessas opções pode ter sido uma mudança mais fácil de fazer e manter em tantos lugares diferentes.


    Função com valor de tabela

    Usando uma função com valor de tabela embutida , podemos fornecer a seguinte sintaxe.

    SELECT resource_id, language_id, name
    FROM dbo.resourceTVF(@resource_id, @language_id) r
    

    Aqui está um exemplo de como criar a função. É essencialmente a mesma consulta da sua pergunta, mas com o alias defaultalterado para def( defaulté uma palavra-chave do SQL Server).

    -- Create the Table-Valued Function
    CREATE FUNCTION dbo.resourceTVF (@resource_id INT, @user_language_id INT)
    RETURNS TABLE 
    AS
    RETURN
    SELECT @resource_id AS resource_id,
      @user_language_id AS language_id,
      ISNULL(ISNULL(exact.name, def.name), res.name) AS name
    FROM dbo.resource res
    LEFT JOIN dbo.resource_local exact ON exact.resource_id = res.resource_id 
        AND exact.language_id = @user_language_id
    LEFT JOIN dbo.resource_local def ON def.resource_id = res.resource_id
        AND def.language_id = res.default_language_id
    WHERE res.resource_id = @resource_id
    GO
    


    Visão

    Você pode renomear a resourcetabela (por exemplo, para resource_base) e criar uma resourceexibição para fornecer a seguinte API:

    SELECT resource_id, language_id, name
    FROM dbo.resource
    WHERE resource_id = @resource_id
      AND language_id = @language_id
    

    A principal desvantagem é que a definição de exibição precisa de CROSS JOINtodos os recursos e idiomas antes de usar a aplicação LEFT JOINaos recursos locais e padrão. Mesmo assim, este será um plano bastante eficiente com 4 buscas singleton, supondo que você tenha os índices adequados.

    CREATE VIEW dbo.resource WITH SCHEMABINDING AS
    SELECT res.resource_id,
      lang.language_id,
      ISNULL(ISNULL(exact.name, def.name), res.name) AS name
    FROM dbo.resource_base res
    CROSS JOIN dbo.languages lang
    LEFT JOIN dbo.resource_local exact ON exact.resource_id = res.resource_id 
        AND exact.language_id = lang.language_id
    LEFT JOIN dbo.resource_local def ON def.resource_id = res.resource_id
        AND def.language_id = res.default_language_id
    GO
    


    roteiro completo

    Aqui está um script completo onde implementei essas duas propostas, carreguei uma pequena quantidade de dados falsos e executei alguns casos de teste. Pelo menos para esses casos de teste, ambas as abordagens produzem os resultados desejados e usam um plano baseado em loop-seek.

    Acho que a função com valor de tabela embutida é provavelmente a abordagem que eu tentaria primeiro. Observe que você pode usar CROSS APPLYpara "juntar" à função com valor de tabela se precisar de mais de um recurso por vez.

    • 4
  2. Solomon Rutzky
    2015-10-14T20:54:01+08:002015-10-14T20:54:01+08:00

    Eu definitivamente segundo a abordagem de função de valor de tabela em linha (iTVF) de @Geoff e ia sugerir isso eu mesmo, mas ele chegou antes de mim ;-).

    Vou apenas acrescentar que parece que ter 2 níveis de "padrão" parece um pouco complicado. Quero dizer, não entendo por que o default_language_idfoi adicionado à resourcetabela. Parece permitir que vários recursos em uma determinada página sejam provenientes de vários idiomas. Acho que é mais consistente para o usuário final se você simplesmente tiver o recurso baseado em localidade/LCID na nova tabela e, se não for encontrado, encontre o padrão na resourcetabela. Mas voltar lá primeiro apenas para obter um padrãolanguage_id? Acho que, a longo prazo, isso causará mais problemas do que resolverá. Se você vai ter um padrão, deve haver um padrão. Ou você encontra o nome do recurso no LCID desejado ou não o encontra e volta para o padrão (embora provavelmente não deva deixar isso acontecer, pois uma página que contém inglês (da esquerda para a direita) e hebraico ou árabe (idiomas da direita para a esquerda) pode ser um pouco confuso ;).

    • 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