比较同一个表的不同订单

时间:2015-11-30 12:03:54

标签: sql postgresql

我有以下场景,一个包含以下列的表:

table_id|user_id|os_number|inclusion_date

在系统中,os_number对用户来说是连续的,但由于系统错误,一些用户以错误的顺序插入操作系统。像这样:

table_id | user_id | os_number | inclusion_date
-----------------------------------------------
1        | 1       | 1         | 2015-11-01
2        | 1       | 2         | 2015-11-02
3        | 1       | 3         | 2015-11-01
  • 请注意在编号为2的
  • 之前插入的编号3

我需要什么:

恢复第2行和第3行的table_id,这是乱序的。

我有两个选择以两个不同的顺序向我显示table_id:

select table_id from table order by user_id, os_number

select table_id from table order by user_id, inclusion_date

我无法弄清楚如何比较这两个选项,看看哪些用户受到此系统错误的影响。

6 个答案:

答案 0 :(得分:2)

您的问题有点困难,因为没有正确的排序(如所示) - 因为日期可以有关系。因此,使用rank()dense_rank()函数比较两个值并返回不正确顺序的值:

select t.*
from (select t.*,
             rank() over (partition by user_id order by inclusion_date) as seqnum_d,
             rank() over (partition by user_id order by os_number) as seqnum_o
      from t
     ) t
where seqnum_d <> seqnum_o;

答案 1 :(得分:1)

对两个订单使用row_number()

select *
from (
    select *, 
        row_number() over (order by os_number) rnn,
        row_number() over (order by inclusion_date) rnd
    from a_table
    ) s
where rnn <> rnd;

 table_id | user_id | os_number | inclusion_date | rnn | rnd 
----------+---------+-----------+----------------+-----+-----
        3 |       1 |         3 | 2015-11-01     |   3 |   2
        2 |       1 |         2 | 2015-11-02     |   2 |   3
(2 rows)

答案 2 :(得分:1)

不完全确定此方面的性能,但您可以在同一个表上使用交叉应用以在一个查询中获得结果。这将调出不正确的table_ids对。

select 
    a.table_id as InsertedAfterTableId,
    c.table_id as InsertedBeforeTableId
from table a
cross apply 
(
    select b.table_id
    from table b
    where b.inclusion_date < a.inclusion_date and b.os_number > a.os_number
) c

答案 3 :(得分:0)

我会使用WINDOW FUNCTIONS获取相关订单中的row numbers,然后对其进行比较:

new width

修改

由于a_horse_with_no_name对我的最终答案有所了解。我回到了我的第一个答案(查看编辑历史记录),如果SELECT sub.table_id, sub.user_id, sub.os_number, sub.inclusion_date, number_order_1, number_order_2 FROM ( SELECT table_id, user_id, os_number, inclusion_date, row_number() OVER (PARTITION BY user_id ORDER BY os_number ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) AS number_order_1, row_number() OVER (PARTITION BY user_id ORDER BY inclusion_date ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) AS number_order_2 FROM table ) sub WHERE number_order_1 <> number_order_1 ; 没有无间隙,那么该工作也会有效。

答案 4 :(得分:0)

下面给出的两个查询示例只是检查包含日期和os_number之间的不匹配:

第一个查询应返回有问题的行(os_number从其包含日期开始关闭的行) - 在示例行3的情况下。

select table.table_id, table.user_id, table.os_number from table
 where EXISTS(select * from table t
 where t.user_id = table.user_id and
       t.inclusion_date > table.inclusion_date and
       t.os_number < table.os_number);

第二个查询将返回两个不匹配行的表号和用户:

 select first_table.table_id, second_table.table_id, first_table.user_id from
  table first_table 
  JOIN table second_table
  ON (first_table.user_id = second_table.user_id and
      first_table.inclusion_date > second_table.inclusion_date and
      first_table.os_number < second_table.os_number);

答案 5 :(得分:0)

select *
from (
  select a_table.*,
  lag(inclusion_date) over (partition by user_id order by os_number) as last_date
  from a_table
) result
where last_date is not null AND last_date>inclusion_date;

这应该包括差距和关系。基本上,我只是检查最后一个os_number的inclusion_date,并确保它不是严格地大于当前日期(所以同一日期的2个版本没问题)。