重新排序某些项目并更改主键

时间:2017-11-17 00:22:45

标签: oracle plsql sequence rows

我有一个表ID STR_1 COUNT_1 STR_2 COUNT_2 1 ORANGES 10 APPLES 10 3 ORANGES 10 BANANAS 1 4 BANANAS 1 APPLES 10 ,其中包含WITH TEST_DATA AS ( SELECT 1 ID, 'ORANGES' STR_1, 2 COUNT_1, 'APPLES' STR_2, 10 COUNT_2 FROM DUAL UNION SELECT 2 ID, 'APPLES' STR_1, 10 COUNT_1, 'ORANGES' STR_2, 2 COUNT_2 FROM DUAL UNION SELECT 3 ID, 'ORANGES' STR_1, 2 COUNT_1, 'BANANAS' STR_2, 1 COUNT_2 FROM DUAL UNION SELECT 4 ID, 'BANANAS' STR_1, 1 COUNT_1, 'APPLES' STR_2, 10 COUNT_2 FROM DUAL UNION SELECT 5 ID, 'BANANAS' STR_1, 1 COUNT_1, 'ORANGES' STR_2, 2 COUNT_2 FROM DUAL ) 列,用于定义每个项目在菜单中的显示位置。为了这个问题简化了,像... ...

MENU_ITEMS

我有一个重新订购商品的程序。其中一个参数是一个字符串数组,其中包含新订单中的SEQ。就目前而言,这样的事情......

MENU_ITEMS:
ITEM_CODE    PARENT_CODE   SEQ* (*unique to parent)
------------------------------
BANANAS      FRUIT         1      
APPLES       FRUIT         2 
CHERRIES     FRUIT         4
DURIANS      FRUIT         3
POTATOES     VEG           1

问题

  1. 使用ITEM_CODEs调用该过程时,我收到了“违反唯一约束”异常(...大概是因为当存在时,第一项的procedure arrange_items( ITEM_CODES in CORE.T_STRINGARRAY, PARENT in VARCHAR2 ) as V_SEQS T_NUMBERARRAY := T_NUMBERARRAY(); begin for i in 1..ITEM_CODES.count loop V_SEQS.extend(); V_SEQS(i) := i; end loop forall i in 1..ITEM_CODES.count update MENU_ITEMS set SEQ = V_SEQS(i) where ITEM_CODE = ITEM_CODES(i) and PARENT_CODE = PARENT; end arrange_items 无法设置为1另一行ITEM_CODES = ("APPLES", "BANANAS", "CHERRIES")也是SEQ

  2. 我不知道如何处理SEQ参数中未指定的项目,其序列无关紧要(禁用菜单项且从不显示。)注意:只有项目是重新排列可以包含在1数组参数中;

  3. 需要重新安排的禁用项目 无法传递。

    阅读Oracle文档似乎建议在不违反唯一约束的情况下更改一次匹配中的所有记录需要BULK COLLECT / UPDATE(我原以为ITEM_CODES而不是ITEM_CODES可能会这样做)但是我的SQL知识极其有限,无法正确使用应用程序,我也无法看到一种方法来考虑未指定的FORALL,其序列可能需要更改,以避免与代码冲突指定。

    是否有人能够建议至少我应该调查的正确方法,如果不是一个有效的解决方案?

2 个答案:

答案 0 :(得分:1)

除非禁用约束,否则无法在不更改过程的情况下执行此操作。

尽管您可以使用比sInput = InputBox("Enter your name") MsgBox ("You entered:" & sInput) sInput1 = InputBox("Enter your name") MsgBox ("You entered:" & sInput1) Set objExcel = CreateObject("Excel.Application") Set objWorkbook = objExcel.Workbooks.Open("C:\Users\saurabh.ad.sharma\Desktop\rrr.xlsx") objExcel.Application.Visible = True objExcel.Sheets(1).unprotect "saurabh" Set rg = objExcel.Sheets(1).Range("A1") lr = rg.CurrentRegion.Rows.Count With rg .Offset(lr, 0).Value = sInput .Offset(lr, 1).Value = sInput1 End With objExcel.ActiveWorkbook.Save objExcel.Sheets(1).protect "saurabh" objExcel.ActiveWorkbook.Save objExcel.ActiveWorkbook.Close objExcel.Application.Quit WScript.Echo "Finished." WScript.Quit 更简单的更新语句,但您的代码似乎没有任何问题。问题是,当您更新列seq时,已存在同一FORALLparent_code的唯一条目。只是您在运行update语句时重新排序它。因此,无论您如何更改更新顺序,都将违反约束。

因此,我建议您使用的解决方案是禁用约束。如果您不知道约束名称,则需要查看seqUSER_CONS_COLUMNS数据字典视图,以提供正确的列名。如果需要,请参阅此链接。

Constraint name

ALL_CONS_COLUMNS

然后执行您的程序并确保在更新后没有任何重复的ALTER TABLE MENU_ITEMS DISABLE CONSTRAINT name_of_unique_constraint; 组合。

然后启用约束。

(SEQ,PARENT_CODE )

并确保它不会失败。

编辑::似乎“不能”这个词在顶部被用作其他人的挑战并且提供了替代解决方案,这很多赞赏。我略微改变了我的第一句话,说清楚。

答案 1 :(得分:1)

您无法直接使用res.contentType("application/msword"); readstream.pipe(res); 与Kaushik达成协议:禁用约束。

解决方案没有禁用约束:向每行添加FORALL,然后做你的事情:

Max(SEQ) +1