Fórum SQL - Pesquisa Numérica com Limitador - É POSSÍVEL !!! #522340
09/06/2015
0
Utilizo o Banco de Dados Firebird 2.0
Tenho uma tabela TBDIRETRIZES que contem os campos e dados ...
CODIGO INTEGER NOT NULL,
META01 INTEGER,
META02 INTEGER,
META03 INTEGER,
META04 INTEGER,
META05 INTEGER,
META06 INTEGER,
META07 INTEGER,
META08 INTEGER,
META09 INTEGER,
.
.
.
META40 INTEGER
...
<< DADOS >>
CODIGO META01 META02 META03 META04 META05 META06 META07 META08 META09 ... META40
000001 125 348 530 855 600 245 43 71 92 54
000002 126 347 531 851 602 242 42 78 98 66
000003 127 346 532 852 603 125 43 72 97 57
000004 128 345 533 853 604 243 44 73 96 59
000005 129 344 534 854 605 244 45 74 91 52
000006 120 344 535 855 125 247 46 75 92 51
000007 121 348 536 856 606 246 43 92 88 125
000008 121 348 536 856 606 246 43 92 88 57
...
*** Como predefinição NENHUM registro conterá o mesmo valor duas vezes...
Portanto o valor 125 NÃO poderá estar no registro 000001 em mais de um campo, Ex: META01 e META07.
Observe :
000001 META01 = 125
000003 META06 = 125
000006 META05 = 125
000007 META40 = 125
Se fosse passado apenas um numero como pesquisa poderia compará-lo aos campos e localizar os registro que me interessa, mas o problema que poderá ser passado até 10 números e com um limitador MINIMO de quantidade a serem filtrados...
Serão passados os numeros a serem localizados, JUNTAMENTE COM SEU LIMITADOR MIN:
125, 43, 92 MIN de 2 dos TRES NUMEROS
ou
128, 44, 59 MIN de 1 dos TRES NUMEROS
ou
120,344,535,855,125,247,46,75,92,51 MIN de 7 dos DEZ NUMEROS
Utilizando o PRIMEIRO EXEMPLO:
125, 43, 92 MIN de 2 dos TRES NUMEROS===> neste caso apenas os registros 000001 e 000007 conteriam os TRÊS números.
MAS... o limitador MINIMO são de 2 números dos 3.
Portanto...
NECESSITO QUE OS REGISTROS COM 3 DOS 3 APAREÇAM
000001 125 348 530 855 600 245 43 71 92 54
000007 121 348 536 856 606 246 43 92 88 125
E NECESSITO QUE OS REGISTROS COM 2 DOS 3 TAMBÉM APAREÇAM, pois o limitador minimo são 2 numeros dos 3.
000003 127 346 532 852 603 125 43 72 97 57
000006 120 344 535 855 125 247 46 75 92 51
000008 121 348 536 856 606 246 43 92 88 57
Precisava de um SELECT que filtrasse os registros que contivessem os 'N' Números passados e obedecendo o limitador...
Existe alguma maneira de fazer esta pesquisa utilizando os campos de entrada e um valor LIMITADOR ... UTILIZANDO UM SELECT ou criando outra tabela ou VIEW?
SOCORRO !!!
Att. Rogerio SanVieira
Rogerio
Curtir tópico
+ 0Posts
09/06/2015
Marcos P
Não seria mais facil implementar um select simples e tratar isso do lado da aplicação ?
Um loop simples, varrendo sequencialmente os registros da tabela, resolve isso aí...
Gostei + 0
10/06/2015
Marisiana Battistella
Gostei + 0
10/06/2015
Marisiana Battistella
Sim Rogério, existe!
Tanto o MySQL quanto o Postgresql suportam um recurso muito útil para paginação de resultados, chamado de OFFSET, normalmente utilizado com LIMIT.
A cláusula LIMIT é utilizada para limitar o número de resultados de uma SQL. Então, se sua SQL retornar 1000 linhas, mas você quer apenas as 10 primeiras, você deve executar uma instrução mais ou menos assim:
SELECT coluna FROM tabela LIMIT 10;
Agora, vamos supor que você quer somente os resultados de 11 a 20. Com a instrução OFFSET fica fácil, basta proceder da seguinte forma:
SELECT coluna FROM tabela LIMIT 10 OFFSET 10;
O comando OFFSET indica o início da leitura, e o LIMIT o máximo de registros a serem lidos. Para os registros de 61 a 75, por exemplo:
SELECT coluna FROM tabela LIMIT 15 OFFSET 60;
Com este recurso, fica fácil paginar os resultados de uma SQL e mostrar ao usuário apenas a página, ao invés de retornar todos os registros da tabela. Uma tabela com 2000 registros, por exemplo, fica muito melhor mostrar ao usuário de 10 em 10, por exemplo, e diminui a carga no banco de dados, melhorando a sua performance.
fonte: [url]http://blog.hallanmedeiros.com/2011/11/23/sql-paginando-resultados-com-limit-e-offset/[/url]
No Oracle utiliza-se o ROWNUM:
SELECT * FROM Persons WHERE ROWNUM <=5;
Gostei + 0
10/06/2015
Cauê Nishijima
Mas acredito que você tenha que criar o SQL dinamicamente no Delphi.
Gostei + 0
10/06/2015
Rogerio
Minha intensão seria realizar esta pesquisa com um comando SELECT...
Gostei + 0
10/06/2015
Rogerio
""
Se fosse passado apenas um numero como pesquisa poderia compará-lo aos campos e localizar os registro que me interessa, mas o problema que poderá ser passado até 10 números e com um limitador MINIMO de quantidade a serem filtrados...
Serão passados os numeros a serem localizados, JUNTAMENTE COM SEU LIMITADOR MIN:
125, 43, 92 MIN de 2 dos TRES NUMEROS
ou
128, 44, 59 MIN de 1 dos TRES NUMEROS
ou
120,344,535,855,125,247,46,75,92,51 MIN de 7 dos DEZ NUMEROS
Utilizando o PRIMEIRO EXEMPLO:
125, 43, 92 MIN de 2 dos TRES NUMEROS===> neste caso apenas os registros 000001 e 000007 conteriam os TRÊS números.
MAS... o limitador MINIMO são de 2 números dos 3.
Portanto...
NECESSITO QUE OS REGISTROS COM 3 DOS 3 APAREÇAM
000001 125 348 530 855 600 245 43 71 92 54
000007 121 348 536 856 606 246 43 92 88 125
E NECESSITO QUE OS REGISTROS COM 2 DOS 3 TAMBÉM APAREÇAM, pois o limitador minimo são 2 numeros dos 3.
000003 127 346 532 852 603 125 43 72 97 57
000006 120 344 535 855 125 247 46 75 92 51
000008 121 348 536 856 606 246 43 92 88 57
""
Gostei + 0
10/06/2015
Rogerio
Gostei + 0
10/06/2015
Rogerio
Gostei + 0
10/06/2015
Cauê Nishijima
Dei o nome da tabela de numeros, e fiz a tabela com as colunas codigo e meta01 até meta10, ai você precisa adaptar as suas necessidades:
SELECT * FROM numeros WHERE
codigo in (
SELECT y.codigo FROM
(
SELECT *, COUNT(*) AS QTD FROM
(
SELECT codigo FROM numeros where meta01 in (2,4,8)
UNION ALL
SELECT codigo FROM numeros WHERE meta02 in (2,4,8)
UNION ALL
SELECT codigo FROM numeros WHERE meta03 in (2,4,8)
UNION ALL
SELECT codigo FROM numeros WHERE meta04 in (2,4,8)
UNION ALL
SELECT codigo FROM numeros WHERE meta05 in (2,4,8)
UNION ALL
SELECT codigo FROM numeros WHERE meta06 in (2,4,8)
UNION ALL
SELECT codigo FROM numeros WHERE meta07 in (2,4,8)
UNION ALL
SELECT codigo FROM numeros WHERE meta08 in (2,4,8)
UNION ALL
SELECT codigo FROM numeros WHERE meta09 in (2,4,8)
UNION ALL
SELECT codigo FROM numeros WHERE meta10 in (2,4,8)
) x
GROUP BY CODIGO
) y
WHERE
y.qtd >= 2
)
Onde (2,4,8) são os números que estamoes pesquisando, e o 2 no final é o limitador minimo de quantidade.
Não achei uma solução muito atraente porque o sql cresce de acordo com o numero de colunas, se alguém souber como refatorar pra fazer um looping percorrendo todas as colunas, ficaria mais elegante a solução.
Espero ter ajudado, abraços.
Gostei + 0
10/06/2015
Emerson Nascimento
SELECT TBD.* FROM TBDIRETRIZES TBD INNER JOIN (SELECT CODIGO, (CASE WHEN META01 IN (125, 43, 92) THEN 1 ELSE 0 END)+ (CASE WHEN META02 IN (125, 43, 92) THEN 1 ELSE 0 END)+ (CASE WHEN META03 IN (125, 43, 92) THEN 1 ELSE 0 END)+ (CASE WHEN META04 IN (125, 43, 92) THEN 1 ELSE 0 END)+ (CASE WHEN META05 IN (125, 43, 92) THEN 1 ELSE 0 END)+ (CASE WHEN META06 IN (125, 43, 92) THEN 1 ELSE 0 END)+ (CASE WHEN META07 IN (125, 43, 92) THEN 1 ELSE 0 END)+ (CASE WHEN META08 IN (125, 43, 92) THEN 1 ELSE 0 END)+ (CASE WHEN META09 IN (125, 43, 92) THEN 1 ELSE 0 END)+ (CASE WHEN META10 IN (125, 43, 92) THEN 1 ELSE 0 END)+ (CASE WHEN META11 IN (125, 43, 92) THEN 1 ELSE 0 END)+ (CASE WHEN META12 IN (125, 43, 92) THEN 1 ELSE 0 END)+ (CASE WHEN META13 IN (125, 43, 92) THEN 1 ELSE 0 END)+ (CASE WHEN META14 IN (125, 43, 92) THEN 1 ELSE 0 END)+ (CASE WHEN META15 IN (125, 43, 92) THEN 1 ELSE 0 END)+ (CASE WHEN META16 IN (125, 43, 92) THEN 1 ELSE 0 END)+ (CASE WHEN META17 IN (125, 43, 92) THEN 1 ELSE 0 END)+ (CASE WHEN META18 IN (125, 43, 92) THEN 1 ELSE 0 END)+ (CASE WHEN META19 IN (125, 43, 92) THEN 1 ELSE 0 END)+ (CASE WHEN META20 IN (125, 43, 92) THEN 1 ELSE 0 END) QTD FROM TBDIRETRIZES WHERE (META01 IN (125, 43, 92) OR META02 IN (125, 43, 92) OR META03 IN (125, 43, 92) OR META04 IN (125, 43, 92) OR META05 IN (125, 43, 92) OR META06 IN (125, 43, 92) OR META07 IN (125, 43, 92) OR META08 IN (125, 43, 92) OR META09 IN (125, 43, 92) OR META10 IN (125, 43, 92) OR META11 IN (125, 43, 92) OR META12 IN (125, 43, 92) OR META13 IN (125, 43, 92) OR META14 IN (125, 43, 92) OR META15 IN (125, 43, 92) OR META16 IN (125, 43, 92) OR META17 IN (125, 43, 92) OR META18 IN (125, 43, 92) OR META19 IN (125, 43, 92) OR META20 IN (125, 43, 92))) T ON T.CODIGO = TBD.CODIGO AND T.QTD >= 2
note que a lista precisa ser repetida nos dois conjuntos de análises e, para efeito de testes, eu avaliei somente 20 das 40 metas.
o campo QTD é o limitador que você procura.
Gostei + 0
10/06/2015
Marcos P
Rogerio,
Quanto a vontade de resolver com apenas "um select", não julguei possível por ter pensado em criar uma procedure que desmembrasse esses dados ( com um loop ) e gerasse o resultado. É o tipo de coisa que quando você tem uma primeira ideia, fica difícil de fugir dela ( ainda mais sem testar... ).
Que bom que podemos compartilhar, ambos, de uma solução tão elegante quanto a que foi dada pelo Emerson !
Gostei + 0
10/06/2015
Marcos P
create table #Simples (Codigo int not null, Meta int )
insert #Simples (Codigo, Meta ) select Codigo, Meta01 from TBDIRETRIZES
insert #Simples (Codigo, Meta ) select Codigo, Meta02 from TBDIRETRIZES
insert #Simples (Codigo, Meta ) select Codigo, Meta03 from TBDIRETRIZES
insert #Simples (Codigo, Meta ) select Codigo, Meta04 from TBDIRETRIZES
insert #Simples (Codigo, Meta ) select Codigo, Meta05 from TBDIRETRIZES
insert #Simples (Codigo, Meta ) select Codigo, Meta06 from TBDIRETRIZES
insert #Simples (Codigo, Meta ) select Codigo, Meta07 from TBDIRETRIZES
insert #Simples (Codigo, Meta ) select Codigo, Meta08 from TBDIRETRIZES
insert #Simples (Codigo, Meta ) select Codigo, Meta09 from TBDIRETRIZES
insert #Simples (Codigo, Meta ) select Codigo, Meta10 from TBDIRETRIZES
insert #Simples (Codigo, Meta ) select Codigo, Meta11 from TBDIRETRIZES
insert #Simples (Codigo, Meta ) select Codigo, Meta12 from TBDIRETRIZES
insert #Simples (Codigo, Meta ) select Codigo, Meta13 from TBDIRETRIZES
insert #Simples (Codigo, Meta ) select Codigo, Meta14 from TBDIRETRIZES
insert #Simples (Codigo, Meta ) select Codigo, Meta15 from TBDIRETRIZES
insert #Simples (Codigo, Meta ) select Codigo, Meta16 from TBDIRETRIZES
insert #Simples (Codigo, Meta ) select Codigo, Meta17 from TBDIRETRIZES
insert #Simples (Codigo, Meta ) select Codigo, Meta18 from TBDIRETRIZES
insert #Simples (Codigo, Meta ) select Codigo, Meta19 from TBDIRETRIZES
insert #Simples (Codigo, Meta ) select Codigo, Meta20 from TBDIRETRIZES
select meta, codigo, count(1) as Count
into #Total
from #simples
where meta IN (1, 8, 4)
group by meta, codigo
select TBD.*
from TBDIRETRIZES TBD INNER JOIN (select codigo,sum(count) QTD
from #Total
group by codigo
having sum(count) >= 3) TOT on TBD.CODIGO = TOT.CODIGO
Esse código, que fiz no Sql Server e pode ser adaptado com facilidade para o FB, não é tão elegante quanto o do Emerson... mas funciona !
Gostei + 0
11/06/2015
David Sylvestre
DECLARE @foo TABLE (ID INT IDENTITY,
CODIGO INT,
M1 INT,
M2 INT,
M3 INT)
INSERT INTO @foo (CODIGO, M1, M2, M3)
SELECT 1, 1, 2, 3 UNION ALL
SELECT 2, 4, 5, 6 UNION ALL
SELECT 3, 6, 7, 8 UNION ALL
SELECT 4, 1, 9, 10 UNION ALL
SELECT 5, 12, 1, 18 UNION ALL
SELECT 6, 17, 4, 12
SELECT DISTINCT
t.*
FROM (
SELECT ID, Meta = M1 FROM @foo union all
SELECT ID, Meta = M2 FROM @foo union all
SELECT ID, Meta = M3 FROM @foo
)RS
INNER JOIN @foo t ON t.ID = rs.ID
WHERE rs.Meta IN (1, 12, 17)Gostei + 0
11/06/2015
Marcos P
Bom dia !
Não identifiquei na sua query o tratamento do limitador que é o "X" da questão proposta pelo Rogério.
Será que entendi errado seu script ?
Gostei + 0
11/06/2015
David Sylvestre
Bom dia !
Não identifiquei na sua query o tratamento do limitador que é o "X" da questão proposta pelo Rogério.
Será que entendi errado seu script ?
Não entendeu errado, isso é apenas uma forma mais simples de identificar os códigos que contém as metas desejadas. Realizar a contagem e determinar o limite do contador fica simples depois disso.
Gostei + 0
Clique aqui para fazer login e interagir na Comunidade :)