PostgreSQL WHERE EXISTS

时间:2015-09-03 17:56:16

标签: python sql postgresql

我无法正确地绕着正确的方式使用EXISTS(以及是否有正确的方法来使用EXISTS来解决这个特殊情况,或者我是否误解了它。)

我正在反对Rigor架构(在这里为SQLAlchemy定义:https://github.com/blindsightcorp/rigor/blob/master/lib/types.py)。

缺点是我有三个我关心的表:" percept","注释"和" annotation_property"。 annotation_properties有一个annotation_id,注释有一个percept_id。

我想找到所有带有特定annotation_property(FOO = BAR)注释的感知。

Percepts可能有许多具有特定属性的注释,因此看起来EXISTS应该能让事情变得更快。

(相对较慢)选项是:

 SELECT DISTINCT(percept.*) FROM percept, annotation, annotation_property 
        WHERE percept.id = annotation.percept_id AND 
              annotation_property.annotation_id = annotation.id AND 
              annotation_property.name = 'FOO' AND annotation_property.value = 'BAR';

我如何使用EXISTS来优化它?

感觉就像第一步是:

 SELECT percept.* FROM percept WHERE id IN (SELECT percept_id FROM 
        annotation, annotation_property WHERE 
        annotation.id = annotation_property.annotation_id AND
        annotation_property.name = 'FOO' AND annotation_property.value = 'BAR');

但我不知道从哪里开始......

2 个答案:

答案 0 :(得分:2)

原始查询的问题(除了隐式连接语法之外)是您从连接中汇集了大量行。然后,您将聚合以删除重复项。

只需从一个表中选择即可消除重复删除:

SELECT p.*
FROM percept p
WHERE EXISTS (SELECT 1
              FROM annotation a JOIN
                   annotation_property ap
                   ON ap.annotation_id = a.id AND 
                      ap.name = 'FOO' AND ap.value =  'BAR'
              WHERE p.id = a.percept_id 
             ) ;

这假设percept中的行没有重复,但这似乎是一个合理的假设。

答案 1 :(得分:2)

首先,使用ANSI JOIN语法将您的连接条件与过滤条件区分开来。结果更易于阅读,并且更好地显示数据结构:

SELECT DISTINCT(percept.*)
FROM
  percept
  JOIN annotation ON percept.id = annotation.percept_id
  JOIN annotation_property ON annotation_property.annotation_id = annotation.id
WHERE
    annotation_property.name = 'FOO'
    AND annotation_property.value = 'BAR'
;

如你所说,这可能是一项改进,并且在主键列上使用distinct而不是一次在整个percept行,但这仍然可能涉及计算大结果集然后合并它。它是exists()条件的替代,而不是对EXISTS条件的补充。

WHERE子句中使用SELECT * FROM percept p WHERE EXISTS ( SELECT * FROM annotation ann JOIN annotation_property anp ON anp.annotation_id = ann.id WHERE anp.name = 'FOO' AND anp.value = 'BAR' AND ann.percept_id = p.id ) ; 条件可能如下所示:

public class MainActivity extends Activity implements View.OnClickListener {
    TextView text;
    Button button;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        button = (Button)findViewById(R.id.startbutton);
        text = (TextView)findViewById(R.id.text);
        button.setOnClickListener(this);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onClick(View v) {
        new CountDownTimer(60000, 1000) {
            @Override
            public void onTick(long millisUntilFinished) {
                text.setText(" "+ String.format("%d min, %d sec", TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished),
                        TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished)-TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished))));

            }

            @Override
            public void onFinish() {
                text.setText("done !!!");
            }
        }.start();
    }
}