【问题标题】:Querying sales, grouped by weeks查询销售额,按周分组
【发布时间】:2017-11-04 12:12:46
【问题描述】:

我正在尝试在 SQLLite 中为我的应用程序组合一个查询,并希望得到一些帮助。

我要写的查询:

“我是用户 ID x 的用户。对于我的个人工作周,可以从我想要的任何一天 D(周日到周六、周一到周日等)开始,我想看看哪个工作周就销售而言,这是我最差的,也是我最好的。

为了简单起见,“最差”和“最好”仅表示该周最高和最低销售额的总和。

如果每个人的工作周从星期日开始,这很容易,但事实并非如此。我必须克服一个 SQL 挑战,即不仅按周分组数据库表中的所有行,还按自定义周分组(用户定义一周的开始和结束日期)。

例如,如果我的工作周从星期日开始,那么过去一周,5 月 28 日这一周是星期日,是我工作周的开始(并在 6 月 3 日星期六结束)。对于表中的所有记录,我都会遵循这种模式。

但是,其他用户的工作周可能从 5 月 29 日星期一开始,到 6 月 2 日星期五结束。

所以这意味着对于用户 1,我想将他的行从周日的开始日到周六的结束日进行分组(然后将它们全部汇总,并获取第一条和最后一条记录进行销售)。

但是,对于用户 2,我想将他的记录分组在星期一到星期日的日期范围内

这是我目前所处的位置。我想我很接近了。

(请注意,我将日期存储为以毫秒为单位的 unix 时间戳,因此除以 1000 和 unixepoch 部分)。 +d 部分实际上是基于一天开始的整数,但我还没有弄清楚这个数字应该是什么。就在我认为我得到它的时候,它却在别人的日子里失败了。

SELECT 'Date', SUM(Amount) 'Amount'  
FROM Sales WHERE UserID = x
GROUP BY CAST(( julianday((datetime(CreationDate / 1000, 'unixepoch', 'localtime')) + d) / 7 ) AS INT) 

有人认为他们可以帮助我吗? :)

非常感谢!

编辑

非常感谢您的帮助!

对于 +d 的问题(值 'd' 应该偏移什么)? 这是我在测试后发现的,据我所知这是有效的。我了解 Sqllite 使用 0 作为星期日,使用 1 作为星期一等,并且我知道我们正在分组并除以 7(一周中的 7 天),但是知道为什么这些将是 'd' 作为偏移量的正确值?它现在似乎正在工作。我看到模式是 2,1,0,6,5,4,3,但是进入的顺序有点奇怪吧?

if (day == Sunday) //if your work week starts on Sunday, d=2
     return 2
else if (day == Monday)
     return 1
else if (day == Tuesday)
     return 0
else if (day == Wednesday) 
     return 6
else if (day == Thursday) 
     return 5
else if (day == Friday) 
     return 4
else if (day == Saturday) 
     return 3

【问题讨论】:

  • 请提供minimal reproducible example,即适当定制玩具数据库的.dump
  • 2,1,0,6,5,4,3 并不奇怪。我们将数字 0 到 6 添加到儒略日数。当我们添加 0 时,我们显然是从星期二开始的。因此,当我们再添加一个时,我们从前一天开始,即星期一。这种情况一直持续到从周三开始增加六个。把数字 2,1,0,6,5,4,3 写成一个圆圈,你会发现它们都是连续的。顺便说一句,如果我们添加 7,我们将再次从星期二开始,因此我们可以将 7(或 14 或 21 或 -7 等)添加到这些数字中的任何一个。所以我们也可以添加数字 9,8,7,6,5,4,3 或减去 5,6,7,8,9,10,11。

标签: sql sqlite fmdb


【解决方案1】:

请尝试执行以下查询:

select 
  min(to_char(to_date(order_date,'mm/dd/yyyy'),'Day'))
    keep(dense_rank first order by sum(sales) desc) best_day,
  min(to_char(to_date(order_date,'mm/dd/yyyy'),'Day'))
    keep(dense_rank last order by sum(sales) desc)worst_day
from orders
where userid=x
group by to_char(to_date(order_date,'mm/dd/yyyy'),'Day');

【讨论】:

  • 哇,谢谢。唯一的事情是我越来越接近“(”:语法错误:所以它没有运行。你的括号似乎与我匹配。我在列的命名后放置了空格,甚至放置了你的 'worst_day' 和 'best_day'用引号引起来,但它仍然会抛出该语法错误。知道 ( ? 附近可能发生什么错误
  • 'keep' 是否可能不是有效的 SQLLITE 语句?
  • 这是一个 Oracle 查询。它在 SQLite 中不起作用。并且它不会在 Oracle 中,因为这个问题是在这里进行的几天而不是几周。
  • 我可以知道为什么它不能在 oracle 中运行,因为它在 oracle 中运行
  • 你按天分组。这怎么会导致每周的总和? (除此之外,是什么让您认为日期存储为格式为“mm/dd/yyyy”的字符串?)
【解决方案2】:

你很亲密。

  1. 您正在将d 添加到日期时间。我不知道这是否真的增加了天数。如果您将整数添加到 SQLite 中的日期时间,我不知道会发生什么。要保存它,请将日期添加到朱利安日。您不必先获取日期时间,顺便说一下,从儒略日开始,您可以一步完成:

    julianday(CreationDate / 1000, 'unixepoch', 'localtime') + d
    

    这是我在您的查询中看到的唯一真正的缺陷。

  2. 儒略日是一个小数,例如 2457907.5。当您调用带有/ 的除法时,您会得到一个小数结果。我看到您将此结果转换为INT,但我建议先转换为 INT,然后再进行除法,这会隐式地使其成为整数除法。

    cast(julianday(CreationDate / 1000, 'unixepoch', 'localtime') + d as int) / 7

    这只是为了便于阅读;我得到一个天数(2457907 而不是一些十进制的 2457907.5)和整数除以 7(例如 2457907 / 7 = 351129)。

整个查询:

SELECT 
  MIN(DATE(CreationDate / 1000, 'unixepoch', 'localtime')) AS from_date, 
  MAX(DATE(CreationDate / 1000, 'unixepoch', 'localtime')) AS till_date, 
  SUM(Amount) AS total
FROM Sales 
WHERE UserID = x
GROUP BY CAST(JULIANDAY(CreationDate / 1000, 'unixepoch', 'localtime') + d as INT) / 7
ORDER BY SUM(Amount);

from_datetill_date 并不总是代表完整的 7 天,而是仅代表工作日(例如,在从星期日到星期六的一周内,但仅在星期一、星期三和星期五工作,它会显示日期周一和周五)。显示真实的一周需要更多的工作。 (我现在最好不要尝试这个,因为当无法尝试查询时很容易休息一天。)

编辑:这是我在一周的开始和结束日期的尝试。当我们在一个浮点值上调用DATE 时,这个值被认为是儒略日。 (也许它也适用于整数,我无法从文档中确定。)

SELECT 
  DATE(CAST(CAST(JULIANDAY(CreationDate / 1000, 'unixepoch', 'localtime') + d as INT) / 7 as REAL)) AS from_date,
  DATE(CAST(CAST(JULIANDAY(CreationDate / 1000, 'unixepoch', 'localtime') + d as INT) / 7 as REAL), '+6 day') AS till_date,
  MIN(DATE(CreationDate / 1000, 'unixepoch', 'localtime')) AS first_working_day, 
  MAX(DATE(CreationDate / 1000, 'unixepoch', 'localtime')) AS last_working_day, 
  SUM(Amount) AS total
FROM Sales 
WHERE UserID = x
GROUP BY CAST(JULIANDAY(CreationDate / 1000, 'unixepoch', 'localtime') + d as INT) / 7
ORDER BY SUM(Amount);

【讨论】:

  • 感谢您抽出宝贵时间查看此内容!在我运行这个的开发数据库中,一个特定的用户在周日 5 月 28 日开始他的一天,并在周六 6 月 2 日(今天)结束。那一周他只工作了3天。当我运行上述查询时,它似乎按照您所说的进行,并考虑了工作日而不是整周。我使用 +d 部分(+0、+1、..、+7),它确实显示了不同的结果,但没有正确聚合。我会继续玩这个,但感谢您的支持!如果您有任何其他建议并且不介意,我很乐意从您那里获得更多帮助。谢谢楼主!
  • 应该是对的。在此查询中考虑了整周(仅未显示真正的一周开始和结束;您必须以某种方式通过公式从您的组中计算它们)。您可以编辑您的问题并在您认为一个或多个结果行不正确的地方显示结果(仅大约五行)。
  • 我添加了一个查询,希望能正确说明周的开始和结束。
  • 我已经更新了 ORDER BY 子句,因此您首先会在结果中看到最差的一周和最好的一周。如果您想将结果限制为仅这两行,您可能必须将UNION ALL 与查询一起使用两次,一次使用ORDER BY SUM(Amount) LIMIT 1,一次使用ORDER BY SUM(Amount) DESC LIMIT 1
  • Thorsten 非常感谢您的帮助。在我编辑的问题中,我有一个小问题。如果你能解释为什么它会以这种方式工作,那么为了完整起见,那就太棒了:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-21
  • 1970-01-01
  • 2010-09-06
  • 2016-02-06
  • 1970-01-01
相关资源
最近更新 更多