【问题标题】:sql query to extract new recordssql查询提取新记录
【发布时间】:2014-12-23 07:01:44
【问题描述】:

我有以下表格:

CREATE TABLE Company (
    CompanyUniqueID BIGSERIAL PRIMARY KEY NOT NULL,
    Name VARCHAR (150) NOT NULL
 );

CREATE TABLE Item ( 
  ItemUniqueID BIGSERIAL PRIMARY KEY NOT NULL,
  CompanyUniqueID BIGINT NULL REFERENCES company DEFERRABLE INITIALLY DEFERRED,
  Name VARCHAR (150) NOT NULL,
  AddedDate TIMESTAMP without time zone DEFAULT now()
);

在应用程序的生命周期中,新的公司和项目被添加到表中。 我希望创建一个 sql 查询,从给定日期选择“新添加的公司” 我从这个查询开始:

(Select * from company
 where companyuniqueid in (
   select distinct companyuniqueid from Item where AddedDate > '2014-10-25'))

上述情况不好,因为在 2014-10-25 之后添加并且属于已经存在的公司的项目也会被选中。

例如,2014 年 10 月 20 日Company 表的快照可能如下所示:

1 AAA
2 BBB
3 CCC

表格项看起来像:

1 1 111 2014-10-01
2 2 222 2014-10-10
3 2 333 2014-10-10
4 3 444 2014-10-15

2014-10-26 增加了以下记录:

表公司

4 DDD

表格项目

5 1 555 2014-10-26
6 3 663 2014-10-26
7 4 777 2014-10-27

我已尝试将此添加到查询中:

(Select * from company
 where companyuniqueid in (
    select distinct companyuniqueid from Item
    where AddedDate > '2014-10-25')
 and companyuniqueid not in (
    select distinct companyuniqueid from Item
    where AddedDate <= '2014-10-25'))

但是我得到一个空的结果,为了只收到 4 个 DDD 应该是什么查询?

【问题讨论】:

  • AddedDate supposed 是否允许 NULL 值?作为NOT NULL 约束的候选者,让我印象深刻。

标签: sql postgresql exists


【解决方案1】:

使用EXISTS 反半连接。通常比NOT IN 更快更干净:

SELECT *
FROM   company c
WHERE  NOT EXISTS (
   SELECT 1
   FROM   item
   WHERE  addeddate < '2014-10-25'
   AND    companyuniqueid = c.companyuniqueid);

这将返回
在给定日期之前没有任何项目的公司。
包括没有物品的公司,也可能有带有addeddate IS NULL的物品。
要将结果限制在有新项目的公司,请添加:

WHERE  EXISTS (
   SELECT 1
   FROM   item
   WHERE  addeddate >= '2014-10-25'
   AND    companyuniqueid = c.companyuniqueid)

但请考虑将另一列 added_date 添加到表 company 以避免歧义并简化事情。

为什么原来的查询不起作用?

可能是 NOT IN 的另一种情况,其中集合包含 NULL
您的列 item.companyuniqueid 允许 NULL 值。您的子查询:

select distinct companyuniqueid from Item where AddedDate <= '2014-10-25'

... 可能包含 NULL 值。在那种情况下,这个表达式永远不会是TRUE

companyuniqueid not in (<above subquery>)

如果集合包含 NULL 值,则返回 FALSENULL(“未知”)。但只有TRUE 符合WHERE 条件。所以没有返回任何行。

Note that the same is not true for an empty set. 如果上述子查询将返回无行,则NOT IN 表达式将计算为TRUE,只要左侧是NOT NULL

基本上,尽可能避免使用NOT IN (&lt;subquery&gt;)NOT EXISTS 几乎总是出类拔萃。
如果您使用它,请了解 NULL 值。更多详情:

【讨论】:

  • @Gordon:item 的表别名不需要。查询按原样有效。没有表限定 item.companyuniqueid 在子查询中首先可见。
  • 我看到你删除了它。我发现这种两边都没有别名的语法很危险。
  • 在我的示例中,添加了公司 #4 (DDD),并且项目 #7 添加了另一列是不可能的,客户请求
  • @liva:考虑添加的解释和链接。
  • @GordonLinoff:毫无疑问是正确的。这里的“危险”在旁观者的眼中。
【解决方案2】:
with min_added as
(
    select i.companyuniqueid, min(i.addeddate) as addeddate
      from item i
  group by companyuniqueid
)
select * from min_added where min_added.addeddate > '2014-10-26';

将为您提供在指定日期之后添加项目的所有公司的公司 ID(对于在该日期之前添加项目的任何公司,不会返回任何公司。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-15
    • 2012-01-12
    • 2021-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多