我无法正确地绕着正确的方式使用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');
但我不知道从哪里开始......
答案 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();
}
}