【问题标题】:Select a table or array for each row of a bigger select query为更大的选择查询的每一行选择一个表或数组
【发布时间】:2010-12-22 12:48:56
【问题描述】:

使用 Oracle 11g

假设我们有两个表:

CREATE TABLE items (
    item_id NUMBER(22,0)
);

CREATE TABLE messages (
    item_id NUMBER(22,0),
    message_code NUMBER(22,0)
);

存在一对多(消息)关系的(项目)。我想在单个查询中选择所有内容以将其导入 java。是否可以编写这样的查询,它会给我这样的输出:

ID         MESSAGE
----------------------------------
1          (100, 105, 201)
2          (100, 105)

其中 MESSAGE 列是一个数组或类似的东西(不是串联字符串)?

【问题讨论】:

  • 为什么不希望每个 ID 使用多行?一旦脱离了关系模型,就很难回头,而且你最终会支持各种在许多情况下无用的奇怪查询。
  • @jonearles:查询如何破坏模型?

标签: sql oracle oracle11g


【解决方案1】:

您可以使用字段级游标:

WITH    items AS
        (
        SELECT  1 AS item_id
        FROM    dual
        UNION ALL
        SELECT  2 AS item_id
        FROM    dual
        ),
        messages AS
        (
        SELECT  1 AS item_id, 100 AS message_code
        FROM    dual
        UNION ALL
        SELECT  1 AS item_id, 105 AS message_code
        FROM    dual
        UNION ALL
        SELECT  1 AS item_id, 201 AS message_code
        FROM    dual
        UNION ALL
        SELECT  2 AS item_id, 100 AS message_code
        FROM    dual
        UNION ALL
        SELECT  2 AS item_id, 15 AS message_code
        FROM    dual
        )
SELECT  item_id,
        CURSOR
        (
        SELECT  message_code
        FROM    messages m
        WHERE   m.item_id = i.item_id
        )
FROM    items i

或创建一个表类型并将值的MULTISET 转换为该类型:

CREATE TYPE t_message_code AS TABLE OF INTEGER

WITH    items AS
        (
        SELECT  1 AS item_id
        FROM    dual
        UNION ALL
        SELECT  2 AS item_id
        FROM    dual
        ),
        messages AS
        (
        SELECT  1 AS item_id, 100 AS message_code
        FROM    dual
        UNION ALL
        SELECT  1 AS item_id, 105 AS message_code
        FROM    dual
        UNION ALL
        SELECT  1 AS item_id, 201 AS message_code
        FROM    dual
        UNION ALL
        SELECT  2 AS item_id, 100 AS message_code
        FROM    dual
        UNION ALL
        SELECT  2 AS item_id, 15 AS message_code
        FROM    dual
        )
SELECT  item_id,
        CAST
        (
        MULTISET
        (
        SELECT  message_code
        FROM    messages m
        WHERE   m.item_id = i.item_id
        ) AS t_message_code
        )
FROM    items i

【讨论】:

  • 感谢您的回答!我使用了第二个变体 - 使用 MULTISET 和表格类型 - 它就像一个魅力。它非常适合 Java 应用程序,因为我们已经使用表类型将值列表传递给存储过程。至于第一个变体,我在 SQLDeveloper 中尝试过,起初它可以工作,但后来我收到一个错误,说我已达到最大游标数(表大约 100 行长)。
【解决方案2】:

以 Quassnoi 的答案为基础,还有 COLLECT 函数,它与另一个答案中的 MULTISET 执行相同的操作,但没有子查询。

CREATE TYPE t_message_code AS TABLE OF INTEGER;

WITH    items AS
        (
        SELECT  1 AS item_id
        FROM    dual
        UNION ALL
        SELECT  2 AS item_id
        FROM    dual
        ),
        messages AS
        (
        SELECT  1 AS item_id, 100 AS message_code
        FROM    dual
        UNION ALL
        SELECT  1 AS item_id, 105 AS message_code
        FROM    dual
        UNION ALL
        SELECT  1 AS item_id, 201 AS message_code
        FROM    dual
        UNION ALL
        SELECT  2 AS item_id, 100 AS message_code
        FROM    dual
        UNION ALL
        SELECT  2 AS item_id, 15 AS message_code
        FROM    dual
        )
SELECT  i.item_id, 
  cast(collect(m.message_code) as t_message_code) as messages_codes
FROM    
  items i
  join messages m on (m.item_id = i.item_id)
group by i.item_id;

【讨论】:

    【解决方案3】:

    注意:这会给你一个字符串(不是你想要的),但我会在这里留下这个答案,因为这个问题经常被问到,而且并不是所有人都知道这种简单的解决方案

      SELECT item_id AS id,
             wm_concat(message_code) AS message
        FROM messages
    GROUP BY item_id
    

    如果您需要消息 ID 列表周围的括号,您可以使用连接:

    '(' || wm_concat(message_code) || ')' AS message
    

    【讨论】:

    • 这将产生一个串联的字符串
    • @Quassnoi:是的,错过了 OP 不希望它成为一个字符串:-S 感谢您的纠正......
    • 清除我不想要字符串的原因。我的目标是在 Java 中获得所有这些值。字符串需要解析。这里的第一个问题是,如果消息不仅包含代码,还包含文本,事情会变得复杂。第二个问题是,在我们的项目中,我们没有在 Java 中使用 OOP 域模型,因此没有完成自定义转换/映射。我们使用地图和列表,理想情况下我希望这个数组显示为地图列表。如果是连接字符串,我会手动指定应该解析哪一列并使用哪种格式。
    • 并且 wm_concat 没有记录,因此使用风险自负。
    • 在 11.2 中,您可以使用已记录的 listagg。
    猜你喜欢
    • 1970-01-01
    • 2019-06-19
    • 1970-01-01
    • 2012-06-04
    • 2011-01-03
    • 2012-10-15
    • 2010-12-25
    • 1970-01-01
    • 2022-01-17
    相关资源
    最近更新 更多