查询NOT NULL,但仅当不用作FK时查询

时间:2019-02-06 12:34:12

标签: postgresql postgresql-9.6

def get_success_url(self):
    return reverse_lazy('settings:category_list')

def get_error_url(self):
    return reverse_lazy('settings:category_list')

def get_context_data(self, **kwargs):
    context = super().get_context_data(**kwargs)
    context['active_menu'] = {"menu1":"setting","menu2":"category","menu3":"basic","menu4":"category"}
    return context

def delete(self, request, *args, **kwargs):
    obj = self.get_object()
    get_success_url = self.get_success_url()
    get_error_url = self.get_error_url()
    try:
        obj.delete()
        messages.success(self.request, self.success_message % obj.__dict__)
        return HttpResponseRedirect(get_success_url)
    except ProtectedError:
        messages.warning(self.request, self.protected_error % obj.__dict__)
        return HttpResponseRedirect(get_error_url)

area
-----
id           BIGSERIAL PRIMARY KEY
deleted_at   TIMESTAMP WITH TIME ZONE   DEFAULT NULL

我想从registration ----- area_id BIGINT REFERENCES area(id) NOT NULL 获取所有具有area和可以拥有deleted_at IS NULL但是的记录,它们作为FK出现在{{ 1}}。

deleted_at is NOT NULL

将省略registration中属于FK但已标记为“已删除”的SELECT * FROM area JOIN registration AS reg ON reg.area_id=area.id WHERE area.deleted_at IS NULL; 记录。

area子句的registration列中添加AND子句是没有意义的,因为这只会去除有效的记录。

由于两个deleted_at条件彼此矛盾,所以我无法完全包住它。

4 个答案:

答案 0 :(得分:1)

尝试这样的事情:

SELECT *
  FROM area
    LEFT JOIN registration AS reg ON reg.area_id = area.id
  WHERE (area.deleted_at IS NULL) <> (reg.area_id IS NOT NULL)

LEFT JOIN将列出所有area行,即使没有registration中的匹配行也是如此。 (这些行的结果NULL值。)
WHERE子句确保两个字段不是同时NULL

答案 1 :(得分:1)

我认为这就是您的要求。当您使用左连接时,用于注册的数据字段将在注册表中不存在的地方显示为空。

select * from area
left join registration as reg
on reg.area_id= area.id
where area.deleted_at is null or reg.area_id is not null;

答案 2 :(得分:1)

-- I need (0) all area records EXCEPT the ones where (1) deleted_at IS NOT NULL
-- AND (2) are NOT present as FKs in registration.

SELECT * FROM area a
WHERE NOT(
   a.deleted_at IS NOT NULL -- (1)
   AND NOT EXISTS (
        SELECT *                -- (2)
        FROM registration r 
        WHERE r.area_id=a.id
        )
     );

请注意:您的文字措辞令人困惑:EXCEPT a AND b可能意味着两件事


问题改写后:


-- I want to get (0) all records from area (1) which have deleted_at IS NULL (1a)
-- and (2) the ones that can have deleted_at is NOT NULL but are present as a FK in the registration.

SELECT * FROM area a
WHERE a.deleted_at IS NULL -- (1)
   OR a.deleted_at IS NOT NULL AND EXISTS (                (1a)  
        SELECT *                -- (2)
        FROM registration r 
        WHERE r.area_id=a.id
        );

如果我的理解正确,您的意思是(1a)处的:如果是这样,则(1a)中的转换为

答案 3 :(得分:0)

您只是在搜索以下查询吗?

SELECT * FROM Area
LEFT OUTER JOIN registration on id = area_id
WHERE deleted_at IS NULL OR area_id IS NOT NULL

如果area.id不是唯一的,这将多次返回相同的registration.area_id(因为您没有UNIQUE约束)。
如果存在问题,则可能需要以下查询。

SELECT * FROM Area
WHERE deleted_at IS NULL OR id IN (SELECT area_id FROM registration)

或者使用COUNT来构建:

SELECT id, deleted_at, COUNT(*) FROM Area
LEFT OUTER JOIN registration on id = area_id
WHERE (deleted_at IS NULL or area_id IS NOT NULL)
GROUP BY id, deleted_at