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 / 167778
Accepted
Maury Markowitz
Maury Markowitz
Asked: 2017-03-22 10:10:57 +0800 CST2017-03-22 10:10:57 +0800 CST 2017-03-22 10:10:57 +0800 CST

Analisar uma coluna com um "intervalo" em um WHERE no SQL Server

  • 772

Estou consultando uma tabela que possui várias colunas de chave alfanumérica...

KEY1  KEY2  KEY3 ... SOMEDATA  SOMEOTHERDATA...
s001
s002
s003  s004  s005
s006

As chaves são o PK de outra mesa em que precisamos nos juntar, o que é irritante, mas não difícil. Mas então eles decidiram fazer isso...

s010-s105

O que significa s010, s011...s015. Existe alguma maneira de fazer uma consulta que quebre isso para que eu possa encontrar uma determinada chave, digamos s013, nessas colunas?

sql-server sql-server-2012
  • 4 4 respostas
  • 222 Views

4 respostas

  • Voted
  1. Lamak
    2017-03-22T10:46:23+08:002017-03-22T10:46:23+08:00

    Tudo bem, por favor, não me odeie por esta consulta, porque tenho certeza de que existem maneiras muito melhores de fazer isso (começando corrigindo esse design). Com os dados de exemplo que você postou, essa consulta deve fornecer todas as chaves da tabela original como uma única coluna ( KEY_Unified):

    WITH CTE AS
    (
        SELECT *
        FROM dbo.YourTable t
        CROSS APPLY 
        (
            VALUES
                (t.KEY1),
                (t.KEY2),
                (t.KEY3)
        ) x (KEY_Unified)
        WHERE x.KEY_Unified IS NOT NULL
    ), CTE2 AS
    (
        SELECT  KEY_Unified, 
                CAST(RIGHT(LEFT(KEY_Unified,CHARINDEX('-',KEY_Unified,0)-1),3) AS INT) Start,
                CAST(RIGHT(SUBSTRING(KEY_Unified,CHARINDEX('-',KEY_Unified,0)+1,4),3) AS INT) Finish
        FROM CTE 
        WHERE KEY_Unified LIKE '%-%'
    ), CTE3 AS 
    (
        SELECT 's' + RIGHT('000' + CAST(B.number AS VARCHAR(3)),3) KEY_Range, CAST(B.number AS VARCHAR(3)) n
        FROM CTE2 A
        CROSS JOIN (SELECT *
                    FROM master.dbo.spt_values
                    WHERE type = 'P') B
        WHERE B.number BETWEEN A.Start AND A.Finish
    ), CTE4 AS
    (
        SELECT KEY_Unified
        FROM CTE
        WHERE KEY_Unified NOT LIKE '%-%'
        UNION
        SELECT KEY_Range
        FROM CTE3
    )
    SELECT *
    FROM CTE4 t1
    LEFT JOIN SomeOtherTable t2
        ON t1.KEY_Unified = t2.SomeKey
    ;
    

    Há um par de suposições embora.

    • O único tipo de intervalo que você pode ter é este tipo: s001-s100, você não pode ter, s001-s100,s005-s006 por exemplo
    • Cada chave tem um comprimento de 4 caracteres, começando com s001atés999
    • 3
  2. SqlZim
    2017-03-22T10:46:14+08:002017-03-22T10:46:14+08:00

    Se você tiver uma tabela de números, poderá analisar as duas partes do intervalo e juntar-se à sua tabela de números. Então você só precisa formatá-lo de volta para como sua chave de junção está formatada.

    create table t (key1 varchar(10),key2 varchar(10),key3 varchar(10));
    insert into t values ('s001',null,null),('s010-s105',null,null),('s002','s003','s004');
    /* numbers table substitute for demo*/
    ;with n as (select n from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(n))
    , numbers as (
      select n = row_number() over(order by (select 1))-1
      from n as deka cross join n as hecto cross join n as kilo 
                     cross join n as tenK cross join n as hundredK
    )
    select 
        t.key1
      , x.*
      , joinKey = left(key1,1)+right('000'+convert(varchar(10),n.n),3)
    from t 
      cross apply (values (key1),(key2),(key3)
        ) as u (keyN)
      cross apply (values (stuff(left(u.keyN,charindex('-',u.keyN+'-')-1),1,1,'')
                          ,stuff(u.keyN,1,charindex('-',u.keyN)+1,''))
        ) as x (fromkey,thrukey)
      left join numbers n
        on n >= try_convert(int,fromkey)
       and n <= try_convert(int,thrukey)
    where u.keyN is not null
    

    demonstração do rextester : http://rextester.com/KAJ77714

    retorna:

    +-----+-----------+---------+---------+---------+
    |     |   key1    | fromkey | thrukey | joinKey |
    +-----+-----------+---------+---------+---------+
    |   1 | s001      |     001 |     001 | s001    |
    |   2 | s002      |     002 |     002 | s002    |
    |   3 | s002      |     003 |     003 | s003    |
    |   4 | s002      |     004 |     004 | s004    |
    |   5 | s010-s105 |     010 |     105 | s010    |
    |   6 | s010-s105 |     010 |     105 | s011    |
    |   7 | s010-s105 |     010 |     105 | s012    |
    |   8 | s010-s105 |     010 |     105 | s013    |
    |   9 | s010-s105 |     010 |     105 | s014    |
    ...
    |  97 | s010-s105 |     010 |     105 | s102    |
    |  98 | s010-s105 |     010 |     105 | s103    |
    |  99 | s010-s105 |     010 |     105 | s104    |
    | 100 | s010-s105 |     010 |     105 | s105    |
    +-----+-----------+---------+---------+---------+
    

    Referência da tabela de números:

    • Gerar um conjunto ou sequência sem loops - 1 - Aaron Bertrand
    • Gerar um conjunto ou sequência sem loops - 2 - Aaron Bertrand
    • Gerar um conjunto ou sequência sem loops - 3 - Aaron Bertrand
    • A tabela "Numbers" ou "Tally": o que é e como substitui um loop - Jeff Moden
    • 1
  3. Best Answer
    Nelson
    2017-03-22T10:57:51+08:002017-03-22T10:57:51+08:00

    T-SQL - 246 Bytes

    Rapido e sujo:

    create table #DataInRanges (KeyId varchar(10), FirstName varchar(10), LastName varchar(10));
    
    insert into #DataInRanges (KeyId, FirstName, LastName) values
    ('s010-s015', 'Nelson', 'Casanova'),
    ('s009-s010', 'Karl', 'Johnson'),
    ('s090-s110', 'Michael', 'Buxton'),
    ('s079-s080', 'Terrence', 'Dickson'),
    ('s010-s030', 'Mario', 'Carrizo'),
    ('s025-s085', 'Victor', 'Lee'),
    ('s019-s040', 'Jim', 'Buckney'),
    ('s030-s110', 'Solomon', 'Bennett')
    
    declare @ANumber INT = 20;
    
    select * 
    from
    (
        select
            cast(replace(parsename(replace(KeyId, '-','.'),2), 's', '') as int) as Key1, 
            cast(replace(parsename(replace(KeyId, '-','.'),1), 's', '') as int) as Key2
        from #DataInRanges
    ) t
    where (@ANumber) between t.Key1 and t.Key2
    
    -----------
    |key1|key2|
    -----------
    | 10 | 30 |
    | 19 | 40 |
    -----------
    

    Com a ressalva de que o parsename não vai além de 4 níveis

    • 1
  4. Maury Markowitz
    2017-03-25T05:08:39+08:002017-03-25T05:08:39+08:00

    E eu adiciono mais um...

    Combinando parte do código acima junto com alguma manipulação básica de strings, o que fiz foi fazer uma consulta interna que retornou ambos os lados do sinal de menos em dois campos...

    select Substring(KEY1,CharIndex('-',KEY1)) as KEYF,
    Substring(KEY1,CharIndex('-',KEY1)+1,len(KEY1)) as KEYT
    from TheDumbTable
    where KEY1 like '%-%'
    

    Isso retorna algo como...

    -------------
    |KEYF |KEYT |
    -------------
    | S10 | S30 |
    | S19 | S40 |
    -------------
    

    Em seguida, envolvo isso em outra consulta que usa PATINDEX para separar os números dos numéricos ...

    SELECT cast(substring(KEYF,patindex('%[0-9]%', KEYF),len(KEYF)) as int) as KEYFINT,
           cast(substring(KEYT,patindex('%[0-9]%', KEYT),len(KEYT)) as int) as KEYTINT,
           replace(KEYF,substring(KEYF,patindex('%[0-9]%', KEYF),len(KEYF)),'') as KEYTEXT
    FROM
    (select Substring(KEY1,CharIndex('-',KEY1)) as KEYF,
    Substring(KEY1,CharIndex('-',KEY1)+1,len(KEY1)) as KEYT
    from TheDumbTable
    where KEY1 like '%-%') inside
    

    O resultado disso é algo como...

    -------------------------
    |KEYFINT|KEYTINT|KEYTEXT|
    -------------------------
    | 10    | 30    | S     |
    | 19    | 40    | S     |
    -------------------------
    

    Se alguém tiver uma boa maneira de combinar as duas consultas anteriores em uma, ficaria grato.

    A grande vantagem deste exemplo é que a parte TEXT da chave pode ser qualquer coisa, então este método funcionará com "ABC100" e "S10". O truque final é envolver essa consulta em outra que tenha seu WHERE...

    WHERE cast(substring('THETHINGYOUWANT',patindex('%[0-9]%', 'THETHINGYOUWANT'),len('THETHINGYOUWANT')) as int) 
    BETWEEN UNITMATCHINGRANGES.keyintfrom AND UNITMATCHINGRANGES.keyintto
    AND KEYTEXT LIKE replace('THETHINGYOUWANT',substring('THETHINGYOUWANT',patindex('%[0-9]%', 'THETHINGYOUWANT'),len('THETHINGYOUWANT')),''))
    

    A primeira parte puxa a parte numérica da chave que você está procurando e ENTRE isso, mas é claro que isso significa que "A100" e "B100" combinariam. Assim, a segunda parte extrai a parte NÃO numérica e a compara com a parte não numérica da chave no intervalo.

    Isso pressupõe que o intervalo sempre será algo como "A100-A999" e não "A100-B100"

    Suspeito que existam maneiras de simplificar drasticamente isso em uma consulta de uma ou duas etapas, mas por enquanto está funcionando!

    • 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