【问题标题】:How to return "0" sales for a kind of subtexture from a left join of results that is null如何从为空的结果的左连接中返回一种子纹理的“0”销售额
【发布时间】:2013-11-24 21:35:29
【问题描述】:

DBMS:德比

语言:Java

外部查询从内部查询中获取结果 它在特定日期内获得一种潜伏的销售额 但有时某种商品没有订单详情 潜台词。所以没有什么可加入的,我想看到一个“0” 对于这种情况。抱歉命名和缩进不好。 谢谢 杰克

SELECT s1.TextureName AS TYPE,
       T.month AS MONTH,
       NULLIF(sum(S.Sales),0) AS NS,
       NULLIF(T.Total,0) AS total,
       NULLIF(NULLIF(cast(S.Sales AS Float),0.0) / NULLIF(Cast(T.Total AS float),0.0) * 100.0,0.0) AS percent
FROM subtexture s1
LEFT JOIN
  (SELECT s.SubTextureID,
          sum(od.NetSales) AS Sales,
          MONTH(o.PURCHASEDATETIME) AS MONTH
   FROM subtexture s
   LEFT JOIN products p ON (s.SubTextureID = p.SubTextureID)
   LEFT JOIN order_details od ON (p.ProductCode = od.ProductCode)
   LEFT JOIN orders o ON (od.OrderCode = o.OrderCode)
   WHERE TRIM(CAST(CAST(YEAR(o.PurchaseDateTime) AS CHAR(4)) AS VARCHAR(4))) || '-' || TRIM(CAST(CAST(MONTH(o.PurchaseDateTime) AS CHAR(2)) AS VARCHAR(2))) = '2013-11'
   GROUP BY s.SubTextureID,
            MONTH(o.PurchaseDateTime)) AS S ON (S.SubTextureID = s1.SubTextureID) ,
  (SELECT sum(od.NetSales) AS Total,
          MONTH(o.PurchaseDateTime) AS MONTH
   FROM orders o
   LEFT JOIN order_details od ON (o.OrderCode = od.OrderCode)
   WHERE TRIM(CAST(CAST(YEAR(o.PurchaseDateTime) AS CHAR(4)) AS VARCHAR(4))) || '-' ||TRIM(CAST(CAST(MONTH(o.PurchaseDateTime) AS CHAR(2)) AS VARCHAR(2))) = '2013-11'
   GROUP BY MONTH(o.PURCHASEDATETIME)) AS T
WHERE T.MONTH = S.MONTH
GROUP BY s1.TextureName,
         T.Total,
         T.MONTH,
         S.Sales

【问题讨论】:

  • 简化您的问题并仅发布查询的相关部分。想一个更简单的例子来说明你的问题。
  • 你为什么使用Java标签?我在问题中看不到任何与 Java 相关的部分。
  • 对不起,我会尝试取消 Java 标记
  • 好的。我正要写一个答案,但你的 SQL 要复杂得多,然后我首先想到了。你能再解释一下,SQL 做了什么,为什么你加入order 两次和subtexture 两次?以及您尝试使用nullif 实现的目标。我认为错误在nullif应该是coalsesce,但我也相信你在SQL中也有其他问题。
  • 当我在这里的时候 :-) 说一个子纹理总是有一个产品是对的吗(不需要外连接)?产品不总是有订单(需要外连接)?一个订单总是至少有一个 order_detail(不需要外连接)?

标签: sql derby


【解决方案1】:

我认为代码存在一些问题。不幸的是我没有表格和测试数据。所以请记住,我或多或少地写下了结果。仔细测试。

为了便于阅读,我将代码分为两个步骤。第一步获取销售额总和,第二步计算所有纹理的总销售额并建立百分比。对于您的测试,将第一个代码复制两次到第二个代码中,替换两次出现的SALES_ONE_TEXTURE。我只是不想过多地淹没答案。

这是一个纹理(以及月份和年份)的销售额总和的第一部分

-- Use this as subselect. And you're right: you need it twice
(   select  s.TextureName, s.SubTextureId, o.year, o.month, sum(COALESCE(d.NetSales, 0)) NetSales
    from    (select SubTextureId, TextureName from subtexture) as s
    join
            (select SubTextureId, ProductCode from products) as p
        on  (p.SubTextureId = s.SubTextureId)
    left outer join
            (select ProductCode, OrderCode, NetSales from order_details) as d
        on  (d.ProductCode = p.ProductCode)
    join
            (   select  YEAR(o.PurchaseDateTime) year,
                        MONTH(o.PurchaseDateTime) month,
                        OrderCode
                from    orders
                where   o.PurchaseDateTime between '2013-11-01 00:00:00' and '2013-11-30 23:59:59' -- make use of an index if one exists
            ) as o
        on  (o.orderCode = d.orderCode)
    group by 1,2,3,4
)   as SALES_ONE_TEXTURE;

这里是把数字放在一起的外部代码:

-- The outer query
select  O.TextureName,
        A.year, A.month,
        A.NetSales, O.NetSales,
        cast(O.NetSales as float) / cast(A.NetSales as float) * 100.0 as percent
from    SALES_ONE_TEXTURE O -- replace here
join
        (   select  year, month, sum(NetSales) as NetSales
            from    SALES_ONE_TEXTURE -- replace here
            group by 1, 2 
        ) as SALES_ALL_TEXTURES A
    on  (A.year = O.year and A.month = O.month)

备注

  • COALESCE 返回第一个非空值,常用于将空值替换为默认值。 NULLIF 则相反:将值替换为 null。
  • 替换来自外部连接的空值不适用于所有 RDBMS 上的所有方言。你必须尝试它是否在这里工作。如果没有,则需要将整个查询放在子选择中,并在外部选择中替换 coalesce
  • 我总是年复一年地过去,你过去的月份。每年重复一个月,所以只有组合是独一无二的。我也改变了获取月份的方式。如果存在索引,我的方法可以使用索引。

【讨论】:

  • 谢谢jboi,这里是深夜。我明天需要测试这些,我相信你,你们都是这里的专家。让我明天回来报告。玩得开心。
  • 我已按照您的提示进行操作,但有一件事是我不能有一个销售数量为零的子纹理来显示。假设 SubTexture A 的销售额为 1000,类型 b 有 2000,类型 c 有 0,类型 c 从来没有出现过
  • 这是我不确定的事情之一。如果 subtexture 有产品但没有订单(因此没有 order_details),您可能需要使用外部连接来连接订单:因此,请尝试在第一部分替换 join,就在 ordery 与 left outer join 连接之前。
【解决方案2】:
NULLIF(sum(S.Sales),0) AS NS,
...
NULLIF(NULLIF(cast(S.Sales AS Float),0.0) / NULLIF(Cast(T.Total AS float),0.0) * 100.0,0.0) AS percent

这永远行不通。稍微简化一下,你正在这样做:

SELECT sum(S.Sales),
       S.Sales

您如何设想将销售额的总和和单个销售额放在一个相同的返回记录中?由于您按销售额分组,因此 SUM(Sales) 在任何时候都等于销售额,这使我相信您可能正在尝试完成查询中未反映的事情。

【讨论】:

  • 对不起,你是对的,我不是故意在第一个中包含 sum(S.Sales)。感谢您指出这一点
猜你喜欢
  • 2016-05-06
  • 1970-01-01
  • 2020-09-06
  • 2016-02-06
  • 1970-01-01
  • 2012-07-08
  • 2021-09-21
  • 1970-01-01
  • 2014-01-27
相关资源
最近更新 更多