【问题标题】:Creating a view in a not relational database在非关系数据库中创建视图
【发布时间】:2013-03-15 07:16:49
【问题描述】:

我遇到了一个问题,希望有人可以帮助我。事实上,我在一个设计不佳的数据库上工作,我无法控制更改其中的内容。我有一个“书籍”表,每本书可以有一个或多个作者。不幸的是,数据库不是完全相关的(请不要问我为什么,因为我从一开始就问同样的问题)。在“书籍”表中,有一个名为“Author_ID”和“Author_Name”的字段,因此当一本书由 2 或 3 个作者撰写时,他们的 ID 和他们的姓名将连接在由星号分隔的同一记录中。这是一个演示:

ID_BOOK | ID_AUTHOR |       NAME AUTHOR       |  Adress        |  Country        |
----------------------------------------------------------------------------------
001     |01         | AuthorU                 | AdrU           | CtryU           |
----------------------------------------------------------------------------------
002     |02*03*04   | AuthorX*AuthorY*AuthorZ | AdrX*NULL*AdrZ | NULL*NULL*CtryZ |
----------------------------------------------------------------------------------

我需要针对这个表创建一个视图,它会给我这个结果:

ID_BOOK | ID_AUTHOR |       NAME AUTHOR       | Adress         | Country         |
----------------------------------------------------------------------------------
001     |01         | AuthorU                 | AdrU           | CtryU           |
----------------------------------------------------------------------------------
002     |02         | AuthorX                 | AdrX           | NULL            |
----------------------------------------------------------------------------------
002     |03         | AuthorY                 | NULL           | NULL            |
----------------------------------------------------------------------------------
002     |04         | AuthorZ                 | AdrZ           | CtryZ           |
----------------------------------------------------------------------------------

我将继续尝试这样做,我希望有人可以帮助我至少提供一些提示。非常感谢各位。

在我应用你们提供的解决方案后,我遇到了这个问题。我正在努力解决它,希望你能帮助我。事实上,当 sql 查询运行时,当其中一些包含 NULL 值时,CLOB 字段是杂乱无章的。结果应该和上面一样,但我得到的结果如下:

ID_BOOK | ID_AUTHOR |       NAME AUTHOR       | Adress         | Country         |
----------------------------------------------------------------------------------
001     |01         | AuthorU                 | AdrU           | CtryU           |
----------------------------------------------------------------------------------
002     |02         | AuthorX                 | AdrX           | CtryZ           |
----------------------------------------------------------------------------------
002     |03         | AuthorY                 | AdrZ           | NULL            |
----------------------------------------------------------------------------------
002     |04         | AuthorZ                 | NULL           | NULL            |
----------------------------------------------------------------------------------

为什么将NULL值放在最后?谢谢。

【问题讨论】:

  • 好问题坏标题
  • 嘿 Praveen,这是我的第一个问题。我尝试了很多标题,但每次都说标题不好,所以我开始寻找可以批准的标题。你的说法是正确的。如果您有任何提示,请告诉我

标签: asp.net sql oracle view


【解决方案1】:

另外:

SELECT distinct id_book,
     , trim(regexp_substr(id_author, '[^*]+', 1, LEVEL)) id_author
     , trim(regexp_substr(author_name, '[^*]+', 1, LEVEL)) author_name
 FROM yourtable
CONNECT BY LEVEL <= regexp_count(id_author, '[^*]+')
ORDER BY id_book, id_author
/

ID_BOOK    ID_AUTHOR    AUTHOR_NAME
------------------------------------
001        01           AuthorU
002        02           AuthorX
002        03           AuthorY
002        04           AuthorZ
003        123          Jane Austen
003        456          David Foster Wallace
003        789          Richard Wright

没有正则表达式:

SELECT str, SUBSTR(str, substr_start_pos, substr_end_pos) final_str
  FROM
 (
  SELECT str, substr_start_pos
       , (CASE WHEN substr_end_pos <= 0 THEN (Instr(str, '*', 1)-1) 
            ELSE substr_end_pos END) substr_end_pos
    FROM
   (
   SELECT distinct '02*03*04' AS str
       , (Instr('02*03*04', '*', LEVEL)+1) substr_start_pos
       , (Instr('02*03*04', '*', LEVEL)-1) substr_end_pos           
    FROM dual
   CONNECT BY LEVEL <= length('02*03*04')
   )
  ORDER BY substr_start_pos
  )
 /

STR         FINAL_STR
---------------------
02*03*04    02
02*03*04    03
02*03*04    04

【讨论】:

  • 嘿艺术,我使用 Oracle 9,所以这段代码对我不起作用,因为 Oracle 9 不理解正则表达式,我正在尝试调整它但仍然没有得到正确的结果。你能给我一些提示吗?非常感谢。
  • @Walloud-对不起,我看到其他人使用正则表达式并假设你也可以。请查看更新。
  • 小修正:当 substr_end_pos
【解决方案2】:

几周前我回答了一个类似的问题here。该答案对一般方法有一个解释(我希望),所以我将在这里跳过解释。这个查询可以解决问题;它使用REGEXP_REPLACE 并利用其“occurrence”参数来选择个人作者 ID 和姓名:

SELECT
 ID_Book,
 REGEXP_SUBSTR(ID_Author, '[^*]+', 1, Counter) AS AuthID,
 REGEXP_SUBSTR(Name_Author, '[^*]+', 1, Counter) AS AuthName
FROM Books
CROSS JOIN (
  SELECT LEVEL Counter
    FROM DUAL
    CONNECT BY LEVEL <= (      
      SELECT MAX(REGEXP_COUNT(ID_Author, '[^*]+'))
      FROM Books))
WHERE REGEXP_SUBSTR(Name_Author, '[^*]+', 1, Counter) IS NOT NULL
ORDER BY 1, 2

您的数据有一个 Fiddle 以及另一行 here


附录:OP 有 Oracle 9,而不是 11,因此正则表达式不起作用。以下是在不使用正则表达式的情况下执行相同任务的说明...

没有REGEXP_COUNT,计数作者的最佳方法是计数星号并加一。要计算星号,请取字符串的长度,然后在所有星号都被吸出后减去它的长度:LENGTH(ID_Author) - LENGTH(REPLACE(ID_Author, '*'))

如果没有REGEX_SUBSTR,则需要使用INSTR找到星号的位置,然后SUBSTR拉出作者ID和姓名。这有点复杂 - 请考虑您原始帖子中的这些作者专栏:

Author U
Author X*Author Y*Author Z
  • AuthorX 位于字符串开头和第一个星号之间。
  • AuthorY 被星号包围
  • AuthorZ 位于最后一个星号和字符串末尾之间。
  • AuthorU 独自一人,没有被任何东西包围。

因此,开头部分(下面的WITH AuthorInfo AS...)在开头和结尾添加了一个星号,因此每个作者姓名(和 ID)都被星号包围。它还获取每一行的作者计数。对于您原始帖子中的示例数据,开头部分将产生以下内容:

ID_Book  AuthCount  ID_Author   Name_Author
-------  ---------  ----------  -------------------------
001              1  *01*        *AuthorU*
002              3  *02*03*04*  *AuthorX*AuthorY*AuthorZ*

然后是与“计数器”表和SUBSTR 的连接,以提取个人名称和 ID。最终查询如下所示:

WITH AuthorInfo AS (
  SELECT
    ID_Book,
    LENGTH(ID_Author) -
        LENGTH(REPLACE(ID_Author, '*')) + 1 AS AuthCount,
    '*' || ID_Author || '*' AS ID_Author,
    '*' || Name_Author || '*' AS Name_Author
  FROM Books
)
SELECT
  ID_Book,
  SUBSTR(ID_Author,
    INSTR(ID_Author, '*', 1, Counter) + 1,
    INSTR(ID_Author, '*', 1, Counter+1) - INSTR(ID_Author, '*', 1, Counter) - 1) AS AuthID,
  SUBSTR(Name_Author,
    INSTR(Name_Author, '*', 1, Counter) + 1,
    INSTR(Name_Author, '*', 1, Counter+1) - INSTR(Name_Author, '*', 1, Counter) - 1) AS AuthName
FROM AuthorInfo
CROSS JOIN (
  SELECT LEVEL Counter
    FROM DUAL
    CONNECT BY LEVEL <= (SELECT MAX(AuthCount) FROM AuthorInfo))
WHERE AuthCount >= Counter
ORDER BY ID_Book, Counter

小提琴是here

【讨论】:

  • 谢谢大家的回复,我试试看。只是我想补充一点,Author_ID 和 Author_Name 是 CLOB 数据,而分隔符并不完全是一个开始,而是一个 wordrap,所以我会尝试调整您的请求并将此 CLOB 数据转换为 Varchar 以便能够使用他们。
  • @Walloud - Oracle 有处理多行正则表达式的方法,但恐怕我不太了解它们,所以从这里开始我无法提供太多帮助。如果您遇到与多行正则表达式有关的问题,我建议您发布一个新问题并将其标记为除 Oracle 之外的“正则表达式” - 这样您的问题就会被许多 RegEx 专家看到。祝你好运,好问题!
  • 嘿 Grace,我使用 Oracle 9,所以这段代码对我不起作用,因为 Oracle 9 不理解正则表达式,我正在尝试调整它,但仍然没有得到正确的结果。你能给我一些提示吗?非常感谢。
  • @Walloud - 我在上面的答案中添加了 9i 查询(带有一些解释)。至少我认为它符合 9i - 如果您遇到任何问题,请告诉我。
  • 嘿,埃德!我真的无法形容我多么想感谢你。你真是个好人!昨天我解决了我的问题,但我忘了给你写信。我会接受你的解决方案并理解它,这样我就可以提高我的技能,也许一旦我会帮助像你这样的人。再次感谢你 !!干杯:)))
【解决方案3】:

在 11g 中,您可以为此使用分解递归子查询:

with data (id_book, id_author, name, item_author, item_name, i)
 as (select id_book, id_author, name,
            regexp_substr(id_author, '[^\*]+', 1, 1) item_author, 
            regexp_substr(name, '[^\*]+', 1, 1) item_name,
            2 i 
       from books
     union all
     select id_book, id_author, name,
            regexp_substr(id_author, '[^\*]+', 1, i) item_author, 
            regexp_substr(name, '[^\*]+', 1, i) item_name, 
            i+1
       from data
      where regexp_substr(id_author, '[^\*]+', 1, i) is not null)
select id_book, item_author, item_name
  from data;

fiddle

【讨论】:

  • 谢谢达扎。请再问一个问题,列 Author_ID 和 Author_Name 是 CLOB 数据,分隔符是 wordrap(不是星号),您认为最好的解决方案是将 CLOB 转换为 VARCHAR 然后应用您的请求吗?否则 regexp_substr 将不起作用。
  • @walloud 那么列中的数据是否超过 4k?
  • 我真的不知道怎么知道 Dazzal,我不熟悉 CLOB :S
  • @walloud 你可以用 select max(length(id_author)) from books 检查;如果不超过 4k,则在字段周围应用 to_char 将解决 clob 问题,例如 regexp_substr(to_char(id_author)...
  • 嘿 Dazzal,再次感谢,我做到了,它给出了 57 个字符,想知道多少 k,请问我需要做什么?
【解决方案4】:

如果你有一个authors 表,你可以这样做:

select b.id_book, a.id_author, a.NameAuthor
from books b left outer join
     authors a
     on '*'||NameAuthor||'*' like '%*||a.author||'*%'

【讨论】:

  • 感谢您回复戈登。不幸的是,我没有 Author 表。对我来说,完美的解决方案是对桌子书的看法。再次感谢!
  • @Walloud。 . .真可惜。使用connect 的解决方案是要走的路。
  • 戈登有什么丢脸的?请说明您何时使用此类词。
  • @Walloud。 . .很遗憾,您有一个包含书籍的数据库,但没有针对其作者的表格。就这样。你在问题中说数据库设计得不好,你是对的。
猜你喜欢
  • 1970-01-01
  • 2011-04-02
  • 1970-01-01
  • 1970-01-01
  • 2014-05-19
  • 2013-03-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-03
相关资源
最近更新 更多