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 / 165719
Accepted
Federico Giust
Federico Giust
Asked: 2017-03-01 05:01:58 +0800 CST2017-03-01 05:01:58 +0800 CST 2017-03-01 05:01:58 +0800 CST

Gerar ID exclusivo com base em critérios de várias linhas

  • 772

Eu tenho o seguinte cenário, eu tenho uma tabela assim

| pid | itemId |
|-----|--------|
|123  | item1  |
|123  | item2  |
|234  | item1  |
|234  | item3  |
|456  | item1  |
|456  | item2  |
|567  | item1  |
|567  | item2  |
|567  | item3  |

Eu preciso obter um ID inteiro exclusivo com base na combinação exclusiva de itens. Portanto, se duas pessoas escolheram os mesmos itens, a combinação única deve ser o mesmo número.

Por exemplo:

| pid | itemId | comb |
|-----|--------|------|
|123  | item1  |  1   |
|123  | item2  |      |
|234  | item1  |  2   |
|234  | item3  |      |
|456  | item1  |  1   |
|456  | item2  |      |
|567  | item1  |  3   |
|567  | item2  |      |
|567  | item3  |      |

O número de combinações possíveis no momento está em torno de 300. Então, ao filtrar, pode ser mais fácil filtrar por apenas um número em uma coluna do que filtrar com vários critérios.

sql-server sql-server-2008-r2
  • 2 2 respostas
  • 10504 Views

2 respostas

  • Voted
  1. Best Answer
    Joe Obbish
    2017-03-01T17:03:01+08:002017-03-01T17:03:01+08:00

    Uma maneira de abordar esse problema é concatenar todos os valores de item para cada um PIDe atribuir um valor a eles usando a função de janela DENSE_RANK . Infelizmente, o SQL Server não facilita a concatenação de strings em um nível agregado até STRING_AGG() no SQL Server vNext. Como você está no SQL Server 2008, vou usar o FOR XMLmétodo de caminho de agregação de strings. Uma explicação desse método, juntamente com outras maneiras de fazê-lo, pode ser encontrada em Grouped Concatenation in SQL Server .

    Preparação de dados usando seus dados de amostra:

    CREATE TABLE #X165719 (
    PID INTEGER NOT NULL,
    ITEMID VARCHAR(10) NOT NULL
    );
    
    INSERT INTO #X165719
    VALUES 
    (123, 'item1'),
    (123, 'item2'),
    (234, 'item1'),
    (234, 'item3'),
    (456, 'item1'),
    (456, 'item2'),
    (567, 'item1'),
    (567, 'item2'),
    (567, 'item3');
    

    Primeiro vamos fazer a agregação de strings. Uma implementação é a seguinte:

    SELECT 
      PID
    , ITEMID
    , (
        SELECT ',' + SUB.ITEMID
        FROM #X165719 SUB
        WHERE SUB.PID = t1.PID
        ORDER BY SUB.ITEMID
        FOR XML PATH (''), TYPE).value('.', 'varchar(max)') all_items
    FROM #X165719 t1
    

    Você deve escolher um delimitador que não apareça em seus dados de origem, se possível. Eu usei uma vírgula. Aqui está a aparência do conjunto de resultados:

    ╔═════╦════════╦════════════════════╗
    ║ PID ║ ITEMID ║     all_items      ║
    ╠═════╬════════╬════════════════════╣
    ║ 123 ║ item1  ║ ,item1,item2       ║
    ║ 123 ║ item2  ║ ,item1,item2       ║
    ║ 234 ║ item1  ║ ,item1,item3       ║
    ║ 234 ║ item3  ║ ,item1,item3       ║
    ║ 456 ║ item1  ║ ,item1,item2       ║
    ║ 456 ║ item2  ║ ,item1,item2       ║
    ║ 567 ║ item1  ║ ,item1,item2,item3 ║
    ║ 567 ║ item2  ║ ,item1,item2,item3 ║
    ║ 567 ║ item3  ║ ,item1,item2,item3 ║
    ╚═════╩════════╩════════════════════╝
    

    Agora precisamos atribuir um número diferente para cada valor exclusivo na all_itemscoluna. Uma maneira de fazer isso é com a DENSE_RANKfunção. Citando o BOL:

    Retorna a classificação das linhas na partição de um conjunto de resultados, sem lacunas na classificação. A classificação de uma linha é um mais o número de classificações distintas que vêm antes da linha em questão.

    A última consulta é:

    SELECT 
      t2.PID
    , t2.ITEMID
    , DENSE_RANK() OVER (ORDER BY all_items) COMB
    FROM
    (
        SELECT 
          PID
        , ITEMID
        , (
            SELECT ',' + SUB.ITEMID
            FROM #X165719 SUB
            WHERE SUB.PID = t1.PID
            ORDER BY SUB.ITEMID
            FOR XML PATH (''), TYPE).value('.', 'varchar(max)') all_items
        FROM #X165719 t1
    ) t2;
    

    O conjunto de resultados final é:

    ╔═════╦════════╦══════╗
    ║ PID ║ ITEMID ║ COMB ║
    ╠═════╬════════╬══════╣
    ║ 123 ║ item1  ║    1 ║
    ║ 123 ║ item2  ║    1 ║
    ║ 456 ║ item1  ║    1 ║
    ║ 456 ║ item2  ║    1 ║
    ║ 567 ║ item1  ║    2 ║
    ║ 567 ║ item2  ║    2 ║
    ║ 567 ║ item3  ║    2 ║
    ║ 234 ║ item1  ║    3 ║
    ║ 234 ║ item3  ║    3 ║
    ╚═════╩════════╩══════╝
    
    • 1
  2. paparazzo
    2017-03-01T06:05:25+08:002017-03-01T06:05:25+08:00

    isso é um começo - são grupos que não correspondem 100%

    select t1.pID, t2.pID, t1.itemID 
    from table t1 
    full outer join table t2
     on t1.pID < t2.pID 
    and t1.itemID = t2.itemID 
    order by t1.pID, t2.pID, t1.itemID  
    where t1.pID is null or t2.pID is null
    

    isso é mais - ainda não feito

    with cte1 as 
    ( select pID, count(*) as cnt 
      from table 
      group by pID 
    ) 
    , cte2 as 
    ( select t1.pID as left, t2.pID as right, count(*) as cnt 
        from table t1 
        join table t2
         on t1.pID < t2.pID 
        and t1.itemID = t2.itemID 
      group by t1.pID, t2.pID 
    )
    , cte3 as 
    ( select comb.* 
        from cte1 as letft 
        join cte2 as comb
          on left.pID = comb.left 
         and left.cnt = comb.cnt
        join cte1 as right  
          on right.pID = comb.right 
         and right.cnt = comb.cnt  
    )
    

    problema aqui é se 1 combina com 3 e 5 vai dar
    1, 3
    1, 5
    3, 5

    , cte4 as 
    ( select unq.left, unq.right 
        from cte3 as unq 
        where not exists ( select 1 from cte3 cpy where cpy.lft = unq.right )
    )
    

    cte4.left são os grupos - agora precisa numerá-los

    , cte5 as 
    ( select cte4.left  
           , row_number() over ( order by unq.left ) as rn
        from cte4 as unq 
        group by cte4.left
    )
    

    Acho que é isso, mas não tenho certeza - tem que haver uma maneira mais esperta

    select base.pID, base.itemID, cte5.rn 
      from table base 
      join cte5 
        on cte5.left = base.itemID 
    union 
    select cpy.pID, cpy.itemID, cte5.rn 
      from table cpy 
      join cte4 
        on cte4.right = cpy.itemID 
      join cte5 
        on cte5.left = cte4.left  
     order by pID, itemID
    
    • 0

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