Python 有没有办法计算sqlite中现有产品的平均值?

Python 有没有办法计算sqlite中现有产品的平均值?,python,sqlite,Python,Sqlite,我正在尝试创建一个商店程序,我遇到了一个问题,我需要你的帮助来解决。程序将包含以下信息的行插入数据库的StoringTF表中: 公司的门店代码 根据代码显示的商店名称 入境日期 产品代码 产品名称 进货数量 单位购买价 总买价 出货量 单位售价 总售价 条目的描述 我希望单位售价自动设置为同一产品单位购买价格的平均值 我试过使用这个代码 c.execute("""WITH cte AS ( SELECT Product_Name, AVG(Unit_Buying_Price) AS Av

我正在尝试创建一个商店程序,我遇到了一个问题,我需要你的帮助来解决。程序将包含以下信息的行插入数据库的StoringTF表中:

公司的门店代码 根据代码显示的商店名称 入境日期 产品代码 产品名称 进货数量 单位购买价 总买价 出货量 单位售价 总售价 条目的描述 我希望单位售价自动设置为同一产品单位购买价格的平均值 我试过使用这个代码

c.execute("""WITH cte AS (
    SELECT Product_Name, AVG(Unit_Buying_Price) AS AveragePrice 
FROM StoringTF 
GROUP BY Product_Name
)
UPDATE StoringTF
SET Unit_Selling_Price = (
SELECT AveragePrice
FROM cte
WHERE Product_Name = StoringTF.Product_Name 
)""") 

但它有两件事做错了

它会更新表中相同产品的所有以前的值 但事实并非如此。 它计算不存在的产品的平均值,这些产品 商店的价格不对。 我希望输出是这样的

我希望它只为插入的行插入它,而不是 编辑上一行 第二,我希望它只对现有产品进行计算 例如: 如果我三个月前买了一台1000美元的显示器$ 然后我把它卖了,平均值是1000美元,这很好 然后今天我用2000美元买了同样的显示器。 我希望平均值是2000美元,而不是1500美元

这是表的模式,以使事情更清楚

c.execute("""
CREATE TABLE StoringTF (
Store_code INTEGER,
Store TEXT,
Product_Date TEXT,
Permission INTEGER,
Product_Code INTEGER,
Product_Name TEXT,
Incoming INTEGER,
Unit_Buying_Price INTEGER,
Total_Buying_Price INTEGER,
Outgoing INTEGER,
Unit_Sell_Price INTEGER,
Total_Sell_Price INTEGER,
Description TEXT)
        """)


它会更新表中同一产品的所有以前的值,但该值不正确。 必须准确指定要更新的记录。数据库没有以前值的自动概念,即使您有一个日期字段或有多行具有相同的产品名称。声明完全按照你告诉它的去做。。。根据Product_Name=StoringTF.Product_Name的位置更新与名称匹配的所有行。你为什么期望它做其他的事情

它计算不存在的产品的平均值,这会导致存储值错误。 这本质上与第一个问题完全相同:数据库将包含与您的条件匹配的所有行。你说只在产品名称上分组,所以它就是这么做的。再一次,不存在产品的自动概念。您必须在WHERE子句中添加一些内容和/或更新GROUP BY子句,以区分现有产品和非现有产品。您甚至没有为其他人提供足够的细节来确定这一事实,那么数据库如何知道排除不存在的产品呢

我希望它只为插入的行插入它,而不编辑以前的行 代码执行UPDATE语句。如果你想插入一个新行,那么你需要做的就是。。。执行INSERT语句。UPDATE语句更新现有行。INSERT语句插入新行

第二,我希望它只对现有产品进行计算 前两点的答案相同

我建议研究数据规范化。数据规范化的基本思想是避免冗余和重复信息。在关系数据库中,这是通过创建多个与主键和外键链接的表来实现的

例如,在一个表中,您仅使用不随时间变化的信息定义产品。。。类似于产品名称或产品代码,并为每行分配唯一的ProductID值。为每个存储定义一个单独的表,其中包含各种存储详细信息和唯一的主键StoreID值

在另一个表中,您存储买卖等交易。事务表将包括外键ProductID和StoreID列。实际上,在交易表中不存储产品或存储详细信息,只存储美元金额和其他交易详细信息。通过外键ID值检索有关产品和商店的所有详细信息。更好的方法是将销售和购买拆分成单独的表格,但这是一个更高级的步骤

更多的建议开始超出这一问题的范围,但是还有其他方法来规范事务数据,以便更容易获得最新的平均值和只选择当前的产品,等等

建议的部分解决方案 尽管我有更好的判断力,我还是发布了更多的细节,希望能对大家有所帮助。StackOverflow在发布长时间、完整的解决方案时,通常变得更加开放和可容忍

以下内容无论如何都不是完整的解决方案,但它包含一个示例模式和查询,可以作为完整解决方案的一部分使用。所有必要的细节问题都不清楚,但以下说明了某种程度的规范化。我当然不包括对现有数据的任何迁移查询,因为这些工作和细节应该由OP来处理

这仍然不能回答只选择现有产品的问题,因为这是您需要定义的 再进一步。我不知道只有现有产品意味着什么。你是说只有存货吗?从您的表架构中不清楚您是在每一行中存储全部项目,还是每一行都是一个事务

创建表存储 存储\u代码整数主键, 存储文本不为空且唯一 创建表格产品 产品代码整数主键, 产品名称文本不为空且唯一, 说明文字, 产品日期文本-这是交易日期吗? -不太清楚这些列的用途, -所以我不知道它们在规范化模式中的确切位置 -权限整数,-不确定这是做什么用的 -输入整数,-与采购数量相同? -输出整数,-与销售数量相同? 创建表销售 ID整数主键自动递增, 存储\u代码整数非空引用存储\u代码, 产品代码整数不为空引用产品产品代码, TransactionDate作为日期时间, 单位售价货币不为空, 数量整数不为空 创建表购买 ID整数主键自动递增, 存储\u代码整数非空引用存储\u代码, 产品代码整数不为空引用产品产品代码, TransactionDate作为日期时间, 单位买入价货币不为空, 数量整数不为空 下面的查询演示如何插入新购买的产品。此INSERT语句使用SQL参数语法指示它需要来自SQLite数据库外部的语言/环境的输入值。关于如何正确执行此类语句的详细信息(包括如何传递输入值)在此不作描述,应单独研究

插入销售门店代码、产品代码、交易日期、单价、数量 值@storecode、@productcode、@trandate、, 选择AVGUnit\u购买价格作为AveragePrice 从购买 其中Store_code=@storecode和Product_code=@productcode, @数量 请注意,总价不存储在Sales或Purchases交易表中,而是使用类似以下的查询动态计算总价

创建视图PurchaseDetails作为 选择*,采购单价*数量作为采购总价 从购买
只有在构建了一个规范化的模式,写下了我的另一个答案,并从OP得到了澄清的评论之后,我才最终意识到了原始问题的意图。我不为我的另一个答案道歉,因为很容易假设所有的问题都与非规范化表有关,并且误解了现有表的含义。关于更新与插入以及存储计算数据而不是使用规范化表上的查询等问题,也存在着混淆。最终我意识到现有的库存或现有产品的方法

最初的问题是只得到库存中尚未售出的商品的平均价格;或者换句话说,只获取最近购买的物品的平均价格

这并不是一个简单的查询,因为采购和销售可能以不同的数量发生,并且库存中可能存在分割单个采购交易的剩余项目。除了这个特殊的挑战之外,一个关键的想法是这必须通过多个子查询来完成。对于sqlite,我们可以使用基本上命名为子查询的公共表表达式CTE:

一组子查询获取总采购进货数量和总销售出库数量,其中的差异是库存量,即现有数量。 另一个查询必须计算一个运行总和,以确定之前所有库存都已售出的关键交易记录。此类临界值很可能不会精确地落在交易边界上,因此关键采购交易将分为一些已售出和一些库存数量。虽然可以使用经典的SQL构造获得运行和,但sqlite支持窗口函数,即我使用的OVER子句。 数学注:不能通过计算多个部分平均值的简单平均值来获得整个样本的平均值。相反,要么对部分平均值进行加权,要么对整个样本进行求和,直接计算平均值。这里最简单的方法是简单求和,即分别计算价格和数量,直接计算总平均值。这种方法避免了必须单独计算各个平均值的权重,并在查询之间传递它们

最后,在实际查询之前,我基于模式和数据的不确定性做出了一些假设。以下代码:

假设每个产品\ U日期有一个传入事务。如果这不是真的,那么表需要更多的信息—一个唯一的ID或时间戳—才能正确地执行 对事务进行排序和区分,以便 ple交易并非如此 选择作为确定现有产品(即库存产品)的关键点。 假设从任何特定产品日期/交易日期起,总出货量永远不会大于总进货量。如果根据实际数据,这是错误的,那么结果肯定是不准确的,并且可能返回虚假的金额。 以下内容旨在处理问题的原始模式。仅此查询仅提供所需的平均采购价格。如果要使用此选项插入以平均值作为单位销售价格的新收货/销售记录,则必须将此查询与另一个插入查询组合。有多种方法可以做到这一点,包括将其保存为sqlite视图,或者继续CTE链,以便在INSERT语句中引用。这个练习留给你做

以总和作为 -首先获取用于计算库存数量的数量总和 选择门店代码、产品代码、, 如果NullSumOutgoing为0,销售时为0,购买时为sumIncoming, sumIncoming-IfNullSumOuting,0为库存 来自斯托林茨 按门店代码、产品代码分组 , 运行 -获取最近购买的项目的运行总数 选择门店代码、产品代码、产品日期、进货、购买单价、, 在购买时,库存超过库存 来自斯托林茨 其中传入>0-仅限购买的行 窗口按门店代码、产品代码、订单、产品日期说明锁定为分区 按门店代码、产品代码、产品日期说明订购 , 英斯托克AS 选择r.门店代码、r.产品代码、, -第一种情况是纯库存而非出售的交易 -否则情况是针对部分售出商品的关键交易
我知道当r.被收购的时候不应该是这样的。这就是我的要求。怎么做是个问题,因为我在任何地方都找不到答案。我将提供上面的模式,请告诉我如果我想实现我期望的输出,应该怎么做,因为我真的无法自己找到解决方案。即使我在where子句中添加一行“`` where Incoming-outing>0```如果我买了新的显示器,它仍然会计算出以前1000美元的显示器的平均值。谢谢你把事情说清楚。我知道数据库没有足够的条件来满足我的要求。问题是我应该提供什么样的条件才能让它按照我解释的那样去做。@MohamedAmr重新阅读了我建议研究数据标准化的答案。这是一个很好的建议。我会的。我将来需要它,这是肯定的。但我现在真的需要答案。我很抱歉,我保证我会开始阅读,但我没有时间创建那个程序了。我确信有一种方法可以添加一个条件来实现这一点,但我真的想不出一种方法来实现这一点。如果你能提供一种方法,我将非常感激,我肯定会研究数据规范化,因为这不是第一次有人这样对我说。很难说一个人在什么级别需要帮助,但堆栈溢出主要是用于编程问题,因为一个人已经知道他们想要做什么。您的问题似乎是从编程开始之前就开始的基本概念问题开始的。这对于一个单堆栈溢出问题来说太宽泛了,部分答案是数学的,并且涉及正确的会计知识等。对不起,所有方面的完整答案都超出了我在这里提供的范围。非常感谢您的帮助。我真的很感激。我有个小问题。如果我有多个事务,那么我就用rowid或我添加到表中的任何唯一ID替换每个产品_日期,对吗?再次感谢您的帮助。是和否,因为问题再次没有包含足够的细节或数据示例,无法真正了解如何回答您的数据。Rowid可用于唯一标识行,因此在许多情况下这就足够了。但是我的查询已经考虑了不止一个事务,并且每个事务都有不同的日期。虽然rowid理论上随时间递增,但它仍然只是一个抽象的整数值。日期值是对交易进行排序的更好方法,特别是如果您想知道哪些价格值较旧,哪些价格值较新。如果您的意思是每个日期有多个交易,则需要同时使用Product_date和rowid对记录进行排序。需要更新查询以考虑到这一点。另一种方法是确保Product_Date字段还包含一个可能低至毫秒的时间,以确保可以使用单个字段对事务进行排序和识别。我认为第二种方法更好。按日期排序将使长期比较价格更加高效和容易。我 将Product_Date设置为datetime,以毫秒为单位,因为每天可能有多个事务。谢谢你的帮助。