【问题标题】:Query SQL - Rank employees / Columns with null values查询 SQL - 对具有空值的员工/列进行排名
【发布时间】:2015-04-23 20:11:49
【问题描述】:

我需要修复以下 SQL 查询:

SELECT  sep.name AS company_name,
    atnp.name AS employee_name,
    (Case WHEN ip.id_item = 0001 THEN 'Product A'  
        ELSE 'Product B'
        END ) AS product_name,
    (Case WHEN ivcp.id_item = 0001 THEN SUM(ivcp.quantity) 
        ELSE NULL
        END ) AS quantityA,
    (Case WHEN ivcp.id_item = 0002 THEN SUM(ivcp.quantity) 
        ELSE NULL
        END ) AS quantityB
FROM    sale_item AS ivcp
    INNER JOIN stock AS mep ON (mep.id_stock = ivcp.id_stock)
    INNER JOIN sale AS vcp ON (vcp.id_sale = ivcp.id_sale)
    INNER JOIN terminal_sale AS mvtp ON (mvtp.id_terminal_sale = vcp.id_terminal_sale)
    INNER JOIN item AS ip ON (ivcp.id_item = ip.id_item)
    INNER JOIN item_category AS cip ON (ip.id_category_item = cip.id_category_item)
    LEFT OUTER JOIN employee AS atnp ON (atnp.id_employee = ivcp.id_employee)
    INNER JOIN sis_company AS sep ON (sep.id_company = mvtp.id_company)
WHERE   mvtp.id_company IN (1)
AND mvtp.date_sale BETWEEN :BeginDate AND  :EndDate
AND DATE(ivcp.date_sale) BETWEEN :BeginDate AND  :EndDate
AND DATE(vcp.data_rec) BETWEEN :BeginDate AND  :EndDate
AND mep.date_sale BETWEEN :BeginDate AND  :EndDate
AND (-1 = -1 OR ivcp.id_employee IN
           (SELECT id_employee FROM team_employee WHERE id_employee = -1))
AND ip.id_category_item = 100
AND ivcp.id_item IN (0002,0001)
AND (ivcp.cancel = 'N' AND vcp.cancel = 'N')
GROUP BY sep.name,
    atnp.name,
    ip.id_item,
    ivcp.id_item
ORDER BY sep.name

结果:

COMPANY   | EMPLOYEE   | PRODUCT NAME | QUANTITY A | QUANTITY B
Company A | Employee A | Product A    | 1.64       | NULL
Company A | Employee A | Product B    | NULL       | 4.70
Company A | Employee B | Product A    | 84.191     | NULL
Company A | Employee B | Product B    | NULL       | 91.885

但我想要这个:

COMPANY   | EMPLOYEE   | QUANTITY A | QUANTITY B
Company A | Employee A | 1.64       | 4.70
Company A | Employee B | 84.191     | 91.885
  • 此查询目标是将某些员工的销售额排序到畅销书排名中。排名将按“产品 A”和“产品 B”销售额排序(ivcp.quantity、id_item = 0001 和 id_item = 0002)。

  • 内连接用于匹配销售日期、商品类别、员工 ID、库存等。

我正在使用基于 Stimulsoft 的程序来设计报告布局,但我不太习惯。因此,如果可以在查询中解决问题,那就太好了!

【问题讨论】:

  • -1 是否在实际查询中应该作为参数的地方弹出 3?或者它是你认为的常数?另外,始终,请提供您的 Postgres 版本。
  • -1 用于报告表单中的可选字段。如果客户端没有为此字段选择任何选项,则查询将显示所有结果。当您说这只是噪音时,您是对的,任何问题都可以将其删除。谢谢。 Edit: Postgres 版本:9.3

标签: sql postgresql aggregate aggregate-filter


【解决方案1】:

这基本上是您的查询的简化。在此过程中,我还修复了其他一些问题:

SELECT sc.name AS company_name
     , em.name AS employee_name
     , SUM((CASE WHEN si.id_item = 0001 THEN si.quantity END) AS quantity_a
     , SUM((CASE WHEN si.id_item = 0002 THEN si.quantity END) AS quantity_b
FROM   team_employee  te
JOIN   sale_item      si USING (id_employee)
JOIN   stock          st ON st.id_stock = si.id_stock
JOIN   sale           sa ON sa.id_sale = si.id_sale
JOIN   terminal_sale  ts ON ts.id_terminal_sale = sa.id_terminal_sale
JOIN   sis_company    sc ON sc.id_company = ts.id_company
JOIN   item           ip ON ip.id_item = si.id_item
JOIN   item_category  ic ON ic.id_category_item = ip.id_category_item
LEFT   JOIN employee  em ON em.id_employee = si.id_employee
WHERE  te.id_employee = -1
AND    st.date_sale BETWEEN :BeginDate AND :EndDate
AND    ts.date_sale BETWEEN :BeginDate AND :EndDate
AND    si.date_sale >= :BeginDate      -- inlude lower border
AND    si.date_sale <  (:EndDate + 1)  -- exclude upper border
AND    sa.data_rec  >= :BeginDate
AND    sa.data_rec  <  (:EndDate + 1)
AND    ts.id_company = 1
AND    ip.id_category_item = 100
AND    si.id_item IN (0002,0001)
AND    si.cancel = 'N'
AND    sa.cancel = 'N'
GROUP  BY 1, 2
ORDER  BY 3 DESC NULLS LAST
        , 4 DESC NULLS LAST;
  • 至于您的问题:使用类似演示的方法恢复方法:CASE 语句的总和,而不是相反。并相应地调整GROUP BY 和ORDER BY。
    在 Postgres 9.4 中,您将使用聚合 FILTER:

  • -1 = -1 OR ... 只是噪音。我删除了它。

  • 奇怪:

    AND   (ivcp.id_employee IN 
      (SELECT id_employee FROM team_employee WHERE id_employee = -1))
    

    假设-1 应该是一个参数。无论哪种方式,我都将其重写为另一个联接。

  • 为什么ip.id_item = 0001 中的前导零?如果是数字,则删除零。如果是字符串,请添加单引号以使其成为字符串文字而不是数字文字。

  • id_company IN (1) 只是说id_company = 1 的一种复杂方式。

  • 为什么选择演员DATE(si.date_sale)?顾名思义,它已经是date。要么名称具有误导性,要么表达方式具有误导性。无论哪种方式,这都不利于性能,因为表达式不是sargable。
    假设它是timestamp,我将其重写为可搜索。 sa.data_rec 也是如此。 还假设:EndDate 是date,所以我们可以添加一个integer::EndDate + 1

  • si.cancel = 'N' 和 sa.cancel = 'N' 看起来像应该真正实现为 boolean 的列。

  • 我根据你的描述改编了ORDER BY:

    排名将按“产品 A”和“产品 B”的销售额排序

    除非您将其设为DESC NULLS LAST,否则 NULL 值会按降序排列:

【讨论】:

  • 您的查询有效,而不是 100%。我不得不同时更改 'SUM((CASE WHEN si.id_item = 0001....',因为结果是递归的 'si.quantity' 总和具有不真实的值(太大)。这里的提示提高了我的知识,谢谢寻求帮助。
  • @GuilhermeCosta:这里没有“递归”。可能不是正确的术语? numeric 对于 any 数字来说足够大了...
  • 对不起,我的意思是总和是累积的,最后一个员工的 'si.quantity' 值超过其实际值的 1000%。但在这种情况下,很少有更改效果很好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-27
  • 1970-01-01
  • 1970-01-01
  • 2020-06-07
  • 2013-07-03
相关资源
最近更新 更多