我正在尝试创建一个查询以检索当前价格和特价[strong]如果正在进行销售;当没有销售时,我希望store_picture_monthly_price_special.price AS special_price以空的价格返回。
在添加第二个 WHERE 条件之前,查询将按照我的期望执行: store_picture_monthly_price_special.price 返回 null ,因为没有销售目前。
store_picture_monthly_reference | tenure | name | regular_price | special_price
3 | 12 | 12 Months | 299.99 | {Null}
2 | 3 | 3 Months | 79.99 | {Null}
1 | 1 | 1 Month | 29.99 | {Null}
pgSQL将第二个 WHERE 条件视为“全部或全部”。如果没有销售,将没有结果。
是否可以调整此查询,以便每次运行时都能获得正常定价,并且特价运行时以美元价值获得特价或返回空,这是我要执行的操作完成需要子查询吗?
这是我目前的查询方式:
SELECT store_picture_monthly.reference AS store_picture_monthly_reference , store_picture_monthly.tenure , store_picture_monthly.name , store_picture_monthly_price_regular.price AS regular_price , store_picture_monthly_price_special.price AS special_price
FROM ( store_picture_monthly INNER JOIN store_picture_monthly_price_regular ON store_picture_monthly_price_regular.store_picture_monthly_reference = store_picture_monthly.reference )
FULL OUTER JOIN store_picture_monthly_price_special ON store_picture_monthly.reference = store_picture_monthly_price_special.store_picture_monthly_reference
WHERE
( store_picture_monthly_price_regular.effective_date < NOW() )
AND
( NOW() BETWEEN store_picture_monthly_price_special.begin_date AND store_picture_monthly_price_special.end_date )
GROUP BY store_picture_monthly.reference , store_picture_monthly_price_regular.price , store_picture_monthly_price_regular.effective_date , store_picture_monthly_price_special.price
ORDER BY store_picture_monthly_price_regular.effective_date DESC
表“ store_picture_monthly ”
reference bigint,
name text,
description text,
tenure bigint,
available_date timestamp with time zone,
available_membership_reference bigint
表 store_picture_monthly_price_regular
reference bigint ,
store_picture_monthly_reference bigint,
effective_date timestamp with time zone,
price numeric(10,2),
membership_reference bigint
表 store_picture_monthly_price_special
reference bigint,
store_picture_monthly_reference bigint,
begin_date timestamp with time zone,
end_date timestamp with time zone,
price numeric(10,2),
created_date timestamp with time zone DEFAULT now(),
membership_reference bigint
答案 0 :(得分:1)
每当您在外部联接的表上放置一个位置谓词时,它都会将外部联接转换为内部联接,因为外部联接引入的空值永远无法与任何产生真值的事物进行比较(因此,外部联接将负载为null的行放在行不匹配的地方,然后WHERE再次取出整行)
考虑以下简单示例:
SELECT * FROM
a LEFT JOIN b ON a.id = b.id
WHERE b.col = 'value'
等同于:
SELECT * FROM
a INNER JOIN b ON a.id = b.id
WHERE b.col = 'value'
要解决此问题,请将谓词移出位置并移至ON
SELECT * FROM
a LEFT JOIN b ON a.id = b.id AND b.col = 'value'
您还可以考虑:
SELECT * FROM
a LEFT JOIN b ON a.id = b.id
WHERE b.col = 'value' OR b.col IS NULL
但是,如果b.col自然包含一些空值,这可能会获取您不想要的数据;它无法区分b.col中本机存在的null和联接失败中引入的null,以将b中的行与a中的行匹配(除非我们还查看联接的id列的空)。 / p>
A
id
1
2
3
B
id, col
1, value
3, null
--wrong, behaves like inner
A left join B ON a.id=b.id WHERE b.col = 'value'
1, 1, value
--maybe wrong, b.id 3 might be unwanted
A left join B ON a.id=b.id WHERE b.col = 'value' or b.col is null
1, 1, value
2, null, null
3, 3, null
--maybe right, simpler to maintain than the above
A left join B ON a.id=b.id AND b.col = 'value'
1, 1, value
2, null, null
3, null, null
在这最后两个中,区别在于b.id是否为null,尽管行数相同。如果我们在计算b.id,我们的计数可能最终会错误。重要的是要了解联接行为的这种细微差别。如果您想通过制作a LEFT JOIN b ON a.id=b.id WHERE b.col = 'value' OR b.id IS NULL
的where子句来排除第3行但包括第2行,则可能甚至想要它-这将保留第2行但排除第3行,因为即使联接成功找到了b .id为3,两个谓词均不保留
答案 1 :(得分:1)
该问题的描述表明您想要LEFT JOIN
,而不是FULL JOIN
。 FULL JOIN
很少见,特别是在具有明确定义的外键关系的数据库中。
在您的情况下,WHERE
子句始终将您的FULL JOIN
变成LEFT JOIN
,因为WHERE
子句需要第一个表中的有效值。
SELECT spm.reference AS store_picture_monthly_reference,
spm.tenure, spm.name,
spmpr.price AS regular_price,
spmps.price AS special_price
FROM store_picture_monthly spm INNER JOIN
store_picture_monthly_price_regularspmpr
ON spmpr.store_picture_monthly_reference = spm.reference LEFT JOIN
store_picture_monthly_price_special spmps
ON spm.reference = spmps.store_picture_monthly_reference AND
NOW() BETWEEN spmps.begin_date AND spmps.end_date
WHERE spmpr.effective_date < NOW();
注意:
ON
子句中。GROUP BY
。似乎没有必要。如果是这样,则可以改用SELECT DISTINCT
。而且,如果需要的话,我会调查数据问题。NOW()
具有时间成分。比较列的名称表明,这些只是没有时间的日期。