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 / 48562
Accepted
Dave Jarvis
Dave Jarvis
Asked: 2013-08-23 12:49:39 +0800 CST2013-08-23 12:49:39 +0800 CST 2013-08-23 12:49:39 +0800 CST

Conexão reversa por valor de nível anterior para hierarquia arbitrariamente profunda

  • 772

Fundo

Usando uma hierarquia de menu para conduzir um processo de login para usuários. Os usuários podem definir seu item de menu preferido. Quando eles fazem login, se tiverem um item de menu preferido definido, o sistema os direciona para esse item. Se nenhum item de menu preferido for definido, eles farão login no item de menu padrão para sua função "mais importante".

Código

A consulta usa connect by priorpara obter a lista de menus:

  SELECT
    LEVEL AS menu_level,
    t.name AS menu_name,
    t.id AS menu_id
  FROM
    jhs_menu_items t, (
      SELECT
        jmi.id
      FROM
        jhs_users ju
      JOIN jhs_user_role_grants jurg ON
        ju.id = jurg.usr_id
      LEFT OUTER JOIN user_menu_preferences ump ON
        ju.id = ump.jhs_usr_id
      LEFT OUTER JOIN default_menu_preferences dmp ON
        jurg.rle_id = dmp.jhs_rle_id
      JOIN jhs_menu_items jmi ON
        -- Retrieve the user's preferred menu item, failing to the default
        -- if no preference is set.
        jmi.id = coalesce(
          ump.jhs_menu_items_id,
          dmp.jhs_menu_items_id
        )
      WHERE
        ju.username = 'USERNAME' AND
        ROWNUM = 1
      ORDER BY
        dmp.role_priority_sort
    ) menu_preference

  -- Derive the menu hierarchy starting at the user's preference, going back to 
  -- the root menu item.
  START WITH t.id = menu_preference.id
  CONNECT BY PRIOR t.mim_id = t.id

Problema

Um item de menu raiz tem NULLcomo pai ( mim_id). A preferência de menu do usuário é um nó de folha de item de menu, que pode ser encontrado em qualquer nível na hierarquia (a profundidade máxima é 3, neste caso).

Quando os dados são retornados, os valores da LEVELpseudocoluna (alias MENU_LEVEL) estão na ordem inversa:

╔════════════╦═══════════╦══════════════╗
║ MENU_LEVEL ║ MENU_NAME ║ MENU_ITEM_ID ║
╠════════════╬═══════════╬══════════════╣
║          1 ║ MenuTab3  ║ 100436       ║
║          2 ║ MenuTab2  ║ 101322       ║
║          3 ║ MenuTab1  ║ 101115       ║
╚════════════╩═══════════╩══════════════╝

Isso realmente deve retornar:

╔════════════╦═══════════╦══════════════╗
║ MENU_LEVEL ║ MENU_NAME ║ MENU_ITEM_ID ║
╠════════════╬═══════════╬══════════════╣
║          3 ║ MenuTab3  ║ 100436       ║
║          2 ║ MenuTab2  ║ 101322       ║
║          1 ║ MenuTab1  ║ 101115       ║
╚════════════╩═══════════╩══════════════╝

No entanto, como a hierarquia connected bycomeça no item de menu preferido do usuário e trabalha de volta ao item de menu raiz, faz sentido LEVELcontar "para trás".

Ter o nível invertido significa que podemos perguntar: "Qual é o item de menu de terceiro nível para o usuário chamado 'USERNAME'"? Expresso como uma cláusula where do SQL:

WHERE menu_level = 3 AND username = 'USERNAME';

Pergunta

Como você inverteria o valor de LEVELpara uma hierarquia arbitrariamente profunda?

Por exemplo, algo como:

SELECT
  LEVEL AS MENU_LEVEL_UNUSED,
  max(LEVEL) - LEVEL + 1 AS MENU_LEVEL
FROM ...

Obviamente isso não vai funcionar porque maxé uma função agregada.

violino

http://sqlfiddle.com/#!4/60678/3/0

Estranhamente, estou vendo comportamentos diferentes na instância 11g R2 do Fiddle do que na instância local do Oracle - o ROWNUM está captando "1" no Fiddle quando deveria estar captando "3". Isso evita ver a hierarquia do menu e, portanto, o arquivo LEVEL. Não sei por quê.

Ideias

  • Poderíamos adicionar uma coluna para jhs_menu_itemsarmazenar a profundidade. Isso é um pouco redundante, porque a própria hierarquia contém essas informações.
  • Poderíamos envolver a jhs_menu_itemstabela em uma exibição que calcula a profundidade. Isso pode ficar computacionalmente caro.
  • Este é um bom candidato para WITH?
oracle hierarchy
  • 1 1 respostas
  • 7579 Views

1 respostas

  • Voted
  1. Best Answer
    Adam Musch
    2013-08-26T13:39:45+08:002013-08-26T13:39:45+08:00

    Você nunca pode consultar ROWNUM = 3; ROWNUM 1 é filtrado, então o próximo registro agora é ROWNUM = 1 e assim por diante.

    Suspeito que estar preocupado em controlar a profundidade computacional é uma otimização prematura. A menos que você tenha milhões de opções sendo retornadas para um único usuário, extrair o nível mais alto do conjunto de dados - ou mesmo extrair o nível mais alto de cada conjunto de dados deve ser bem simples. Não é como se você não pudesse explorar totalmente a hierarquia, então o trabalho adicional no mecanismo SQL de priorizar/ classificar cada janela de linhas é bastante leve em cima disso.

    Portanto, usar funções de agregação/janela parece ser uma escolha natural aqui.

    Seu SQLFiddle não retorna o conjunto de dados esperado, mas modifiquei o SQL abaixo para mostrar como você pode priorizá-los, supondo que eu entenda os requisitos que você está procurando.

    Rocha analítica.

    select menu_level, menu_name, menu_id
    from
    (
    select menu_level, menu_name, menu_id,
           row_number() over (partition by menu_name order by menu_level desc) as menu_priority
    from
    (
    SELECT
        LEVEL AS menu_level,
        t.name AS menu_name,
        t.id AS menu_id
      FROM
        jhs_menu_items t, (
          SELECT
            jmi.id
          FROM
            jhs_users ju
          JOIN jhs_user_role_grants jurg ON
            ju.id = jurg.usr_id
          LEFT OUTER JOIN user_menu_preferences ump ON
            ju.id = ump.jhs_usr_id
          LEFT OUTER JOIN default_menu_preferences dmp ON
            jurg.rle_id = dmp.jhs_rle_id
          JOIN jhs_menu_items jmi ON
            -- Retrieve the user's preferred menu item, failing to the default
            -- if no preference is set.
            jmi.id = coalesce(
              ump.jhs_menu_items_id,
              dmp.jhs_menu_items_id
            )
          WHERE
            ju.username = 'adminname' 
    --      AND ROWNUM = 1
          ORDER BY
            dmp.role_priority_sort
        ) menu_preference
    
      -- Derive the menu hierarchy starting at the user's preference, going back to 
      -- the root menu item.
      START WITH t.id = menu_preference.id
      CONNECT BY PRIOR t.mim_id = t.id
      )
    )
     where menu_priority = 1
     order by menu_name
    
    MENU_LEVEL  MENU_NAME   MENU_ID
            3   MenuTab1    1
            2   MenuTab2    2
            1   MenuTab3    3
    
    • 1

relate perguntas

  • ORDER BY usando prioridades personalizadas para colunas de texto

  • Interface sqlplus confortável? [fechado]

  • Como encontrar as instruções SQL mais recentes no banco de dados?

  • Como posso consultar nomes usando expressões regulares?

  • Atravessando dados semelhantes a árvores em um banco de dados relacional usando SQL

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