【问题标题】:How to split comma-separated values into multiple rows in Oracle table如何将逗号分隔的值拆分为 Oracle 表中的多行
【发布时间】:2018-03-26 00:34:30
【问题描述】:
SELECT year, movietitle, director, actorname 
  FROM films11 
  WHERE actorname like '%Christina Ricci%' 
  order by year asc;

在 ORACLE SQL Developer 中从原始数据模式生成以下内容。

我想转换整个表,使主键成为actor name。 (如第二张表)

这样查询

SELECT year, movietitle, director, actorname 
  FROM films11 
  WHERE actorname like '%Christina Ricci%' 
  order by year asc;

将只生成搜索到的项目(要么创建一个新视图,要么完全更改数据架构。)(第三个表)

【问题讨论】:

  • 横向转动显示器
  • 你已经在截图中找到了答案。您的新表只需要在 ACTORNAME 列中为每个不同的 Actor 设置一行,如屏幕截图的第三个表所示。或者,您可以使用@Strawberry 的建议。
  • 表格的行数太多,无法做到这一点。我想知道是否有一个 SQL 查询用逗号分隔 ACTORNAME 列中的名称,就像你说的那样成一个新行...
  • 有一种方法,但 SQL 作为一种专用语言,最适合用于基于集合的检索/操作操作,这样的细微差别很复杂,可能涉及过程 SQL。我建议导入通用语言 Java/Python/PHP/R 并从那里进行争论(即,用逗号分隔,重新整形为行)。
  • 您是否考虑过规范化数据库设计?你可以有一个actor 表、一个film 表和一个actedInFilm 表。查询这个会更直接。

标签: sql oracle pivot oracle-sqldeveloper normalization


【解决方案1】:

第 1 步:“如何炸毁数据库”

发件人:

SQL Fiddle

Oracle 11g R2 架构设置

查询 1

select * from films11

Results

| YEAR | DIRECTOR | MOVIETITLE |      ACTORNAME |
|------|----------|------------|----------------|
| 2000 |     dir1 |     title1 |      act1,act2 |
| 2001 |     dir2 |     title2 | act1,act2,act3 |
| 2002 |     dir1 |     title3 |           act4 |

查询 2

select YT.year, YT.movietitle,
       REPLACE(REGEXP_SUBSTR(YT.actorname||',','.*?,',1,lvl.lvl),',','') AS actorname
from films11 YT
join (select level as lvl 
      from dual 
      connect by level <= (select max(regexp_count(actorname,',')+1) from films11)
     ) lvl on lvl.lvl <= regexp_count(YT.actorname,',')+1
     order by YT.year, YT.movietitle, actorname

有一个不错的笛卡尔积

Results

| YEAR | MOVIETITLE | ACTORNAME |
|------|------------|-----------|
| 2000 |     title1 |      act1 |
| 2000 |     title1 |      act2 |
| 2001 |     title2 |      act1 |
| 2001 |     title2 |      act2 |
| 2001 |     title2 |      act3 |
| 2002 |     title3 |      act4 |

您运行它ONCE并使用它将所有内容移动到规范化数据库中


这里是将架构更改为更方便的完整脚本...

CREATE TABLE actors(
    id_actor NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY,
    act_name VARCHAR2(100)
) 
;

CREATE TABLE directors(
    id_director NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY,
    dir_name VARCHAR2(100)
) 
;

CREATE TABLE movies(
    id_movie NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY,
    mov_year NUMBER,
    mov_name VARCHAR2(100),
    director_id NUMBER
) 
;

CREATE TABLE playedby(
    movie_id NUMBER,
    actor_id NUMBER
) 
;

    INSERT INTO directors (dir_name)
    SELECT DISTINCT director dir_name
    FROM films11
    ;

    INSERT INTO movies (mov_year, mov_name, director_id)
    SELECT year mov_year, movietitle mov_name, directors.id_director director_id
    FROM films11
    INNER JOIN directors ON directors.dir_name = films11.director

    ;

    INSERT INTO actors (act_name)
    SELECT DISTINCT t.actorname act_name
    FROM (
        SELECT YT.year, YT.movietitle,
               REPLACE(REGEXP_SUBSTR(YT.actorname||',','.*?,',1,lvl.lvl),',','') AS actorname
        FROM films11 YT
        JOIN (SELECT level AS lvl 
              FROM dual 
              CONNECT BY level <= (SELECT MAX(REGEXP_COUNT(actorname,',')+1) FROM films11)
             ) lvl ON lvl.lvl <= REGEXP_COUNT(YT.actorname,',')+1
    ) t
    ;

    INSERT INTO playedby (movie_id, actor_id)
    SELECT movies.id_movie movie_id, actors.id_actor actor_id
    FROM (
        SELECT YT.year, YT.movietitle,
               REPLACE(REGEXP_SUBSTR(YT.actorname||',','.*?,',1,lvl.lvl),',','') AS actorname
        FROM films11 YT
        JOIN (SELECT level AS lvl 
              FROM dual 
              CONNECT BY level <= (SELECT MAX(REGEXP_COUNT(actorname,',')+1) FROM films11)
             ) lvl ON lvl.lvl <= REGEXP_COUNT(YT.actorname,',')+1
    ) t
    INNER JOIN actors ON t.actorname = actors.act_name
    INNER JOIN movies ON t.year = movies.mov_year AND t.movietitle = movies.mov_name 

    ;

之后,您可以像这样进行选择:

查询 3

SELECT mov_year, mov_name, dir_name, act_name 
FROM movies
INNER JOIN directors ON directors.id_director = movies.director_id
INNER JOIN playedby ON movies.id_movie = playedby.movie_id
INNER JOIN actors ON playedby.actor_id = actors.id_actor
WHERE act_name like '%act2%' 
order by mov_year asc

Results

| MOV_YEAR | MOV_NAME | DIR_NAME | ACT_NAME |
|----------|----------|----------|----------|
|     2000 |   title1 |     dir1 |     act2 |
|     2001 |   title2 |     dir2 |     act2 |

【讨论】:

  • 美丽在您的回复之后,这非常有帮助。 [SQLFiddle] 网站 (sqlfiddle.com) 就像我今天学到的第二好的东西。
猜你喜欢
  • 2013-09-17
  • 2019-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多