游标无限循环

时间:2017-05-31 10:45:14

标签: sql oracle plsql

这个问题只是出于好奇。我试图找出当没有为游标指定退出条件时会发生什么。获取最后一条记录后会发生什么。光标是指向第一条记录还是指向空白区域?为此,我创建了一个具有以下结构的测试表。

create table CURSOR_TEST
  (col1 number,col2 NUMBER
  );

以下是没有退出条件的匿名块

declare
  cursor CUR is select EMPNO from EMP;
  v1 number;
begin
  open CUR;

  loop
    fetch CUR into V1;
    insert into CURSOR_TEST values(s.nextval,V1);
    commit;
  end loop;

  close CUR;
end;

因为它是无限循环,我需要打破它们之间的操作。在此之后,当我检查表中的记录时,我可以看到在获取所有emp行之后,光标再次指向第一行,但是在此之后似乎没有取出。我无法理解为什么游标在表的第二次迭代期间无法获取第二行和后续行。

2 个答案:

答案 0 :(得分:3)

  

“获取最后一条记录后会发生什么。光标是指向第一条记录还是指向空白区域?”

都不是。我们需要区分游标和结果集。

光标只是关于查询的一些信息。一旦我们获取了所有记录,光标就会“耗尽”,但它不会改变。它不会重新设置自己并从头开始。没有“表的第二次迭代”。它也不会返回null。它有一个状态,我们可以测试它,例如public class MapViewFragment extends Fragment { MapView mMapView; private GoogleMap googleMap; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.location_fragment, container, false); mMapView = (MapView) rootView.findViewById(R.id.mapView); mMapView.onCreate(savedInstanceState); mMapView.onResume(); // needed to get the map to display immediately try { MapsInitializer.initialize(getActivity().getApplicationContext()); } catch (Exception e) { e.printStackTrace(); } mMapView.getMapAsync(new OnMapReadyCallback() { @Override public void onMapReady(GoogleMap mMap) { googleMap = mMap; // For showing a move to my location button googleMap.setMyLocationEnabled(true); // For dropping a marker at a point on the Map LatLng sydney = new LatLng(-34, 151); googleMap.addMarker(new MarkerOptions().position(sydney).title("Marker Title").snippet("Marker Description")); // For zooming automatically to the location of the marker CameraPosition cameraPosition = new CameraPosition.Builder().target(sydney).zoom(12).build(); googleMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition)); } }); return rootView; } @Override public void onResume() { super.onResume(); mMapView.onResume(); } @Override public void onPause() { super.onPause(); mMapView.onPause(); } @Override public void onDestroy() { super.onDestroy(); mMapView.onDestroy(); } @Override public void onLowMemory() { super.onLowMemory(); mMapView.onLowMemory(); } ,并使用CUR%NOTFOUND进行操作。

当我们不这样做时,执行提取但不返回任何内容。结果集 - 在您的情况下,变量EXIT包含提取的最后一个值。因此,您的表格应在V1中包含大量重复值。

  

“光标再次指向第一行,但在此之后似乎没有提取”

这似乎不太可能。请记住,您的光标没有ORDER BY子句,因此V1的值可以具有随机排序顺序。提取的最后一个EMPNO可能是EMP表中的最低值。

答案 1 :(得分:1)

您的代码将继续尝试获取下一条记录并提出cur%notfound条件,直到您从外部取消过程调用。

<cursor>%notfound本身并不是一个例外,因为在得知未找到下一条记录之前,Oracle不知道它何时到达结果集的末尾。这就是你需要捕获然后适当处理以便停止循环。

您可以通过运行以下命令来查看:

DECLARE
  CURSOR cur IS SELECT dummy FROM dual;

  v_dummy VARCHAR2(1);
  v_nf_count INTEGER := 0;
  v_f_count INTEGER := 0;
BEGIN
  OPEN cur;
  LOOP
    FETCH cur INTO v_dummy;
    IF cur%NOTFOUND THEN
     v_nf_count := v_nf_count + 1;
     dbms_output.put_line('current %notfound count = '||v_nf_count||'; v_dummy = '||v_dummy);
    ELSIF cur%FOUND THEN
     v_f_count := v_f_count + 1;
     dbms_output.put_line('current %found count = '||v_f_count||'; v_dummy = '||v_dummy);
    END IF;

    EXIT WHEN v_f_count = 10 OR v_nf_count = 10;
  END LOOP;
END;
/

current %found count = 1; v_dummy = X
current %notfound count = 1; v_dummy = X
current %notfound count = 2; v_dummy = X
current %notfound count = 3; v_dummy = X
current %notfound count = 4; v_dummy = X
current %notfound count = 5; v_dummy = X
current %notfound count = 6; v_dummy = X
current %notfound count = 7; v_dummy = X
current %notfound count = 8; v_dummy = X
current %notfound count = 9; v_dummy = X
current %notfound count = 10; v_dummy = X