Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
SQL:筛选行_Sql_Postgresql_Postgresql 9.1 - Fatal编程技术网

SQL:筛选行

SQL:筛选行,sql,postgresql,postgresql-9.1,Sql,Postgresql,Postgresql 9.1,我试图编写一个SQL查询,从包含数据的表中返回行: 表格结构如下: CREATE TABLE person( id INT PRIMARY KEY, name TEXT, operation TEXT); 我想返回所有未取消的唯一名称行。 如果操作是insert或delete,并且存在另一个具有相同名称且具有相反操作的行,则认为该行已取消 例如,如果我有以下行 id name operation 1 bob insert 2 bob de

我试图编写一个SQL查询,从包含数据的表中返回行:

表格结构如下:

CREATE TABLE person(
    id INT PRIMARY KEY,
    name TEXT,
    operation TEXT);
我想返回所有未取消的唯一名称行。 如果操作是insert或delete,并且存在另一个具有相同名称且具有相反操作的行,则认为该行已取消

例如,如果我有以下行

id   name   operation
1    bob    insert
2    bob    delete
3    bob    insert
前两行相互抵消,因为它们具有相同的名称,并且具有相反的操作。因此,查询应该返回第3行

下面是另一个例子:

id   name   operation
1    bob    insert
2    bob    delete
3    bob    insert
4    bob    delete
在这种情况下,第1行和第2行取消,第3行和第4行取消。因此,查询不应返回任何行

最后一个例子:

id   name   operation
1    bob    insert
2    bob    insert
在这种情况下,第1行和第2行不会取消,因为操作不是相反的。因此,查询应该同时返回两行

下面的查询处理前两个场景,但不处理最后一个场景

有人对可以处理所有3种情况的查询有什么建议吗

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

一种方法是比较操作计数。由于您还需要获取与InsertCount-deleteCount或InsertCount-deleteCount相对应的插入或删除的数量,并且由于PostgreSQL支持,因此您应该能够使用row_number

注意:我没有对此进行测试,但根据这一点,您可以在内联查询中引用窗口函数

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')

最佳速度和最短答案: 这个问题可以归结为

统计每个名称的删除操作 忽略第一个cnt_del插入 这可以用这种方式一次完成:不知道这个查询是否一切正常

select * from(
    SELECT id, name, 
       row_number() over (partition by name order by case 
                                                     when operation = 'insert' 
                                                     then id 
                                                     else null end 
                                            nulls last ) rnk_insert,
       count(case 
             when operation='delete' then 1 
             else null 
             end) over (partition by name) as cnt_del 
    FROM person z 
    WHERE operation IN ('insert','delete') 
)
where rnk_insert > cnt_del
如果以前的解决方案在postgresAFAIK中不起作用,Oracle可以处理它。解决方案可以以更轻松的方式实施:

select i.id, i.name 
from

  (select id, name, 
         row_number over (partition by name order by id) as rnk_insert
  from person z
  where operation='insert') i

  left join 

  (select name, count(*) as cnt_del
  from person z 
  where operation='delete') d

  on d.name = i.name

where rnk_insert > coalesce(cnt_del, 0)

测试显示我最初的查询比@Conrad的优秀查询慢。我很谦卑,尝试了一些事情,提出了一个实际上更简单、更快的查询

测试设置 查询:
它最终与@Conrad的查询相似,只是做了一些简化/改进。关键的一点是要消除在游戏早期被取消的名字。

顺序重要吗?如果你有INSERT,INSERT,DELETE哪个INSERT应该被保留?@Martin-最新的INSERT行是最相关的,所以我猜是第二行。这是很有趣的,但仍然缺少一些东西。您只提供了maxp.id,您应该提供更多,请参见问题“示例3。我在运行查询时遇到以下错误:错误:列引用名称不明确第6行:按名称划分的行数,操作…@Jin对此表示抱歉。我忘记了第_行中的表格别名。“我修好了。”康拉德谢谢你的帮助。不过,我现在遇到了一个不同的错误:错误:表操作计数第27行的子句条目中缺少:rn@Jin doh复制/粘贴错误再次触发。我修好了。在这种情况下,我们不需要别名引用,但如果需要,它将是数据
INSERT INTO person
SELECT i
      ,'name' || (random() * 500)::int::text
      ,CASE WHEN random() >= 0.5 THEN 'insert' ELSE 'delete' END
FROM   generate_series(1,10000) AS i;
SELECT id, name, operation
FROM  (
    SELECT row_number() OVER (PARTITION BY name, operation ORDER by id) AS rn
          ,id
          ,name
          ,operation
          ,y.cancel
    FROM  (
       SELECT name
             ,least(ct_del, ct_all - ct_del) AS cancel
       FROM  (
          SELECT name
                ,count(*) AS ct_all
                ,count(NULLIF(operation, 'insert')) AS ct_del
          FROM   person
          GROUP  BY 1
          )   x
       WHERE (ct_all - ct_del) <> ct_del
       )   y
    JOIN   person USING (name)
    )   p
WHERE  rn > cancel