【问题标题】:How do I select null if no rows match in PostgreSQL?如果 PostgreSQL 中没有匹配的行,我如何选择 null?
【发布时间】:2021-10-21 22:58:39
【问题描述】:

我有以下疑问:

SELECT c.customer_id
FROM order o
JOIN customer c USING (customer_id)
WHERE c.time >= '2021-01-01 10:00:00' AND c.time < '2021-01-01 11:00:00'
    AND (0 IN (22) OR o.product_id IN (22))
LIMIT 1

只要至少有一个匹配,就会返回一行,如果没有匹配,则不会有任何行。

如果没有匹配,是否可以返回一行空值?

【问题讨论】:

  • 提示:Left JoinLeft join
  • @Georgy 我试过了,它不返回null,它返回一个空行..

标签: sql postgresql null row


【解决方案1】:

所以你必须表CustomersOrders,并且客户和订单之间存在一对多的关系:每个客户都有零个或多个订单,每个订单只属于一个客户,即客户CustomerId 所指的外键。

每个客户都有一个属性时间。 (您确定 Time 是 Customer 的属性,而不是 Order 的属性吗?)。您有两个 DateTime 值:timeStart 和 timeEnd,并且对于在 timeStart 和 timeEnd 之间具有属性时间值的每个客户,您想要他的订单之一,不管是哪一个,如果此客户没有任何订单,则为 null订单。

步步为营:

DateTime timeStart = ...              // = '2021-01-01 10:00:00'
DateTime timeEnd = ...                // = '2021-01-01 11:00:00'

IQueryable<Order> allOrders = ...
IQueryable<Customer> allCUstomers = ...
IQueryable<Customer> customersWithinTimeRanges = allCustomers
    .Where(customer => timeStart <= customer.Time and customer.Time < timeEnd);

换句话说:从所有客户中,只保留属性时间值介于 timeStart 和 timeEnd 之间的客户(使用属性

现在从时间范围内的每个客户那里,您需要他的一个订单,如果客户没有任何订单,则为 null。

只要您有一对多关系,例如学校有零个或更多学生,城市有零个或更多居民,或者在您的情况下:客户有零个或多个订单,并且来自每个“一个”你想要零个或多个他的“许多”项目,考虑使用Queryable.GroupJoin的重载之一

我几乎总是需要带有参数resultSelector的重载

var customersWithAnOrder = customersWithinTimeRanges.GroupJoin(
    allOrders,

    customer => customer.Id,        // from every Customer take the primary key
    order => order.CustomerId,      // from every Order take the foreign key

    // parameter resultSelector: from every Customer with his zero or more Orders
    // make one new object:
    (customer, ordersOfThisCustomer) => new
    {
         // select the Customer properties that you plan to use:
         Id = customer.Id,
         Name = customer.Name,
         ...

         Order = ordersOfThisCustomer.Select(order => new
         {
             // select the Order properties that you plan to use
             Id = order.Id,
             Date = order.Date,
             ...

             // not needed, you already got the value in property Id:
             // CustomerId = order.CustomerId
          })
          // you don't need all Orders of this Customer, you only want one,
          // don't care which one or null if this Customer doesn't have any Orders
          .FirstOrDefault(),
    });

如果您没有对序列进行排序,有时数据库不允许您执行FirstOrDefault。在这种情况下,在 FirstOrDefault 之前排序:

Order = ordersOfOfThisCustomer.Select(order => new {...})
        .OrderBy(order => order.Date) // or whatever you want to sort on
        .FirstOrDefault(),

【讨论】:

    【解决方案2】:

    最简单的解决方案是检查“左连接”表行

    select 
        case when c.customer_id is null then null else o.customer_id end 
    from order as o 
      left join customer_cte as c using (customer_id)
    

    【讨论】:

      【解决方案3】:

      一个解决方案是LEFT JOIN,但从客户表开始。但是,它有点复杂:

      SELECT o.customer_id
      FROM customer c LEFT JOIN
           order o
           ON c.customer_id = o.customer_id AND
              o.time >= '2021-01-01 10:00:00' AND
              o.time < '2021-01-01 11:00:00'
      LIMIT 1;
      

      请注意,这是从 orders 表返回 customer_id。如果没有匹配,那就是NULL

      以上假设您至少有一个客户,这似乎是一个合理的假设。

      另一种选择是UNION ALL

      WITH c as (
            SELECT customer_id
            FROM customer c JOIN
                 order o
                 USING (customer_id) 
            WHERE o.time >= '2021-01-01 10:00:00' AND
                  o.time < '2021-01-01 11:00:00'
            LIMIT 1
           )
      SELECT c.customer_id
      FROM c
      UNION ALL
      SELECT NULL
      WHERE NOT EXISTS (SELECT 1 FROM c);
      

      第三种选择可能更简单,子查询:

      select (select o.customer_id
              from order o
              where o.time >= '2021-01-01 10:00:00' AND
                    o.time < '2021-01-01 11:00:00'
              limit 1
             ) as customer_id;
      

      如果子查询没有返回任何行,则结果为NULL

      【讨论】:

      • 第一个不返回null,它只是返回一个空行。我对查询进行了一些编辑,请参阅帖子。
      • @Ben empty 技术上可以认为是null 检查column is null,它会返回true
      • @SagarPanchal 问题是这个select是在jdbc queryForObject中使用的,它不认为空行是null...
      • @Ben 如果查询没有返回任何行,那么它可能会抛出空数据集异常,但是您是否检查了空行的结果?
      • @Ben。 . .问题是:“如果没有匹配,是否可以返回一行具有空值?”此答案中的所有查询都是这样做的。如果您有不同的问题,那么也许您应该提出一个新问题。
      猜你喜欢
      • 1970-01-01
      • 2016-07-03
      • 2021-02-11
      • 2011-04-20
      • 1970-01-01
      • 2015-08-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多