Fórum SQL - Pesquisa Numérica com Limitador - É POSSÍVEL !!! #522340

09/06/2015

0

Olá pessoal. Estou com um problema e caso alguém puder me ajudar agradeço antecipadamente a sua atenção.

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

Rogerio

Responder

Posts

09/06/2015

Marcos P

Você não vai conseguir resolver isso aí com um unico select, ainda mais no Firebird !

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í...
Responder

Gostei + 0

10/06/2015

Marisiana Battistella

Rogerio, qual é o banco de dados que vc está utilizando?
Responder

Gostei + 0

10/06/2015

Marisiana Battistella

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?

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;
Responder

Gostei + 0

10/06/2015

Cauê Nishijima

Rogerio, tem como gerar o sql de criação e população do banco de dados, pra eu ter uma base pra fazer uns testes aqui, se der me mande por email, caue_nishijima@yahoo.com.br

Mas acredito que você tenha que criar o SQL dinamicamente no Delphi.
Responder

Gostei + 0

10/06/2015

Rogerio

Utilizo o Banco de Dados Firebird 2.0 - IBExpert -
Minha intensão seria realizar esta pesquisa com um comando SELECT...
Responder

Gostei + 0

10/06/2015

Rogerio

Olá Marisiana, agradeço por sua contribuição, contudo o problema está sendo em limitar a seleção do registro e não a quantidade de registro...

""
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
""
Responder

Gostei + 0

10/06/2015

Rogerio

Olá Cauê Nishijima, muito obrigado por participar, a intenção é achar uma solução para que esta pesquisa "Select" seja feita direta no IBExpert, esta situação que descrevi, está na faze de um projeto que estou acompanhando, nada foi criado... e sei que o problema existe, e disseram que não teria como....por ser um cara chato, comprei esta briga mesmo sabendo que meu conhecimento em SQL é intermediário...
Responder

Gostei + 0

10/06/2015

Rogerio

Olá, Marcos P... o que você disse, "Você não vai conseguir resolver isso aí com um unico select, ainda mais no Firebird !!!" ... foi que mesmo que me levou a tentar resolver... quantos mais ouço ou recebo...."NÃO..." ou...."É IMPOSSIVEL..." ....................mais quero tentar... Obrigado...
Responder

Gostei + 0

10/06/2015

Cauê Nishijima

Olá Rogerio, esse problema não é tão complicado, pra resolver isso, criei uma tabela no mysql pra simular, mas acredito que funcione no firebird tbm.
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.
Responder

Gostei + 0

10/06/2015

Emerson Nascimento

tente assim (testado no FB 2.5.1):

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.
Responder

Gostei + 0

10/06/2015

Marcos P

Excelente Emerson... parabéns !


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 !
Responder

Gostei + 0

10/06/2015

Marcos P

Fui por outro caminho e resolvi com...

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 !
Responder

Gostei + 0

11/06/2015

David Sylvestre

Pequeno teste em sql server
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)
Responder

Gostei + 0

11/06/2015

Marcos P

David,

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 ?
Responder

Gostei + 0

11/06/2015

David Sylvestre

David,

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.
Responder

Gostei + 0

Utilizamos cookies para fornecer uma melhor experiência para nossos usuários, consulte nossa política de privacidade.

Aceitar