简体   繁体   中英

Postgresql left join issue

I have two tables

create table sources (
    user_id bigint,
    source varchar,
    created timestamp default now(),
    unique(user_id, source)
)
create table subscriptions (
    user_id bigint unique primary key,
    plan int not null references plans(id),
    starts timestamp default now(),
    ends timestamp default now() + interval '30' day
)

I try to select everything from sources when user has active subscription, I use this query

SELECT src.* FROM sources AS src LEFT JOIN subscriptions as sub ON sub.user_id=src.user_id WHERE now() < sub.ends

However, it does not return all data, the problem became clear when I tried

SELECT * FROM sources AS src LEFT JOIN subscriptions as sub ON sub.user_id=src.user_id

What may be the problem and how itspossible for me to get this info in the other way? PS subscriptions table has rows with other user_id's. Thank you very much! 第二个 sql 查询的输出

UPDATE

Your left join is working. If your image is of SELECT * FROM sources AS src LEFT JOIN subscriptions as sub ON sub.user_id=src.user_id then some of your users have no subscriptions.

SELECT * FROM sources AS src LEFT JOIN subscriptions ... only ensures every matching row in sources will be fetched regardless of whether it has a matching row in subscriptions .


[I wrote the rest when I thought it was a different problem, but the advice remains.]

This is possible because sources.user_id is not set up as a foreign key so the database cannot enforce referential integrity . As far as the database is concerned, sources.user_id is just some number. If you delete a user, their sources and subscriptions will hang around.

In general...

  • Clever primary keys just bring complications. Give everything more complicated than a simple join table id bigserial primary key and be done with it.
  • Declare everything not null unless you have a good reason it should be null.
  • Use on delete cascade to clean up when a user is deleted, but see below.
create table sources (
    id bigserial primary key,

    -- When a user is deleted, its sources will also be deleted
    user_id bigint not null references users(id) on delete cascade,

    source varchar not null,
    created timestamp not null default now(),

    unique(user_id, source)
)

create table subscriptions (
    id bigserial primary key,

    -- When a user is deleted, its subscriptions will also be deleted
    user_id bigint not null unique references foreign key users(id) on delete cascade,

    -- Make foreign key names consistent, and use a consistent type for ids.
    plan_id bigint not null references plans(id) on delete cascade,

    starts timestamp not null default now(),
    ends timestamp not null default now() + interval '30' day
)

Whether to use on delete cascade when a deleted user still has sources and subscriptions depends on how you want to handle that situation. You might want to prevent deleting a user which still has active sources and subs, in which case leave off on delete cascade and handle cleaning up the user's sources and subs manually.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM