Informix一对多格式问题

时间:2017-03-10 16:54:25

标签: informix

尝试从一对多关系修复我的Informix查询结果格式。我当前的查询是使用JOIN,但每次与JOIN ON条件匹配时都会创建一个新行。我应该添加以下只是一个例子,真正的数据是成千上万的条目,大约有100个独特的"类别"条目所以我不能硬编码WHERE语句,它需要读取每个条目并添加,如果匹配。我尝试了一个GROUP_CONCAT然而只是返回一个错误,猜测它不是一个informix函数,我也试过读这个线程但是还是无法工作。 Show a one to many relationship as 2 columns - 1 unique row (ID & comma separated list)

任何帮助将不胜感激。

  • IBM / Informix-Connect版本3.70.UC4
  • IBM / Informix LIBGLS LIBRARY版本5.00.UC5
  • IBM Informix Dynamic Server版本11.70.FC8W1

电影

name    rating  movie_id
rio g   1   
horton  g   2
blade   r   3
lotr_1  pg13    4
lotr_2  pg13    5
paul_blart  pg  6

类别

cat_name    id
kids    1
comedy  2
action  3
fantasy 4

category_member

movie_name  cat_name    catmem_id
lotr_1 action 1
lotr_1 fantasy 2
rio kids 3
rio comedy  4

当我使用

#!/bin/bash

echo "SET isolation dirty read;
UNLOAD to /export/home/movie/movieDetail.unl DELIMITER ','
    SELECT a.name, a.rating, b.cat_name
      FROM movie a
      LEFT JOIN category b ON b.movie_name = a.name
;" | dbaccess thedb;

我得到的是

rio,g,kids
rio,g,comedy
lotr_1,pg13,action
lotr_1,pg13,fantasy

我想要的是

rio,g,kids,comedy
lotr_1,pg13,action,fantasy

1 个答案:

答案 0 :(得分:2)

安装GROUP_CONCAT用户定义的聚合

您必须将GROUP_CONCAT用户定义的聚合从SO 715350(在您的问题中引用)安装到您的数据库中。 GROUP_CONCAT聚合不是由Informix定义的,但如果您使用该问题中的SQL,则可以添加该聚合。它与普通内置函数之间的一个区别是,您需要在需要使用它的服务器中的每个数据库中安装聚合。可能有办法进行全球安装' (对于给定服务器中的所有数据库),但我已经忘记了(或者,更确切地说,从未学过)如何做到这一点。

编写查询

底部列出了示例数据库:

  1. 问题中的查询未运行:

    SELECT a.name, a.rating, b.cat_name
      FROM movie a
      LEFT JOIN category b ON b.movie_name = a.name;
    SQL -217: Column (movie_name) not found in any table in the query (or SLV is undefined).
    
  2. 可以通过将category更改为category_member来解决此问题。这会产生:

    SELECT a.name, a.rating, b.cat_name
      FROM movie a
      LEFT JOIN category_member b ON b.movie_name = a.name;
    rio           g       kids
    rio           g       comedy
    horton        g
    blade         r
    lotr_1        pg13    action
    lotr_1        pg13    fantasy
    lotr_2        pg13
    paul_blart    pg
    
  3. LEFT JOIN似乎不受欢迎。使用GROUP_CONCAT会产生大致所需的答案:

    SELECT a.name, a.rating, GROUP_CONCAT(b.cat_name)
      FROM movie a
      JOIN category_member b ON b.movie_name = a.name
     GROUP BY a.name, a.rating;
    rio          g       kids,comedy
    lotr_1       pg13    action,fantasy
    
  4. 如果您将分隔符指定为,,则GROUP_CONCAT运算符数据中的逗号将被转义以避免歧义:

    SELECT a.NAME, a.rating, GROUP_CONCAT(b.cat_name)
      FROM movie a
      JOIN category_member b ON b.movie_name = a.NAME
     GROUP BY a.NAME, a.rating;
    rio,g,kids\,comedy
    lotr_1,pg13,action\,fantasy
    

    在标准的Informix实用程序中,没有办法避免这种情况;他们不会以模糊的格式留下选定/卸载的数据。

  5. 我不相信数据库架构组织得很好。电影表是好的; Category表是可以的;但如果使用模式,则Category_Member表会更正统:

    DROP TABLE IF EXISTS category_member;
    CREATE TABLE category_member
    (
        movie_id INTEGER NOT NULL REFERENCES Movie(Movie_id),
        category_id INTEGER NOT NULL REFERENCES Category(Id),
        PRIMARY KEY(movie_id, category_id)
    );
    INSERT INTO category_member VALUES(4, 3);
    INSERT INTO category_member VALUES(4, 4);
    INSERT INTO category_member VALUES(1, 1);
    INSERT INTO category_member VALUES(1, 2);
    
    -- Use GROUP_CONCAT
    SELECT a.NAME, a.rating, GROUP_CONCAT(c.cat_name)
      FROM movie a
      JOIN category_member b ON b.movie_id = a.movie_id
      JOIN category c ON b.category_id = c.id
     GROUP BY a.NAME, a.rating;
    

    此查询的输出与前一个查询的输出相同,但加入更为正统。

  6. 示例数据库

    DROP TABLE IF EXISTS movie;
    CREATE TABLE movie
    (
        name VARCHAR(20) NOT NULL UNIQUE,
        rating CHAR(4) NOT NULL,
        movie_id SERIAL NOT NULL PRIMARY KEY
    );
    INSERT INTO movie VALUES("rio", "g", 1);
    INSERT INTO movie VALUES("horton", "g", 2);
    INSERT INTO movie VALUES("blade", "r", 3);
    INSERT INTO movie VALUES("lotr_1", "pg13", 4);
    INSERT INTO movie VALUES("lotr_2", "pg13", 5);
    INSERT INTO movie VALUES("paul_blart", "pg", 6);
    
    DROP TABLE IF EXISTS category;
    CREATE TABLE category
    (
        cat_name VARCHAR(10) NOT NULL UNIQUE,
        id SERIAL NOT NULL PRIMARY KEY
    );
    INSERT INTO category VALUES("kids", 1);
    INSERT INTO category VALUES("comedy", 2);
    INSERT INTO category VALUES("action", 3);
    INSERT INTO category VALUES("fantasy", 4);
    
    DROP TABLE IF EXISTS category_member;
    CREATE TABLE category_member
    (
        movie_name VARCHAR(20) NOT NULL,
        cat_name VARCHAR(10) NOT NULL,
        catmem_id SERIAL NOT NULL PRIMARY KEY
    );
    INSERT INTO category_member VALUES("lotr_1", "action", 1);
    INSERT INTO category_member VALUES("lotr_1", "fantasy", 2);
    INSERT INTO category_member VALUES("rio", "kids", 3);
    INSERT INTO category_member VALUES("rio", "comedy", 4);