使用非等值连接操作的Oracle代码出错

时间:2014-11-18 23:19:03

标签: sql oracle join

我是堆栈溢出的新手,所以当我发布这个时,如果我做错了,我会道歉。 我在使用这段代码时遇到了一些问题。我相信我的加入存在问题。

UPDATE   rental_item ri
SET      rental_item_price =
      (SELECT   p.amount
       FROM     price p INNER JOIN common_lookup cl1
       ON       p.price_type = cl1.common_lookup_id CROSS JOIN rental r
                CROSS JOIN common_lookup cl2 
       WHERE    p.item_id = ri.item_id AND ri.rental_id = r.rental_id
       AND      ri.rental_item_type = cl2.common_lookup_id
       AND      cl1.common_lookup_code = cl2.common_lookup_code
       AND      r.check_out_date
                  BETWEEN p.start_date AND p.end_date);

此代码块应使用上面指定的条件使用“AMOUNT”列中的数据填充“RENTAL_ITEM_PRICE”列。我无法删除WHERE和AND语句中的任何条件。

RENTAL_ITEM_ID RENTAL_ITEM_PRICE AMOUNT
-------------- ----------------- ------
  1001                             5
  1002                             5
  1003                             5
  1004                             5
  1005                             5
  1006                             5
  1007                             5
  1008                             5
  1009                             5
  1010                             3
  1011                             3
  1012                            10
  1013                            15

当我运行代码时,它表示已更新了13行,但您可以看到没有写入任何信息。它也不会返回任何错误。

它应该是这样的:

RENTAL_ITEM_ID RENTAL_ITEM_PRICE     AMOUNT
-------------- ----------------- ----------
      1001                 5          5
      1002                 5          5
      1003                 5          5
      1004                 5          5
      1005                 5          5
      1006                 5          5
      1007                 5          5
      1008                 5          5
      1009                 5          5
      1010                 3          3
      1011                 3          3
      1012                10         10
      1013                15         15

2 个答案:

答案 0 :(得分:1)

您的子查询没有返回任何行,因此更新将所有rental_item_price值设置为null。单独运行子查询 - 替换rental_item表中的实际值代替ri.*列,因为当您运行select部分时,该别名将不存在 - 可能会显示没有找到数据。

如果确实如此,则必须确定哪些连接或条件不正确,这是基本调试,但您可以先删除过滤条件,直到出现某些数据或检查连接条件。

我最初的猜测 - 现在已经确认 - 是price.end_date可能为空,如果你有活跃的产品并且你没有设置一个人工魔术结束日期(例如9999-12-31),这是有意义的,有一天会成为Y10K问题的一部分)。然后,between子句无法匹配,因为实际日期和空值之间没有任何内容。

您可以将结束日期设置为表格中的魔术值,许多人认为这是一个讨厌的黑客,或将其视为一个神奇的未来日期作为查询的一部分,这不是更好,或使用比较日期为默认值:

r.check_out_date BETWEEN p.start_date
  AND COALESCE(p.end_date, r.check_out_date)

我不确定你为什么使用交叉连接然后应用过滤条件,至少对于common_lookup的自连接是这样;与这个问题没有多大关系,但从我的想法来看,我可能将子查询结构为:

SELECT p.amount
FROM rental r
CROSS JOIN common_lookup cl1
INNER JOIN common_lookup cl2
ON cl2.common_lookup_code = cl1.common_lookup_code
INNER JOIN price p 
ON p.price_type = cl2.common_lookup_id
AND r.check_out_date BETWEEN p.start_date
  AND COALESCE(p.end_date, r.check_out_date)
WHERE r.rental_id = ri.rental_id
AND cl1.common_lookup_id = ri.rental_item_type
AND p.item_id = ri.item_id

答案 1 :(得分:1)

此SQL的问题在p.end_date。 end_date可以为null。这就是为什么我们需要在发生这种情况时使用NVL添加值。 您的问题的解决方案是:

enter code here

UPDATE   rental_item ri
SET      rental_item_price =
(SELECT p.amount 
FROM price p 
INNER JOIN common_lookup cl1 
ON p.price_type = cl1.common_lookup_id CROSS JOIN rental r
CROSS JOIN common_lookup cl2 
WHERE p.item_id = ri.item_id AND ri.rental_id = r.rental_id 
AND ri.rental_item_type = cl2.common_lookup_id 
AND cl1.common_lookup_code = cl2.common_lookup_code 
AND r.check_out_date 
BETWEEN p.start_date AND NVL (p.end_date, TRUNC(SYSDATE + 1)));