Evitando múltiplas expressões `ou`

13

Eu tenho o seguinte oracle SQL e seus trabalhos e tudo, mas é bastante feio com todos os ors. Existe uma maneira mais concisa de fazer isso?

SELECT * FROM foobar WHERE
  (SUBJECT ='STAT' and TERM ='111') or  
  (SUBJECT ='STAT' and TERM ='222') or  
  (SUBJECT ='ENGLISH' and TERM ='555') or 
  (SUBJECT ='COMM' and TERM ='444') or
  (SUBJECT ='COMM' and TERM ='333') or  
  (SUBJECT ='STAT' and TERM ='666')
  ...
Kyle Decot
fonte

Respostas:

21

Você pode preferir algo assim:

select *
from foobar
where (subject,term) in ( ('STAT','111')
                         ,('STAT','222')
                         ,('ENGLISH','555')
                         ,('COMM','444')
                         ,('COMM','333')
                         ,('STAT','222')
                         ,('STAT','666') 
                        );

DBFiddle aqui

Jack diz que tenta topanswers.xyz
fonte
2
Eu gostaria que o MS SQL Server tivesse essa sintaxe.
Ross Presser
@RossPresser Acho que há um item / sugestão do Connect para a sintaxe a ser adicionada. Você pode votar;)
ypercubeᵀᴹ
Descobri que não é algo mais ou menos como capaz:SELECT * FROM foobar INNER JOIN (SELECT * FROM (VALUES ('4','a'),('5','b')) AS myTable(subject,term)) ON myTable.subject=foobar.table and mytable.term=foobar.term
Ross Presser
mas eu gostaria dessa sintaxe real. Alguma idéia de onde está o item do Connect?
Ross Presser
@RossPresser aqui está: Adicione suporte para construtores de valor de linha padrão ANSI A resposta da MS foi: "Olá. Obrigado pelo seu feedback. Certamente, estamos considerando construtores de valor de linha para uma versão futura do SQL Server". Pelo menos o pedido ainda está aberto, há 10 anos.
ypercubeᵀᴹ
11

Em termos de uma limpeza pura de código, o seguinte parece mais limpo:

SELECT * 
  FROM foobar 
  WHERE (SUBJECT = 'STAT' and TERM IN ('111','222','666') )
    OR  (SUBJECT = 'COMM' and TERM IN ('333','444') )
    OR  (SUBJECT = 'ENGLISH' and TERM = '555' ) ;

Dependendo do aplicativo e com que frequência a lógica será reutilizada, também pode valer a pena configurar uma tabela de pesquisa para aplicar a lógica:

CREATE TABLE foobar_lookup (SUBJECT VARCHAR2(7), TERM VARCHAR2(3)) ;

INSERT INTO foobar_lookup SELECT 'STAT',    '111' FROM dual ;
INSERT INTO foobar_lookup SELECT 'STAT',    '222' FROM dual ;
INSERT INTO foobar_lookup SELECT 'STAT',    '666' FROM dual ;
INSERT INTO foobar_lookup SELECT 'COMM',    '444' FROM dual ;
INSERT INTO foobar_lookup SELECT 'COMM',    '333' FROM dual ;
INSERT INTO foobar_lookup SELECT 'ENGLISH', '555' FROM dual ;

SELECT f.* FROM foobar f
JOIN foobar_lookup fl 
    ON fl.subject = f.subject
    AND fl.term = f.term ;
Thomas Cleberg
fonte
4

Aqui está outra maneira de fazer isso. Usar o where (col1, col2) pode fazer com que o Oracle não use nenhum índice, mas isso parece uma tabela para a consulta, portanto, pode funcionar melhor. Você saberá quando testar as várias versões.

  WITH subject_terms 
            (subject,   term) AS
    ( SELECT 'STAT'   , '111' FROM dual UNION ALL
      SELECT 'STAT'   , '222' FROM dual UNION ALL
      SELECT 'ENGLISH', '555' FROM dual UNION ALL
      SELECT 'COMM'   , '444' FROM dual UNION ALL
      SELECT 'COMM'   , '333' FROM dual UNION ALL
      SELECT 'STAT'   , '666' FROM dual )
SELECT * 
  FROM foobar             fb
 INNER JOIN subject_terms st
    ON fb.subject = st.subject
   AND fb.term    = st.term;

DBFiddle Here

Gandolf989
fonte