从选择子查询中获取多列

Spa*_*tus 35 subquery

SELECT 
   *, 
   p.name AS name, 
   p.image, 
   p.price,
   ( 
       SELECT ps.price 
       FROM product_special ps 
       WHERE p.id = ps.id
         AND ps.date < NOW() 
       ORDER BY ps.priority ASC, LIMIT 1
   ) AS special_price,
   ( 
       SELECT ps.date 
       FROM product_special ps 
       WHERE p.id = ps.id
         AND ps.date < NOW() 
       ORDER BY ps.priority ASC, LIMIT 1
   ) AS date
FROM product p LEFT JOIN product_special ps ON (p.id = ps.id)
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,我重复相同的子查询只是为了得到另一列。我想知道有没有更好的方法来做到这一点?

id是两个表中的主键。如果有帮助,我可以让product_special.priority变得独一无二。

a1e*_*x07 15

假设组合product_special.id, product_special.priority是唯一的

 SELECT p.*, special_price,special_date
 FROM product p
 LEFT JOIN 
 (
     SELECT ps.id, ps.price as special_price, ps.`date` as special_date
     FROM product_special ps
     INNER JOIN 
     (
       SELECT id, MIN(priority) as min_priority 
       FROM product_special
       GROUP BY id
     ) ps2 
     ON (ps2.id = ps.id)
 )a ON (a.id=p.id)
Run Code Online (Sandbox Code Playgroud)


小智 10

受到 dezso 的回答https://dba.stackexchange.com/a/222471/127433的启发 ,我正在使用数组解决 PostgreSQL 中的问题,如下所示:

SELECT 
   *, 
   p.name AS name, 
   p.image, 
   p.price,
   ( 
       SELECT ARRAY[ps.price, ps.date]
       FROM product_special ps 
       WHERE p.id = ps.id
         AND ps.date < NOW() 
       ORDER BY ps.priority ASC, LIMIT 1
   ) AS special_price_and_date
FROM product p LEFT JOIN product_special ps ON (p.id = ps.id)
Run Code Online (Sandbox Code Playgroud)

诚然,它仍然只是一列,但在我的代码中,我可以轻松访问这两个值。希望它也适合你。


mpa*_*pag 8

除非您打算将字段作为 special_price.price 和 date.date 返回,为什么不在子查询中使用别名?例如

SELECT p.*, p.name AS  name, p.image, p.price, ps.*
FROM product p
LEFT JOIN
   (SELECT
      psi.price as special_price, psi.date as my_date 
    FROM product_special psi
    WHERE 
      p.id = psi.id AND
      psi.date < NOW()
    ORDER BY psi.priority ASC, LIMIT 1
   ) AS ps ON
  p.id = ps.id
Run Code Online (Sandbox Code Playgroud)

您的查询语言是否具有 FIRST() 聚合函数?不确定是否可以使 product_special 的 PK 成为 id 和优先级(均为 ASC 排序)之间的组合并将 ORDER 子句更改为GROUP BY id, psi.priority

您可能能够完全删除 ORDER BY 子句并使用 HAVING MIN(psi.priority)


小智 5

请注意,SQL Server 中的“交叉应用”机制可以解决此问题,但在 PostgreSQL 中不可用。基本上,他们的解决方案是如何将参数(通常是对当前表表达式外部的列的引用)传递给 FROM 子句中称为表表达式的函数。但事实证明,它对于您想要避免另一级子查询嵌套或将内容从 FROM 子句移动到 SELECT 子句的各种情况都很有用。PostgreSQL 通过创建一种异常来实现这一点——如果表达式是一个简单的函数调用但严格来说不是一个嵌入式 SELECT,那么您可以传递这样的参数。所以

left join highestPriorityProductSpecial(p.id) on true

可以,但不行

left join (select * from product_special ps where ps.id = p.id order by priority desc limit 1) on true

即使函数的定义正是如此。

所以,这实际上是一个方便的解决方案(至少在 9.1 中):创建一个函数,通过在函数内部执行 limit 来提取最高优先级的行。

但函数有一个缺点,即查询计划不会显示它们内部发生的情况,我相信它总是会选择嵌套循环连接,即使这可能不是最好的。

  • 从 9.3(2013 年发布)开始,Postgres 中提供了“cross apply”功能,但他们选择遵守 SQL 标准并使用标准的“later”运算符。在第二个查询中,将“left join”替换为“left join Lateral” (8认同)

小智 5

尝试以下 SQL 命令:

SELECT p.name,p.image,p.price,pss.price,pss.date
FROM Product p OUTER APPLY(SELECT TOP(1)* 
FROM ProductSpecial ps
WHERE p.Id = ps.Id ORDER BY ps.priority )as pss
Run Code Online (Sandbox Code Playgroud)

  • 您可以在您的答案中添加更多信息吗 (2认同)