从查询

时间:2017-03-05 00:45:16

标签: sql postgresql node-postgres

我有一个看起来像这样的表(简化):

  CREATE TABLE IF NOT EXISTS records (
    user_id   uuid NOT NULL
    ts        timestamptz NOT NULL,
    op_type   text NOT NULL,
    PRIMARY KEY (user_id, ts, op_type)
  );

我不能为实际目的改变PRIMARY KEY。

我正在尝试编写一个查询,以获取给定records的所有user_id,对于特定记录,tsop_type不会匹配一系列排除。

我不完全确定正确的postgres术语,所以让我看看这个例子是否使我的约束更清晰:

这个数组看起来像这样(在JavaScript中):

var excludes = [
  [DATE1, 'OP1'],
  [DATE2, 'OP2']
]

如果对于给定的用户ID,数据库中有如下所示的行:

             ts             |   op_type   
----------------------------+-------------
 DATE1                      | OP1
 DATE2                      | OP2
 DATE1                      | OP3
 DATE2                      | OP1
 OTHER DATE                 | OP1
 OTHER DATE                 | OP2

然后,使用上面的excludes,我想运行一个返回EXCEPT或前两行的查询,因为它们完全匹配。

我的尝试是这样做:

client.query(`
    SELECT * FROM records
      WHERE
        user_id = $1
        AND (ts, op_type) NOT IN ($2)
`, [userId, excluding])

但我得到“匿名复合类型的输入未实现”。我不确定如何正确输入excluding或者这是否是正确的方法。

1 个答案:

答案 0 :(得分:3)

查询可能如下所示

SELECT * 
FROM records
WHERE user_id = 'a0eebc999c0b4ef8bb6d6bb9bd380a11'
AND (ts, op_type) NOT IN (('2016-01-01', 'OP1'), ('2016-01-02', 'OP2'));

因此,如果您想将条件作为单个参数传递,那么excluding应该是格式为的字符串:

('2016-01-01', 'OP1'), ('2016-01-02', 'OP2')

似乎没有简单的方法将条件字符串作为参数传递给query()。您可以尝试编写一个函数来以正确的格式获取字符串(我不是JS开发人员,但这段代码似乎运行良好):

excluding = function(exc) {
    var s = '(';
    for (var i = 0; i < exc.length; i++)
        s = s+ '(\''+ exc[i][0]+ '\',\''+ exc[i][1]+ '\'),';
    return s.slice(0, -1)+ ')';
};

var excludes = [
    ['2016-01-01', 'OP1'],
    ['2016-01-02', 'OP2']
];

// ...

client.query(
    'SELECT * FROM records '+
    'WHERE user_id = $1 '+
    'AND (ts, op_type) NOT IN ' + excluding(excludes),
    [userId])