SQL:过滤行

Jin*_*Kim 6 sql postgresql postgresql-9.1

我正在尝试编写一个SQL查询,该查询返回包含数据的表中的行:

表结构如下:

CREATE TABLE person(
    id INT PRIMARY KEY,
    name TEXT,
    operation TEXT);
Run Code Online (Sandbox Code Playgroud)

我想返回尚未"取消"的所有唯一名称行.如果操作是"插入"或"删除"并且存在具有相同操作的相同名称的另一行,则认为行被"取消".

例如,如果我有以下行

id   name   operation
1    bob    insert
2    bob    delete
3    bob    insert
Run Code Online (Sandbox Code Playgroud)

前两行相互"取消",因为它们使用相反的操作共享相同的名称.所以查询应该返回第3行.

这是另一个例子:

id   name   operation
1    bob    insert
2    bob    delete
3    bob    insert
4    bob    delete
Run Code Online (Sandbox Code Playgroud)

在这种情况下,行1和2抵消,行3和4抵消.因此查询不应返回任何行.

最后的例子:

id   name   operation
1    bob    insert
2    bob    insert
Run Code Online (Sandbox Code Playgroud)

在这种情况下,行1和2不会取消,因为操作不相反.所以查询应该返回两行.

我有以下查询处理前两个方案,但它不处理最终方案.

有没有人对可以处理所有3种情况的查询有任何建议?

SELECT MAX(id),name 
FROM person z 
WHERE operation IN ('insert','delete') 
GROUP BY name 
HAVING count(1) % 2 = 1;
Run Code Online (Sandbox Code Playgroud)

Con*_*rix 4

一种方法是比较操作计数。由于您还需要获取与 InsertCount - deleteCount 或 InsertCount - deleteCount 相对应的 INSERTS 或 DELETES 数量,并且由于 PostgreSQL 支持窗口函数,您应该能够使用 row_number()。

注意:我还没有对此进行测试,但是根据PostgreSQL 手册第 3 章高级功能,3.5 窗口函数,您可以在内联查询中引用窗口函数

SELECT
       id, name
FROM
   (
    SELECT 
            row_number() over (partition by p.name, p.operation order by p.id desc) rn , 
            id,  
            p.Name,
            p.operation, 
            operationCounts.InsertCount,
            operationCounts.deleteCount

    FROM 
       Person p
    INNER JOIN (

        SELECT 
          SUM(CASE WHEN operation = 'insert' then 1 else 0 END) InsertCount,
          SUM(CASE WHEN operation = 'delete' then 1 else 0 END) deleteCount,
          name 
        FROM 
           person 
        GROUP BY
           name ) operationCounts
    ON p.name = operationCounts.name
    WHERE 
      operationCounts.InsertCount <> operationCounts.deleteCount) data
WHERE
      (rn <=  (InsertCount -  deleteCount)
      and operation = 'insert')
      OR
     (rn <=  (deleteCount -  InsertCount)
      and operation = 'delete')
Run Code Online (Sandbox Code Playgroud)