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 / 141241
Accepted
Martin F
Martin F
Asked: 2016-06-15 13:53:59 +0800 CST2016-06-15 13:53:59 +0800 CST 2016-06-15 13:53:59 +0800 CST

Como posso permitir que parte de uma chave seja nula e impor exclusividade de registros com nulos?

  • 772

Tenho uma tabela do Access chamada Engagementcom quatro campos:

Emp_id, Year, Week, Act_id

Ele registra quando um funcionário está/estava envolvido em uma atividade. Cada campo é Number e cada um faz parte da chave primária composta. A semântica do aplicativo era que cada entrada (cada Emp_id- Year- Week- Act_idcombinação) deveria ser única. Ou seja, embora um funcionário geralmente tenha diferentes semanas do ano e diferentes atividades, às vezes um funcionário pode se envolver na mesma atividade em diferentes semanas do ano ou até mesmo se envolver em atividades diferentes na mesma semana do ano. Nulos não eram permitidos. Tudo funcionou.

Agora preciso expandir/modificar a semântica para permitir valores ano-semana desconhecidos – ou mais apropriadamente, não divulgados – associados a qualquer atividade de funcionário. Obviamente, tentar inserir uma linha com um ano-semana vazio resulta em "Índice ou chave primária não pode conter um valor nulo". Então eu preciso de uma mudança no design da mesa.

Uma coisa que tentei foi converter o índice de chave primária em um índice não primário desativando Primário (e deixando Único ativado) na janela Índices. Isso evita corretamente registros duplicados onde os valores de Ano-Semana não estão vazios -- mas permite registros duplicados onde Ano-Semana estão vazios.

Por exemplo, usando o índice exclusivo não primário acima, os seguintes dados são permitidos:

Emp_id  Year  Week  Act_id
     7  2014    12      31  } Same activity,
     7  2015    22      31  } different dates.
     7  2015    33      32
     7  2015    40      33  } Same dates,
     7  2015    40      34  } different activities.
     7  2016     2      36
     7                  38  } Different activities,
     7                  39  } undisclosed dates.

E nenhuma das seguintes adições são permitidas posteriormente:

Emp_id  Year  Week  Act_id
     7  2014    12      31  } Both records are 
     7  2015    33      32  } duplicates of above.

Até aqui tudo bem (o comportamento corresponde aos requisitos). No entanto, ambas as adições a seguir são permitidas posteriormente, mas não devem ser :

Emp_id  Year  Week  Act_id
     7                  38  } Both records are
     7                  39  } duplicates of above.

Por que é que?

Qual é uma boa maneira de contornar esse problema de, por um lado, permitir algo equivalente a nulo para Ano e Semana e, por outro lado, restringir cada Emp_id- Year- Week- Act_idcombinação a ser única?

Posso pensar em duas outras soluções (não testadas):

  1. Escolha um valor numérico equivalente a nulo, como zero ou -1 e de alguma forma explique isso aos usuários.
  2. Converta os tipos de campo Ano-Semana de Número para Texto e simplesmente use "" (string vazia) para nulo.

Na sua experiência, qual é uma boa solução para esse tipo de situação?

Estou ciente de O que há de errado com colunas anuláveis ​​em chaves primárias compostas? e valor NULL na chave primária de várias colunas , que explicam certas coisas, mas não fornecem uma solução.

ms-access primary-key
  • 5 5 respostas
  • 2340 Views

5 respostas

  • Voted
  1. Peter Vandivier
    2016-06-16T16:24:41+08:002016-06-16T16:24:41+08:00

    O conselho mais forte que posso dar é manter a chave primária imutável , a menos que seja absolutamente inviável para o seu caso de uso. Você parece estar descrevendo 2 conjuntos de dados diferentes.

    1. User-Actionstomada durante um determinado Period (definido pela chave composta de Ano-Semana)
    2. User-Actionstirada durante um desconhecido Period

    Minha impressão inicial é que o período desconhecido deve ser um conjunto de dados diferente. Certamente, se você não sabe quando uma ação ocorreu, também não sabe o suficiente para movê-la de seu ambiente de teste para a tabela onde User-Action-Periodestá o identificador exclusivo. Não conheço o MS Access bem o suficiente para comentar sobre as especificidades da chave nula nesse ambiente, mas recomendo definir seu modelo de dados para você mesmo de forma que você saiba se precisa incluir o "equivalente a nulo " registros chaveados na mesma tabela .

    Pela sua descrição, parece que o problema ocorre ao tentar inserir várias instâncias de um User-Actiononde o Periodocorrido não é conhecido . Mais uma vez, se você não souber o suficiente para identificar exclusivamente o tempo de confirmação do User-Action, é apropriado testar as métricas que você está registrando sobre o mesmo User-Actionem outro lugar até que você possa identificar adequadamente o relacionamento que isso User-Actiontem com o outro semelhante User-Actionsque ocorreu em outra chave -tempo capaz Period.

    Vejo dois caminhos a seguir:

    Se apenas uma ação do usuário com chave de tempo "desconhecida" for permitida

    Exemplo: A ação está "pendente" ou "a ser concluída". O usuário estará sempre enviando dados para um período futuro/não concluído.

    Solução: escolha seu método favorito de codificar o período de tempo como "equivalente a nulo" e torne as colunas-chave não anuláveis. Você pode continuar armazenando esses conjuntos de dados na mesma tabela

    Pegadinha: se o usuário enviar uma ação com um período confirmado enquanto existe um período desconhecido para o mesmo User-Action, você pode se deparar com uma situação em que os dados são confirmados em que o período é conhecido, mas outros dados já confirmados por um período desconhecido (que por acaso é o mesmo ) é deixado no estado "período desconhecido" e perdido para esse User-Action-Timeregistro e o usuário não sabe imediatamente o motivo.

    Múltiplas ações do usuário com chaves de tempo "desconhecidas" são permitidas

    Exemplo: os usuários podem identificar exclusivamente o mesmo tipo de ação com um identificador diferente para um período desconhecido .

    Solução: Deve-se definir outra forma de chavear os dados (onde o horário em que a ação ocorre é uma métrica do outro registro multichaveado). Permita que os usuários enviem dados para este conjunto de dados armazenado separadamente e mescle-os em seu User-Action-Timeconjunto de dados de período usando a lógica apropriada. Dá mais trabalho, mas não há como contornar isso se os conjuntos de dados estiverem separados de boa-fé.

    • 6
  2. Anthony Genovese
    2016-06-16T16:04:59+08:002016-06-16T16:04:59+08:00

    Você pode usar uma data padrão de algo fora dos limites. por exemplo, na definição da tabelaYEAR INTEGER DEFAULT 1776, WEEK INTEGER DEFAULT 99

    Dessa forma, você sabe que tudo é inserido com alguma data. Ele continuará a não permitir que você insira dados duplicados.

    Além disso, você pode criar um relatório de exceção com base nesses valores iniciados para alguém, informando que precisa atualizar essa data para a correta.

    • 1
  3. mpag
    2016-06-17T15:00:18+08:002016-06-17T15:00:18+08:00

    Esta solução funcionará apenas no Access 2010+ (por exemplo, 2013) e somente se o arquivo for salvo como um accdb (esta solução não funciona para MDBs, mesmo no Access 2010) . Você também pode ter que habilitar macros no documento salvo para que as verificações realmente... você sabe... funcionem.

    Configure o índice exclusivo como antes, tendo em mente que ele não será realmente exclusivo se você tiver valores nulos até que o restante desta solução seja colocado em ação. O código SQL para isso seria

    CREATE UNIQUE INDEX uidx_engagement
      ON Engagement (Emp_id ASC,  Act_id ASC, Year ASC, Week ASC)
    

    Na visualização da folha de dados da tabela, clique em Tableabaixo Table Toolsna faixa de opções superior. Clique Before Changena Before Eventsseção da faixa de opções.

    a primeira ação deve ser

    SetLocalVar
    Name    vm
    Expression     = ValidateMe()
    

    A segunda ação deve ser

    If    Not [vm]   Then
    

    Isso deve criar um If..End Ifbloco

    No meio do Ifbloco, crie outra instrução. Eu acredito que o número real do erro não importa.

    RaiseError
    Error Number   1
    Error Description   Duplicate Record Entered
    

    Em seguida, salve e feche a Before Changechamada de macro.

    Agora você precisará criar o código VBA. Clique na Database Toolsfita. Na Macroseção, cliqueVisual Basic

    No painel superior esquerdo que se abre, você deve ver uma árvore de arquivos. Um desses objetos deve ser uma entrada para seu banco de dados. Clique com o botão direito do mouse no nome e selecione Insert-> Module. Em seguida, na janela principal que se abre, cole o seguinte.

    Option Compare Database
    
    Public Function ValidateMe() As Boolean
    'idea from http://www.utteraccess.com/forum/lofiversion/index.php/t1965349.html'
        Dim tabl As Object
        Dim my As Object
        Dim tablName As String
        Dim str As String
        Set tabl = Application.CurrentData.AllTables(Application.CurrentObjectName)
        Set my = Application.Screen.ActiveDatasheet.Controls
        tablName = tabl.Name
        str = "Emp_id=" & my!Emp_id & " AND Act_id=" & my!Act_id & " AND " & IIf(IsNull(my!Year), "ISNULL(Year)", "Year=" & my!Year) & " AND " & IIf(IsNull(my!Week), "ISNULL(Week)", "Week=" & my!Week) 'need "'"s if non-numeric data types'
        If DCount("[Emp_id]", tabl.Name, str) > 0 Then ValidateMe = False Else ValidateMe = True
    End Function
    

    Salve este módulo e o código VBA em geral. Chamei meu módulo de "Validador", mas não importa como você o chama... talvez seja necessário também compilar o módulo no Debugmenu.

    Consulte o histórico de edição deste tópico para uma tentativa anterior de solução. Bah.

    • 1
  4. Best Answer
    Martin F
    2016-07-05T13:49:48+08:002016-07-05T13:49:48+08:00

    A primeira parte da solução foi - como eu disse na pergunta - converter o índice de chave primária em um índice não primário desativando Primário (e deixando Único ativado) na janela Índices.

    Um meio alternativo para criar esse índice, conforme sugerido por @mpag, é via SQL:

    CREATE UNIQUE INDEX uidx_engagement ON Engagement (Emp_id, Year, Week, Act_id)
    

    A segunda parte da solução foi perceber que eu já estava utilizando uma consulta SQL parametrizada, get_engagement, no código dos meus formulários onde o usuário insere ou apaga os dados do engajamento:

    SELECT * FROM Engagement WHERE
    Emp_id = e AND Act_id = a AND Year = y AND Week = w
    

    E, em seguida, modifique-o para que ele possa lidar com os casos nulos:

    SELECT * FROM Engagement WHERE
    Emp_id = e AND Act_id = a
    AND IIF (IsNull(y), IsNull(Year), Year = y)
    AND IIF (IsNull(w), IsNull(Weak), Weak = w)
    

    Foi a ideia de @mpag para o código de validação que me fez pensar no caminho certo.

    • 1
  5. paparazzo
    2016-06-16T13:05:22+08:002016-06-16T13:05:22+08:00

    Você pode fazer muitas coisas, mas inteiro e texto não são classificados da mesma forma.

    O texto interromperia uma pesquisa na semana > 6.
    No texto 10, 11, 12 não são > 6.

    Eu usaria 0 para nenhuma data

    Não que o tamanho seja grande coisa, mas você usaria tinyint para semana e smallint para ano

    um varchar é do tamanho de um smallint

    • 0

relate perguntas

  • Consultar o banco de dados Linked Access no compartilhamento de rede via SQL Job Agent

  • Existe algum benefício de uma chave primária que compreende todas as colunas da tabela?

  • Remova o campo da chave composta e reúna os dados duplicados

  • Quais são as desvantagens de usar UUID ou GUID como chave primária?

  • Chaves primárias de caractere x número inteiro

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