存储过程中的高级选择

时间:2010-04-27 13:50:57

标签: sql oracle stored-procedures plsql

我得到了这张表:

CREATE TABLE Test_Table (
    old_val VARCHAR2(3),
    new_val VARCHAR2(3),
    Updflag NUMBER,
    WorkNo NUMBER  );

这是在我的表中:

INSERT INTO Test_Table  (old_val, new_val, Updflag , WorkNo) VALUES('1',' 20',0,0);
INSERT INTO Test_Table  (old_val, new_val, Updflag , WorkNo) VALUES('2',' 20',0,0);
INSERT INTO Test_Table  (old_val, new_val, Updflag , WorkNo) VALUES('2',' 30',0,0);
INSERT INTO Test_Table  (old_val, new_val, Updflag , WorkNo) VALUES('3',' 30',0,0);    
INSERT INTO Test_Table  (old_val, new_val, Updflag , WorkNo) VALUES('4',' 40',0,0);
INSERT INTO Test_Table  (old_val, new_val, Updflag , WorkNo) VALUES('4',' 40',0,0);

现在我的表看起来像这样:

Row  Old_val  New_val       Updflag  WorkNo
1    '1'        ' 20'       0        0
2    '2'        ' 20'       0        0
3    '2'        ' 30'       0        0
4    '3'        ' 30'       0        0
5    '4'        ' 40'       0        0
6    '5'        ' 40'       0        0

(如果new_val列中的值相同,则它们在一起,同样转到old_val) 所以在上面的例子中,第1-4行在一起,第5-6行是

目前我的存储过程中有一个光标:

 SELECT t1.Old_val, t1.New_val, t1.updflag, t1.WorkNo
    FROM Test_Table t1
    WHERE t1.New_val =
      (
        SELECT t2.New_val
        FROM Test_Table t2
        WHERE t2.Updflag = 0
          AND t2.Worknr = 0
          AND ROWNUM = 1
      )

输出是这样的:

Row  Old_val  New_val   Updflag  WorkNo
1    1         20       0        0
2    2         20       0        0

我的问题是,我不知道如何通过一个选择获得第1行到第4行。 (我有4个子查询的想法,但如果它的更多数据匹配在一起,这将不起作用)

你有没有人有想法?

2 个答案:

答案 0 :(得分:1)

您可以使用分析来定义连续行组:

SQL> SELECT old_val, new_val, updflag, workno,
  2         SUM(gap) over(ORDER BY old_val, new_val) grp
  3    FROM (SELECT t.*,
  4                  CASE
  5                     WHEN new_val = lag(new_val)
  6                                    over(ORDER BY old_val, new_val)
  7                       OR old_val = lag(old_val)
  8                                    over(ORDER BY old_val, new_val)
  9                     THEN
 10                      0
 11                     ELSE
 12                      1
 13                  END gap
 14             FROM Test_Table t);

OLD_VAL NEW_VAL    UPDFLAG     WORKNO        GRP
------- ------- ---------- ---------- ----------
1        20              0          0          1
2        20              0          0          1
2        30              0          0          1
3        30              0          0          1
4        40              0          0          2
4        40              0          0          2

内部SELECT构建一个“GAP”列,当前一行与前一行不在同一组时,该列等于1.

外部SELECT使用间隙列上的运行总计来获取组编号。

编辑2

由于分析函数,您无法将FOR UPDATE子句直接添加到查询中。您可以直接查询基表:

SQL> WITH t_new AS (
  2  SELECT t_rowid, old_val, new_val, updflag, workno,
  3         SUM(gap) over(ORDER BY old_val, new_val) grp
  4    FROM (SELECT t.*, t.rowid t_rowid,
  5                  CASE
  6                     WHEN new_val = lag(new_val)
  7                                    over(ORDER BY old_val, new_val)
  8                       OR old_val = lag(old_val)
  9                                    over(ORDER BY old_val, new_val)
 10                     THEN
 11                      0
 12                     ELSE
 13                      1
 14                  END gap
 15             FROM test_table t)
 16  )
 17  SELECT *
 18    FROM test_table
 19   WHERE ROWID IN (SELECT t_rowid
 20                     FROM t_new
 21                    WHERE grp = (SELECT grp
 22                                   FROM t_new t2
 23                                  WHERE t2.new_val = ' 20'
 24                                    AND t2.old_val = '1'))
 25     FOR UPDATE;

OLD_VAL NEW_VAL    UPDFLAG     WORKNO
------- ------- ---------- ----------
1        20              0          0
2        20              0          0
2        30              0          0
3        30              0          0

答案 1 :(得分:0)

如果您想要的是返回的所有“与某些内容一起”的行,那么您的原始示例数据似乎不会提供不应返回的行。所以,让我们添加以下内容:

INSERT INTO Test_Table  (old_val, new_val, Updflag , WorkNo) VALUES('6',' 50',0,0);

此行不应与任何内容一起使用,不应返回。鉴于此,我认为我们可以使用EXISTS来获得您想要的东西:

Select *
From Test_Table T1
Where Exists    (
                Select 1
                From Test_Table T2
                Where ( T2.old_val = T1.old_val Or T2.new_val = T1.new_val )
                    And ( T2.row <> T1.row )
                )