4

問題が発生したので、誰かが私を助けてくれることを願っています。実際、私は不十分に設計されたデータベースで作業しており、データベース内の内容を変更することはできません。私は「本」というテーブルを持っており、各本には1人以上の著者を含めることができます。残念ながら、データベースは完全にリレーショナルではありません(最初から同じ質問をしているので、理由を聞かないでください)。表「Books」には「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クエリを実行すると、CLOBフィールドの一部に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値を入れるのですか?ありがとうございました。

4

4 に答える 4

2

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;

フィドル

于 2013-03-25T18:15:16.233 に答える
1

数週間前、私はここで同様の質問に答え ました。その答えには一般的なアプローチの説明があります(私は願っています)ので、ここでは説明をスキップします。このクエリでうまくいきます。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

ここにデータと別の行のフィドルがあります。


補遺:OPには11ではなくOracle 9があるため、正規表現は機能しません。以下は、正規表現なしで同じタスクを実行するための手順です...

がないREGEXP_COUNT場合、作成者を数える最良の方法は、アスタリスクを数えて1つ追加することです。アスタリスクを数えるには、文字列の長さを取得し、すべてのアスタリスクが文字列から吸い出されたときにその長さを減算します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*

次に、「Counter」テーブルとの結合と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

フィドルはここにあります

于 2013-03-25T18:04:58.210 に答える
0

テーブルがある場合は、次のauthorsことができます。

select b.id_book, a.id_author, a.NameAuthor
from books b left outer join
     authors a
     on '*'||NameAuthor||'*' like '%*||a.author||'*%'
于 2013-03-25T18:05:05.607 に答える
0

加えて:

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
于 2013-03-25T19:24:18.697 に答える