【问题标题】:How to create a not null column in a view如何在视图中创建非空列
【发布时间】:2013-08-15 15:23:36
【问题描述】:

给定一个像这样的表:

CREATE TABLE "MyTable" 
(
  "MyColumn" NUMBER NOT NULL
);

我想创建一个类似的视图:

CREATE VIEW "MyView" AS
SELECT
    CAST("MyColumn" AS BINARY_DOUBLE) AS "MyColumn"
FROM "MyTable";

仅当列“MyColumn”为“NOT NULL”时。

在 SQL Server 中,这非常简单:

CREATE VIEW [MyView] AS
SELECT
    ISNULL(CAST([MyColumn] AS Float), 0.0) AS [MyColumn]
FROM [MyTable];

但是,Oracle 等效项会导致“NULL”列:

CREATE VIEW "MyView" AS
SELECT
    NVL(CAST("MyColumn" AS BINARY_DOUBLE), 0.0) AS "MyColumn"
FROM "MyTable";

是否有强制 Oracle 在元数据中将视图的列标记为“NOT NULL”?

【问题讨论】:

  • 在 DBA.SE 中交叉发布:dba.stackexchange.com/questions/19484/…
  • 在这种情况下,如果基础表列具有非空约束,则视图中的列不能为空。你想让desc "MyView"(希望你不是真的使用大小写混合的对象名称!)也将其显示为非空吗?
  • 是的,我想将元数据显示为非空。 (不,这些不是真正的命名约定。)
  • 这必须在 Oracle 10g 和 11g 上工作(有两个版本的数据库)。

标签: oracle casting oracle10g sql-view


【解决方案1】:

您不能向视图添加非空或检查约束;请参阅this 和同一页面上的“非空约束的限制”和“检查约束的限制”。您可以在视图中添加 with check option(针对冗余 where 子句),但不会在数据字典中将其标记为 not null

我认为获得这种效果的唯一方法是,如果您使用的是 11g,则将强制转换值作为虚拟列添加到表上,并(如果仍然需要)创建视图:

ALTER TABLE "MyTable" ADD "MyBDColumn" AS
    (CAST("MyColumn" AS BINARY_DOUBLE)) NOT NULL;

CREATE OR REPLACE VIEW "MyView" AS
SELECT
    "MyBDColumn" AS "MyColumn"
FROM "MyTable";

desc "MyView"

 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 MyColumn                                  NOT NULL BINARY_DOUBLE

由于您在 dba.se 的评论中说这是为了模拟某些东西,您可以使用普通列和触发器来模拟虚拟列:

CREATE TABLE "MyTable" 
(
  "MyColumn" NUMBER NOT NULL,
  "MyBDColumn" BINARY_DOUBLE NOT NULL
);

CREATE TRIGGER "MyTrigger" before update or insert on "MyTable"
FOR EACH ROW
BEGIN
    :new."MyBDColumn" := :new."MyColumn";
END;
/

CREATE VIEW "MyView" AS
SELECT
    "MyBDColumn" AS "MyColumn"
FROM "MyTable";

INSERT INTO "MyTable" ("MyColumn") values (2);

SELECT * FROM "MyView";

  MyColumn
----------
  2.0E+000

desc "MyView" 仍然给出:

 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 MyColumn                                  NOT NULL BINARY_DOUBLE

正如 Leigh 提到的(也在 dba.se 上),如果您确实想要插入/更新视图,您可以使用 instead of 触发器,以及 VC 或假版本。

【讨论】:

  • 因此,您向表中添加了一个计算列,其中包含强制转换和非空约束,这样视图就不需要强制转换。 - 我会尽快试试这个。新列是否可写? (它可以更新原始列吗?)
  • 不行,不能插入到表上的VC中(因为已经生成了);你不能插入到视图中,因为它违反了 VC。你会在insert 上获得 ORA-54013,或在update 上获得 ORA-54017。 (但我得到与你原来的观点相同的错误,cast,如果 VC 存在;如果不存在 ORA-01733)。
  • 现在已经足够好了 :-)(至少在 Oracle 支持在其 EF 提供程序中将“数字”映射到“双”之前,直到我们从 Oracle 迁移出来。)
  • 我在运行“alter table”命令时收到“ERROR ORA-00902: invalid datatype”。显然我使用的是 10g (10.2.0.5.0)。
  • 啊,直到 11g 才引入虚拟列,所以这对你不起作用。我添加了一个使用伪虚拟列的版本,我认为它可以在 10g 或 11g 中工作,但我没有方便测试的 10g 数据库。
【解决方案2】:

如果您可以在视图列上有 NOT NULL 约束,我相信如果相关列为 NULL,则视图中的 SELECT 将失败。如果这是意图,那么以下内容可能会为您提供所需的内容:

CREATE OR REPLACE VIEW some_view AS
  SELECT some_field,
         some_other_field,
         CASE
           WHEN field_of_interest IS NOT NULL
             THEN CAST(field_of_interest AS BINARY_DOUBLE)
             ELSE 1 / 0
         END AS field_of_interest_not_null
     FROM some_table;

不是很吸引人,如果采用 CASE 的 ELSE 分支,你会得到一个丑陋的“ORA-01476:除法等于零”消息,但也许这是在“更好”的道路上迈出的一步。

分享和享受。


编辑:如果目标是只选取目标列不为空的行,也许您可​​以在视图中添加 WHERE 子句,如下所示:

CREATE OR REPLACE VIEW some_view AS
  SELECT some_field,
         some_other_field,
         CAST(field_of_interest AS BINARY_DOUBLE) AS field_of_interest
    FROM some_table
    WHERE field_of_interest IS NOT NULL;

YMMV.


编辑2: 查看 SQL Server 示例,似乎使用 ISNULL 函数来确保该列永远不会为 NULL。如果这是可以接受的,您可以执行以下操作:

CREATE OR REPLACE VIEW some_view AS
  SELECT some_field,
         some_other_field,
         CAST(NVL(field_of_interest, 0.0) AS BINARY_DOUBLE) AS field_of_interest
    FROM some_table
    WHERE field_of_interest IS NOT NULL;

引用 Bullwinkle 的话,“这次一定要确定!!!” :-)

【讨论】:

  • 值不能为空,所以选择不会失败,我只是想让元数据反映这一点。
  • 我理解你的感受。我猜底层表列是 NOT NULL 约束的最佳选择。
  • @DannyVarod:添加了第三个选项以使用 NVL 和 CAST,这大致相当于原始帖子中 SQL Server 示例中使用的 ISNULL。
  • MSSQL ISNULL() 函数向 MSSQL 指示如果转换失败,则该值不为空。 MSSQL 在元数据中反映了这一点。 Oracle NVL() 函数旨在执行相同的操作,但是元数据并未反映它。我不确定 Oracle 是否有一个好的选择。
  • 啊,现在我明白你的意思了。我同意不能说服 Oracle 在 DBA_TAB_COLUMNS 中将该列标记为非 NULLABLE。此外,我发现由于 BINARY_DOUBLE 的存在,我什至无法从上述视图定义中选择 - 我得到“ORA-03115 - 不支持的网络数据类型或表示”。我每天都学到新东西。 :-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-17
  • 1970-01-01
相关资源
最近更新 更多