【问题标题】:SQL sum 2 different column by different condtion then subtraction and addSQL通过不同的条件对2个不同的列求和,而不是减法和加法
【发布时间】:2013-11-06 17:31:03
【问题描述】:

我正在尝试的东西有点复杂,我会尽力解释。

我完成了第一部分,即按小时对列求和。

示例

ID         TIMESTAMP          CUSTAFFECTED
1     10-01-2013 01:00:23       23
2     10-01-2013 03:00:23       55
3     10-01-2013 05:00:23       2369
4     10-01-2013 04:00:23       12
5     10-01-2013 01:00:23       1
6     10-01-2013 12:00:23       99
7     10-01-2013 01:00:23       22
8     10-01-2013 02:00:23       3

输出将是

      Hour          TotalCALLS   CUSTAFFECTED
  10/1/2013 01:00       3         46        
  10/1/2013 02:00       1         3
  10/1/2013 03:00       1         55
  10/1/2013 04:00       1         12
  10/1/2013 05:00       1         2369
  10/1/2013 12:00       1         99

查询

    SELECT   TRUNC(STARTDATETIME, 'HH24') AS hour, 
           COUNT(*) AS TotalCalls,
           sum(CUSTAFFECTED) AS CUSTAFFECTED
    FROM     some_table
    where STARTDATETIME >= To_Date('09-12-2013 00:00:00','MM-DD-YYYY HH24:MI:SS') and
          STARTDATETIME <= To_Date('09-13-2013 00:00:00','MM-DD-YYYY HH24:MI:SS') and
GROUP BY TRUNC(STARTDATETIME, 'HH')

我需要什么 我需要的总和 2 个查询并按时间戳/小时分组。第二个查询与第一个查询完全相同,只是 where 子句不同。

第二次查询

SELECT   TRUNC(RESTOREDDATETIME , 'HH24') AS hour, 
     COUNT(*) AS TotalCalls, 
     SUM(CUSTAFFECTED) AS CUSTRESTORED
FROM     some_table
where RESTOREDDATETIME >= To_Date('09-12-2013 00:00:00','MM-DD-YYYY HH24:MI:SS') and
      RESTOREDDATETIME <= To_Date('09-13-2013 00:00:00','MM-DD-YYYY HH24:MI:SS') 
GROUP BY TRUNC(RESTOREDDATETIME , 'HH24')

所以我需要减去 custaffected - custrestoed,然后显示总数。

我添加了指向 excel 文件的链接。 http://goo.gl/ioo9hg

谢谢

【问题讨论】:

  • 请包含some_table的完整sql查询和表架构。
  • 感谢您指出。我更新了。
  • @CharlesBretana 什么是表架构,示例数据?
  • 表模式,是列名和数据类型的列表。另外,不应该在第一个查询引用STARTDATETIME 和第二个查询RESTOREDDATETIME 中首先输出列??

标签: sql oracle oracle11g timestamp where-clause


【解决方案1】:

好的,现在正确的 sql 是有问题的文本,试试这个:

SELECT TRUNC(STARTDATETIME, 'HH24') AS hour,        
   COUNT(*) AS TotalCalls, 
   Sum(case when RESTOREDDATETIME is null Then 0 else 1 end) RestoredCount,
   Sum(CUSTAFFECTED) as CUSTAFFECTED,
   Sum(case when RESTOREDDATETIME is null Then 0 else CUSTAFFECTED end) CustRestored,
   SUM(CUSTAFFECTED) - 
    Sum(case when RESTOREDDATETIME is null Then 0 else CUSTAFFECTED end) AS CUSTNotRestored
FROM     some_table
where STARTDATETIME >= To_Date('09-12-2013 00:00:00','MM-DD-YYYY HH24:MI:SS') 
   and STARTDATETIME <= To_Date('09-13-2013 00:00:00','MM-DD-YYYY HH24:MI:SS') 
GROUP BY TRUNC(STARTDATETIME, 'HH24')

【讨论】:

  • 你是如何得到 custrestored 的?,你必须在 where 子句中使用 RESTOREDDATETIME 来查找给定小时的恢复,然后从开始减去恢复。
【解决方案2】:

我最近需要这样做,并且不得不使用它来让它工作。

挑战是让一个查询的结果链接到同一查询中的另一个查询,然后操作字段的返回值,以便在一个查询的结果集中给定字段中的值,称为 FieldA,从不同结果集中的字段中的值中减去,称为 FieldB。主题值是否是 COUNT(...) 等聚合函数的结果并不重要;它们可以是结果集中是否需要分组的任何数字字段。查看聚合函数中的值仅意味着您需要调整查询逻辑以将 GROUP BY 用于正确的字段。该方法需要在查询中创建内嵌视图,并使用这些视图作为数据源进行减法。

在处理这种事情时,一个红鲱鱼是 MINUS 运算符(假设您使用的是 Oracle 数据库),但这不起作用,因为 MINUS 不是将结果集的字段值中的值相互减去,而是减去一个从查询返回的最终结果集中在另一组记录中找到的匹配记录集。此外,MINUS 不是 SQL 标准运算符,因此如果您使用的不是 Oracle,您的数据库可能不支持它。尽管如此,在您需要时拥有它还是非常棒的。

好的,前奏足够了。这是您要使用的查询表单,例如我们希望按 YYYY-MM 分组的日期范围:

select inlineview1.year_mon, (inlineview1.CNT - inlineview2.CNT) as finalcnt from
 (SELECT TO_CHAR(*date_field*, 'YYYY-MM') AS year_mon, count(*any_field_name*) as CNT
  FROM *schemaname.tablename*
   WHERE *date_field* > TO_DATE('*{a year}-{a month}-{a day}*', 'YYYY-MM-DD') and
    *date_field* < TO_DATE('*{a year}-{a month}-{a day}*', 'YYYY-MM-DD') and 
    *another_field* = *{value_of_some_kind}* -- ... etc. ...
  GROUP BY TO_CHAR(*date_field*, 'YYYY-MM')) inlineview1,
 (SELECT TO_CHAR(*date_field*, 'YYYY-MM') AS year_mon, count(*any_field_name*) as CNT
  FROM *schemaname.tablename* 
   WHERE *date_field* > TO_DATE('*{a year}-{a month}-{a day}*', 'YYYY-MM-DD') and
     *date_field* < TO_DATE('*{a year}-{a month}-{a day}*', 'YYYY-MM-DD') and
     *another_field* = *{value_of_some_kind}* -- ... etc. ...
  GROUP BY TO_CHAR(*date_field*, 'YYYY-MM')) inlineview2
WHERE
inlineview1.year_mon = inlineview2.year_mon
order by *either or any of the final resultset's fields* -- optional

稍微不那么抽象,举个例子,书商希望查看 2013 年任何给定月份售出的净书籍数量。为此,卖家必须从售出的数量中减去退回退款的书籍数量.他不在乎这本书什么时候被卖掉,因为他觉得退回的书在统计上代表着销售和收入的损失,无论它发生在什么时候和什么时候售出。示例:

select bookssold.year_mon, (bookssold.CNT - booksreturned.CNT) as netsalescount from
 (SELECT TO_CHAR(SALE_DATE, 'YYYY-MM') AS year_mon, count(TITLE) as CNT
  FROM RETAILOPS.ACTIVITY
   WHERE SALE_DATE > TO_DATE('2012-12-31', 'YYYY-MM-DD') and
    SALE_DATE < TO_DATE('2014-01-01', 'YYYY-MM-DD') and 
    OPERATION = 'sale'
  GROUP BY TO_CHAR(SALE_DATE, 'YYYY-MM')) bookssold,
 (SELECT TO_CHAR(SALE_DATE, 'YYYY-MM') AS year_mon, count(TITLE) as CNT
  FROM RETAILOPS.ACTIVITY
   WHERE SALE_DATE > TO_DATE('2012-12-31', 'YYYY-MM-DD') and
    SALE_DATE < TO_DATE('2014-01-01', 'YYYY-MM-DD') and 
    OPERATION = 'return'
  GROUP BY TO_CHAR(SALE_DATE, 'YYYY-MM')) booksreturned
WHERE
bookssold.year_mon = booksreturned.year_mon
order by bookssold.year_mon desc

请注意,为确保查询按预期返回,两个内联视图必须根据某些条件等值连接,如上所示,如下所示:

bookssold.year_mon = booksreturned.year_mon

或者计数记录的减法不能在 1:1 的基础上进行,因为查询解析器将不知道要从哪个记录中减去带有分组计数值的返回记录。未能指定等值连接条件将产生笛卡尔连接结果,可能不是您想要的(尽管您可能会想要那个)。例如,在上例中顶级 select 语句的返回字段列表中,在 'bookssold.year_mon' 之后添加 'booksreturned.year_mon' 并消除

bookssold.year_mon = booksreturned.year_mon

其 WHERE 子句中的条件将生成一个工作查询,该查询对结果集前两列中 YYYY-MM 值的 CNT 值进行减法计算,并将它们显示在第三列中。如果您需要,很容易知道这一点,因为如果您不仅可以在给定的原子时间范围内比较销售和回报,而且可以以 1:N 的方式在此类时间范围内进行比较,那么它在业务趋势分析中具有可靠的应用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-19
    • 2022-01-12
    • 2017-08-18
    相关资源
    最近更新 更多