使用if / else列值,选择不同的表和列

时间:2016-05-10 08:07:36

标签: sql postgresql case postgresql-9.3

目标
我有下面的表, 我想选择comment tbl, 但只返回comment行检查相关表status列所有相等的输入参数。

问题
在查询1中,注释掉我突出显示,否则它将返回零行。 要么 查询2获取错误语法

如何解决这个问题?

comment
id | endpoint_code | endpoint_id | status | create_by_user_id
1  | 1             | 56          | 0      | 1
2  | 0             | 27          | 0      | 1

description:   
endpoint_code  0:gallery tbl 1:media tbl  
use `endpoint_code` value if `0` means `endpoint_id` is point to `gallery` tbl,  
if `1` means point to `media` tbl.


user
id | status 
1  | 0 

gallery
id | status | ...
56 | 0

media
id | status | ...
27 | 0

category_gallery
id | category_id | gallery_id | ...
...

gallery_media
id | gallery_id | media_id | ...
...

查询1

SELECT c.* ,
  row_to_json(m.*) as media,
  row_to_json(mg.*) as media_gallery,
  row_to_json(g.*) as gallery
  FROM comment c
    LEFT JOIN "user" u ON u.id = c.create_by_user_id

    LEFT JOIN media m ON m.id = c.endpoint_id
      AND c.endpoint_code = 1
    LEFT JOIN "user" mcbu ON mcbu.id = m.create_by_user_id
      AND c.endpoint_code = 1
    LEFT JOIN gallery_media gm ON gm.media_id = c.endpoint_id
      AND c.endpoint_code = 1
    LEFT JOIN gallery mg ON mg.id = gm.gallery_id
      AND c.endpoint_code = 1

    LEFT JOIN gallery g ON g.id = c.endpoint_id
      AND c.endpoint_code = 0
    LEFT JOIN "user" gcbu ON gcbu.id = g.create_by_user_id
      AND c.endpoint_code = 0
    LEFT JOIN category_gallery cg ON cg.gallery_id = g.id
      AND c.endpoint_code = 0
    LEFT JOIN category ca ON ca.id = cg.category_id
      AND c.endpoint_code = 0 

    WHERE c.status = $1 
      AND u.status = $1 

      // comment out these for c.endpoint_code 0 (gallery)
      AND 
        CASE WHEN c.endpoint_code = 1
        THEN 
          m.status = $1
        END
      AND 
        CASE WHEN c.endpoint_code = 1
        THEN 
          mcbu.status = $1
        END
      AND 
        CASE WHEN c.endpoint_code = 1
        THEN 
          mg.status = $1
        END
      //


      // or comment out these for c.endpoint_code 1 (media)
      AND 
        CASE WHEN c.endpoint_code = 0
        THEN 
          g.status = $1
        END
      AND 
        CASE WHEN c.endpoint_code = 0
        THEN 
          gcbu.status = $1
        END
      AND 
        CASE WHEN c.endpoint_code = 0
        THEN 
          ca.status = $1
        END
      //

    AND c.id = $2

查询2
错误

SELECT c.* ,
  row_to_json(m.*) as media,
  row_to_json(mg.*) as media_gallery,
  row_to_json(g.*) as gallery
  FROM comment c
    LEFT JOIN "user" u ON u.id = c.create_by_user_id

    LEFT JOIN media m ON m.id = c.endpoint_id
      AND c.endpoint_code = 1
    LEFT JOIN "user" mcbu ON mcbu.id = m.create_by_user_id
      AND c.endpoint_code = 1
    LEFT JOIN gallery_media gm ON gm.media_id = c.endpoint_id
      AND c.endpoint_code = 1
    LEFT JOIN gallery mg ON mg.id = gm.gallery_id
      AND c.endpoint_code = 1

    LEFT JOIN gallery g ON g.id = c.endpoint_id
      AND c.endpoint_code = 0
    LEFT JOIN "user" gcbu ON gcbu.id = g.create_by_user_id
      AND c.endpoint_code = 0
    LEFT JOIN category_gallery cg ON cg.gallery_id = g.id
      AND c.endpoint_code = 0
    LEFT JOIN category ca ON ca.id = cg.category_id
      AND c.endpoint_code = 0 

    WHERE c.status = $1 
      AND u.status = $1 

      CASE WHEN c.endpoint_code = 1
      THEN 
        AND 
          m.status = $1
        AND 
          mcbu.status = $1
        AND 
          mg.status = $1
      END


      CASE WHEN c.endpoint_code = 0
      THEN 
        AND 
          g.status = $1
        AND 
          gcbu.status = $1
        AND 
          ca.status = $1
      END

    AND c.id = $2

我在javascript中执行此操作从函数中生成查询字符串
输入status params是下面的选项,我希望找到解决上述问题的方法, 不想过多地重构代码

查询2例如

var query = `

SELECT c.* ,
  row_to_json(m.*) as media,
  row_to_json(mg.*) as media_gallery,
  row_to_json(g.*) as gallery
  FROM comment c
    LEFT JOIN "user" u ON u.id = c.create_by_user_id


    LEFT JOIN media m ON m.id = c.endpoint_id
      AND c.endpoint_code = 1
`;

if (inputOption.status != 'undefined') {
query += `
    LEFT JOIN "user" mcbu ON mcbu.id = m.create_by_user_id
      AND c.endpoint_code = 1
    LEFT JOIN gallery_media gm ON gm.media_id = c.endpoint_id
      AND c.endpoint_code = 1
`;
}
query += `
    LEFT JOIN gallery mg ON mg.id = gm.gallery_id
      AND c.endpoint_code = 1
`;

query += `
    LEFT JOIN gallery g ON g.id = c.endpoint_id
      AND c.endpoint_code = 0
`;
if (inputOption.status != 'undefined') {
query += `
    LEFT JOIN "user" gcbu ON gcbu.id = g.create_by_user_id
      AND c.endpoint_code = 0
    LEFT JOIN category_gallery cg ON cg.gallery_id = g.id
      AND c.endpoint_code = 0
    LEFT JOIN category ca ON ca.id = cg.category_id
      AND c.endpoint_code = 0 
`;
}

if (inputOption.status != 'undefined') {
query += `
    WHERE c.status = $1 
      AND u.status = $1 

      CASE WHEN c.endpoint_code = 1
      THEN 
        AND 
          m.status = $1
        AND 
          mcbu.status = $1
        AND 
          mg.status = $1
      END


      CASE WHEN c.endpoint_code = 0
      THEN 
        AND 
          g.status = $1
        AND 
          gcbu.status = $1
        AND 
          ca.status = $1
      END
`;
}
query += `
    AND c.id = $2
`;

编辑:进一步的问题

在我选择

之后
SELECT c.* ,
    row_to_json(mg.*) as media_gallery, 
    row_to_json(m.*) as media,
    row_to_json(g.*) as gallery
  FROM comment c

  LEFT JOIN media m ON m.id = c.endpoint_id

.... other query
  query += `
WHERE c.status = $1 
  AND u.status = $1 
  AND
  (
    (c.endpoint_code = 1
     AND m.status = $1
     AND mcbu.status = $1
     AND mg.status = $1
    )
    OR
....

json结果因为endpoint_code = 0所以json键media_gallerymedia(来自查询部分row_to_json(mg.*) as media_gallery, ...)值将为null。
endpoint_code = 1gallery值为空。

如果endpoint_code = 0然后输出media_gallery media,如何过滤/删除,则表示在查询中不执行row_to_json(mg.*) as media_gallery, ...?或其他方式?

rows: 
[ { id: 7,
  endpoint_code: 0,
  endpoint_id: 27,
  status: 0,

  media_gallery: null,
  media: null,
  gallery: 
   { id: 27,
     status: 0,
     create_date: 
   ...

尝试获得像

这样的结果
rows: 
[ { id: 7,
  endpoint_code: 0,
  endpoint_id: 27,
  status: 0,

  gallery: 
   { id: 27,
     status: 0,
     create_date: 
   ...

rows: 
[ { id: 7,
  endpoint_code: 1,
  endpoint_id: 27,
  status: 0,

  media_gallery: {
    id: ....
  },
  media: 
   { id: 27,
     status: 0,
     create_date: 
   ...

2 个答案:

答案 0 :(得分:2)

CASE不作为模板工作,而是作为一种功能。更新您的JavaScript,如下所示:

if (inputOption.status != 'undefined') {
query += `
    WHERE c.status = $1 
      AND u.status = $1 

      AND CASE WHEN c.endpoint_code = 1 -- this will return a boolean
      THEN m.status = $1
       AND mcbu.status = $1
       AND mg.status = $1
      END   

      AND CASE WHEN c.endpoint_code = 0 -- this too
      THEN g.status = $1
       AND gcbu.status = $1
       AND ca.status = $1
      END
`;

上述工作,但它不允许PostgreSQL优化查询。如果你使用AND和OR会好得多,正如@jarlh在评论中指出的那样:

if (inputOption.status != 'undefined') {
query += `
    WHERE c.status = $1 
      AND u.status = $1 
      AND
      (
        (c.endpoint_code = 1
         AND m.status = $1
         AND mcbu.status = $1
         AND mg.status = $1
        )
        OR
        (c.endpoint_code = 0
         AND g.status = $1
         AND gcbu.status = $1
         AND ca.status = $1)
      )
`;

答案 1 :(得分:1)

解决问题的第二部分,您似乎将查询结果检索为单个JSON文档,其中rows对象是查询返回的实际行数组。如果这是你想要的,那么你可以选择在返回的整行上使用jsonb_strip_nulls()函数:

SELECT array_to_json(ARRAY(
  SELECT json_strip_nulls(row_to_json(r.*)) AS comment
  FROM (
    SELECT c.* ,
      row_to_json(m.*) as media,
      row_to_json(mg.*) as media_gallery,
      row_to_json(g.*) as gallery
    ...
    ) r
  )) AS rows