WHERE(一组条件)OR(一组第二个条件)OR ...优雅地写

Posted

技术标签:

【中文标题】WHERE(一组条件)OR(一组第二个条件)OR ...优雅地写【英文标题】:WHERE (set of conditions) OR (set of second conditions) OR ... written elegantly 【发布时间】:2017-05-16 12:14:01 【问题描述】:

我有以下问题:

我有一个包含材料属性的 Oracle 数据库,我正在为它开发一个 Excel-VBA 前端。

有一个视图 ALL_TESTS 表示我要从中加载数据表中所有属性的整个表。准确地说,我得到了一个属性列表,每个属性都在特定条件下进行了特定测试,并带有样本的状态。对于公司的一种材料,我总是希望加载整个包。

如果我会这样做:

SELECT * FROM ALL_TESTS WHERE COMPANY in (Company1, Company2, ...)
                        AND MATERIAL (Material1,Material2, ... )
                        AND Test in (Test1,Test2, ...)
                        AND Property in (Property1, Property2, ...)
                        AND Condition in (Condition1, Condition2, ...)
                        AND State in (State1,State2, ...)

我不仅会得到我想要的测试,还会得到索引不匹配的记录。例如,当记录匹配 company1、material2、test3、property4 和 State2 时。但这不是我想要的,我想要的是:

SELECT * FROM ALL_TESTS WHERE (COMPANY = Company1
                        AND MATERIAL = Material1
                        AND Test = Test1
                        AND Property = Property1
                        AND Condition = Condition1
                        AND State = State1)

                        OR (COMPANY = Company2
                        AND MATERIAL = Material2
                        AND Test = Test2
                        AND Property = Property2
                        AND Condition = Condition2
                        AND State = State2)
                        OR ...

我有一种方法可以用更优雅的方式编写它,然后只构建一个超长的 SQL 查询?

感谢您的宝贵时间!

【问题讨论】:

【参考方案1】:

你应该可以做到:

SELECT *
FROM ALL_TESTS
WHERE (COMPANY, MATERIAL, Test, Property, Condition, State) IN
          ( (Company1, Material1, Test1, Property1, Condition1, State1),
            (Company2, Material2, Test2, Property2, Condition2, State2)
          )

【讨论】:

我选择了您的解决方案并实施了它。会不会,如果某些条件为 NULL,这将不起作用? 确实不适用于某些属性为 null - 再说一次,最初问题中描述的 where 子句也是如此。 @LucasRaphaelPianegonda 。 . .里克完全正确。这与您问题中的 equals 行为相同。 我纠正自己:我 90% 确定没有 NULL 值,只有空值。您可以想象,例如,拉伸测试具有拉伸速度、温度和材料的测试方向等参数。但是简单的密度测量没有这样的参数。这意味着测试条件有时有值,有时没有值(空)。但它们不是 NULL(未知)。【参考方案2】:

如果您在另一个表中有匹配公司的数据,那么您可以进行简单的连接并获得您的结果:

SELECT at.*
FROM ALL_TESTS
INNER JOIN MATCHING_COMPANIES mc
    ON at.COMPANY   = mc.COMPANY AND
       at.MATERIAL  = mc.MATERIAL AND
       at.Test      = mc.Test AND
       at.Property  = mc.Property AND
       at.Condition = mc.Condition AND
       at.State     = mc.State

当然,这需要一个单独的表,但希望在 Oracle 或 VBA 中创建一个临时表不是那么麻烦,而是无法完成。

【讨论】:

【参考方案3】:

将您的位置放入(临时)表(列:MATERIAL、Test、Property、Condition、State)中,将可能的值插入其中(每个 OR 是一行),然后将该表内部连接到原始表(ALL_TESTS ),临时表中的所有列如下:

Select *
from ALL_TESTS
inner join temp1 on ALL_TESTS.MATERIAL = temp1.MATERIAL 
AND ALL_TESTS.Test = temp1.Test
AND ALL_TESTS.Property = temp1.Property
.... all other columns 

所以你可以在 temp1 中有很多行,所有不同的 OR,以及一个简单的选择来询问它

【讨论】:

似乎是一个很好的解决方案,但是我不想从这张表中写入数据库。它应该只是一个展示工具,我的想法是让它成为用户的只读工具。通过这种方式,我可以确定用户或错误无法操作数据库上的数据。我会尝试第一个答案,尽管我认为你的答案会更好。【参考方案4】:

除了 Gordon 的解决方案,我还建议使用带有自定义比较逻辑的 oracle 对象类型来处理 NULL 比较问题:

CREATE OR REPLACE TYPE test_obj as object(
  company varchar2(100),
  material varchar2(100),
  property varchar2(100),
  condition varchar2(100),
  map member function get_unique_key return varchar2  
)
/

CREATE OR REPLACE TYPE BODY test_obj as 
  map member function get_unique_key return varchar2
  as
  begin
    return nvl(company,'?')||'|'||nvl(material,'?')||'|'||nvl(property,'?')||'|'||nvl(condition,'?');
  end;  
end;
/

DROP TABLE all_tests;

CREATE TABLE all_tests
(
  test          VARCHAR2(100),
  test_obj      TEST_OBJ
)
;

insert into all_tests
select 'TEST1', test_obj('XXX', null, 'test', null)
  from dual 
;

select * from all_tests
where test_obj = test_obj('XXX', null, 'test', null);
TEST     TEST_OBJ
------   --------------
TEST1    (XXX, , test, )

【讨论】:

以上是关于WHERE(一组条件)OR(一组第二个条件)OR ...优雅地写的主要内容,如果未能解决你的问题,请参考以下文章

Python 操作Redis

python爬虫入门----- 阿里巴巴供应商爬虫

Python词典设置默认值小技巧

《python学习手册(第4版)》pdf

Django settings.py 的media路径设置

Python中的赋值,浅拷贝和深拷贝的区别