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 / 201898
Accepted
Philᵀᴹ
Philᵀᴹ
Asked: 2018-03-22 06:23:29 +0800 CST2018-03-22 06:23:29 +0800 CST 2018-03-22 06:23:29 +0800 CST

ORDER definido pelo usuário no SQL [duplicado]

  • 772
Essa pergunta já tem respostas aqui :
Ordenação arbitrária de registros em uma tabela (6 respostas)
Definir ordem dos 10 principais produtos manualmente no banco de dados (2 respostas)
Fechado há 4 anos .

Acabei de ler um artigo de blog interessante sobre a ordenação do conjunto de resultados definido pelo usuário.

Alguns aplicativos, como listas de tarefas, precisam manter uma ordem de itens definida pelo usuário. O desafio é que a ordem é arbitrária e pode mudar quando o usuário reorganiza os itens

Uma tabela de exemplo poderia ser assim:

create table items
(
  itemid int primary key,
  itemdata varchar(200),
  ...
  ...
  userorder ??? 
);

Com uma possível consulta de recuperação de:

select * from items order by userorder asc;

Há alguma abordagem que eu deva considerar, já que gostaria de manter as atualizações no mínimo, atualizações atômicas e consultas de recuperação o mais simples e "desempenhadas" possível?

Meu pensamento inicial era usar uma TIMESTAMPcoluna extra e atualizar apenas userordere os timestampvalores para uma única linha (com a consulta de recuperação usando ORDERing by userorder asc, usertimestamp desc), mas isso falha quando você precisa mover uma linha entre duas outras linhas que têm o mesmo valor .

Nenhum banco de dados específico em mente, pois eu mesmo uso um amplo espectro.

order-by
  • 2 2 respostas
  • 1939 Views

2 respostas

  • Voted
  1. Jack Douglas
    2018-03-23T09:46:14+08:002018-03-23T09:46:14+08:00

    Há alguma abordagem que eu deva considerar, já que gostaria de manter as atualizações no mínimo, atualizações atômicas e consultas de recuperação o mais simples e "desempenhadas" possível?

    Eu penso nisso como uma variação esotérica da abordagem "True Fractions" naquela postagem do blog - a vantagem é que não há necessidade de introduzir um tipo definido pelo usuário (pelo menos se você estiver usando o Postgres).

    Isso funciona usando as propriedades de ordenação natural varbite mapeando uma sequência delas em uma árvore binária, de modo que sempre seja possível gerar outro varbitvalor entre quaisquer dois valores adjacentes existentes:

                              _____ 1 ____
                       ______/            \______
                  _ 01 _                          11
                _/      \_                    _/      \_
            001            011            101            111
           /   \          /   \          /   \          /   \
        0001   0011    0101   0111    1001   1011    1101    1111
    
    create table foo(id serial primary key, userorder varbit unique);
    
    create function adj(orig varbit, b varbit) returns varbit language sql as $$
      select substring(orig for length(orig)-1)
           ||b
           ||substring(orig from length(orig));
    $$;
    
    create function f(l varbit, h varbit) returns varbit language plpgsql as $$
    
    begin
      if l is null and h is null then return B'1'; end if;
      if l is null then return adj(h,B'0'); end if;
      if h is null then return adj(l,B'1'); end if;
      if length(l)>length(h) then return adj(l,B'1'); end if;
      return adj(h,B'0');
    end;
    $$;
    
    insert into foo(userorder) values(f(null,null));
    select * from foo order by userorder;
    
    identificação | ordem do usuário
    -: | :--------
     1 | 1        
    
    insert into foo(userorder) values(f(null,B'1'));
    select * from foo order by userorder;
    
    identificação | ordem do usuário
    -: | :--------
     2 | 01       
     1 | 1        
    
    insert into foo(userorder) values(f(B'01',B'1'));
    select * from foo order by userorder;
    
    identificação | ordem do usuário
    -: | :--------
     2 | 01       
     3 | 011      
     1 | 1        
    
    insert into foo(userorder)
    values(f(B'01',B'011')),(f(B'011',B'1')),(f(B'1',null));
    
    select * from foo order by userorder;
    
    identificação | ordem do usuário
    -: | :--------
     2 | 01       
     4 | 0101     
     3 | 011      
     5 | 0111     
     1 | 1        
     6 | 11       
    

    dbfiddle aqui

    Se você carregar inicialmente muitas linhas ordenadas, talvez queira usar algum outro algoritmo para gerar os userordervalores iniciais, pois atingirá o pior caso para uso de espaço (cada linha usará um bit a mais do userorderque a linha anterior). Você pode percorrer valores de mesmo comprimento para um número suficientemente grande de bits (por exemplo, para 8 valores: B'0001', B'0011', B'0101', B'0111', B'1001', B'1011', B'1101', B'1111').

    • 5
  2. Best Answer
    Michael Kutz
    2018-03-22T10:33:35+08:002018-03-22T10:33:35+08:00

    Introdução

    Algumas linguagens BASIC realmente antigas exigiam um número de linha para cada linha de código.

    Ao programar, os números de linha eram normalmente espaçados em múltiplos de 10. Isso permitia que você adicionasse mais código entre as linhas posteriormente.

    Sua itemstabela deve seguir o mesmo conceito.

    Algoritmo básico

    1. Valores para userordercomeçar como múltiplos de 10 começam com 10 para cadauserid
    2. Atualizações de aplicativos userorderconforme necessário
    3. Você renumera o usuário desse usuário userorderusando o Analytics
    4. Os valores para 'userorder' permanecem como múltiplos de 10.
    5. commitos dados mudam.

    Código de renumeração

    Isso é basicamente o que eu usei:

    merge into items a
    using (
      select i.itemid
        ,10 * row_number() over (partition by i.userid order by i.userorder)
          as new_userorder
      from items i
      where i.userid=?
    ) b
    on (a.itemid = b.itemid)
    when matched then update
      set a.userorder=b.new_userorder
    ;
    

    Estou assumindo que esta tabela contém a lista TODO de todos e cada usuário é identificado por userid.

    Este exemplo usa ROW_NUMBER()do Oracle. Você terá que substituí-lo por qualquer RDBMS que estiver usando.

    • 2

relate perguntas

  • Como fazer ordenação condicional para duas ou mais colunas

  • MySQL: ORDER BY condicional para apenas uma coluna

  • A classificação de uma instrução ORDER BY pode ser salva explicitamente com apenas uma instrução UPDATE?

  • Usar ordem de outra cláusula select

  • adicionar um pedido por a esta consulta retorna mais rápido do que sem, por quê?

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