C#SQL在FIFO中减去产品数量

时间:2017-10-01 10:03:48

标签: c# sql sql-server

我只是想知道如何用不同的日期到期减去相同产品的数量。

实施例

广告资源

Product | Qty | Expiration |
--------+-----+------------+
Oreo    | 2   | 10/18/2017 |
Oreo    | 6   | 10/09/2017 |

我已请求Inventory的{​​{1}}表格,数量为7.那7个奥利奥请求 必须减去首先到期,这是10/09/2017。我的请求剩下1个奥利奥将被减去到下一个到期时间,即10/18/2017所以表格将是这样的

Oreo

3 个答案:

答案 0 :(得分:0)

假设:

  1. 您正在使用MySQL数据库。
  2. 使用MySQL Connector / .Net。
  3. 假设您的表中有主ID Id |产品|数量|到期|
    --- + ---------- + ----- + ------------ +
    1 |奥利奥| 1 | 10/18/2017 |
    2 |奥利奥| 0 | 10/09/2017 |
  4. 这是我编写的一个函数,用于演示您需要的逻辑:

    // Function to get all the product listing for a given product name in ascending order
    public void UpdateProductListing(string myConnString, String productName, Int productQty)  
    {
    
        MySqlConnection myConnection = new MySqlConnection(myConnString);
        MySqlCommand myCommand = (MySqlCommand)myConnection.CreateCommand();
        // Warning : never use String query, instead use parametrized query by calling myCommand.Parameters.AddWithValue
        myCommand.CommandText = "SELECT Id, Product, Qty, Expiration FROM YourDb.YourTable ORDER BY Expiration ASC";
        myConnection.Open();
    
        // The reader enables us to acces each row by calling it's read method
        MySqlDataReader myReader = myCommand.ExecuteReader();
        try 
        {
                // QtyRemaining variable will hold how much of the quatity is to be taken from next row.
                Int QtyRemaining = productQty;
    
                // Always call Read before accessing data.
                while (myReader.Read()) 
                {                    
                    if (myReader.GetInt16(2) >= productQty)
                    {
                        Int NewQty = myReader.GetInt16(2) - productQty;
                        // At this moment i'm not sure if you need to close the reader before Inserting.
                        // Anyways you'll require to arrange this code in a proper order to suite your situation
                        MySqlCommand InsertCommand = (MySqlCommand) myConnection.CreateCommand();
    
                        // Warning : never use String query, instead use parametrized query by calling myCommand.Parameters.AddWithValue
                        InsertCommand.CommandText = "Insert INTO YourDb.YourTable (Qty) VALUES (" + NewQty.toString()  + ") WHERE Id=" + myReader.GetInt16(0).toString();
                        InsertCommand.ExecuteNonQuery();
                        break;
                    }
                    else
                    {
                        // Now we know that this particular row cannot supply the entire qty, so we'll set it to zero and move to next row for remaining qty
                        MySqlCommand InsertCommand = (MySqlCommand) myConnection.CreateCommand();
    
                        // Warning : never use String query, instead use parametrized query by calling myCommand.Parameters.AddWithValue
                        InsertCommand.CommandText = "Insert INTO YourDb.YourTable (Qty) VALUES (" + 0.toString()  + ") WHERE Id=" + myReader.GetInt16(0).toString();
                        InsertCommand.ExecuteNonQuery();
    
                        // the quantity to be captured from next row
                        QtyRemaining =  productQty - myReader.GetInt16(2);
                    }                    
                }
        }
        finally 
        {
                // always call Close when done reading.
                myReader.Close();
    
                // Close the connection when done with it.
                myConnection.Close();
        }
    }
    

    注意:
    1.如果您尝试直接编译,此代码可能会出现几个错误。请将其视为逻辑的参考 2.始终使用Paramterized SQL查询。对于.Net MySQL连接器,请参阅:https://dev.mysql.com/doc/connector-net/en/connector-net-tutorials-parameters.html
    3.您可能需要关闭Reader才能执行查询 4.最好创建一个Product类,然后在那里编写这个逻辑。

    希望这会有所帮助。如需进一步查询,请提供您正在尝试的更多详细信息。如果您正在使用.Net桌面应用程序或Web应用程序。如果您使用的是.Net或.Net Core。

答案 1 :(得分:0)

MSSQL版本看起来像这样(再次,很多假设,因为我们无法看到你的表结构实际上是什么样的):

private void SubtractInventory(string product, int qty)
{
    string connectionString = "connection sting goes here";
    try
    {
        using (SqlConnection cn = new SqlConnection(connectionString))
        {
            string sql = $"select ID, PRODUCT, QTY, EXPIRES from PRODUCTS order by EXPIRES asc";

            using (SqlDataAdapter adapter = new SqlDataAdapter(sql, cn))
            {
                using (DataTable tempTable = new DataTable())
                {
                    adapter.Fill(tempTable);
                    if (tempTable.Rows.Count == 0) throw new Exception("No such product.");

                    foreach (DataRow r in tempTable.Rows)
                    {
                        int newQty = (int)r["QTY"] - qty;
                        if (newQty >= 0)
                        {
                            r["QTY"] = newQty;
                            qty = 0;
                            break;
                        }
                        else
                        {
                            qty = qty - (int)r["QTY"];
                            r["QTY"] = 0;
                        }
                    }

                    if (qty > 0) throw new Exception($"Not enough of {product} in inventory to subtract {qty}.");

                    using (SqlCommandBuilder cb = new SqlCommandBuilder(adapter))
                    {
                        adapter.UpdateCommand = cb.GetUpdateCommand();
                        adapter.Update(tempTable);
                    }
                }
            }
        }
    }
    catch (Exception ex)
    {
        // log ex.Message somehow..
    }

答案 2 :(得分:0)

您可以使用此查询进行计算。

;WITH CTE AS (
    SELECT  *,
        CumulativeSum= SUM(Qty) OVER (PARTITION BY Product ORDER BY Expiration  ROWS UNBOUNDED PRECEDING) 
    FROM Inventory
)
SELECT Product,  
    Qty = CASE 
            WHEN (CumulativeSum - @request) < 0 THEN 0
            WHEN (CumulativeSum - @request) BETWEEN 0 AND Qty THEN (CumulativeSum - @request)
            ELSE Qty 
           END 
    , Expiration
FROM CTE
ORDER BY Product, Expiration

更新表脚本:

;WITH CTE AS (
    SELECT  *,
        CumulativeSum= SUM(Qty) OVER (PARTITION BY Product ORDER BY Expiration  ROWS UNBOUNDED PRECEDING) 
    FROM Inventory
)
UPDATE 
    CTE
SET
    Qty = CASE 
            WHEN (CumulativeSum - @request) < 0 THEN 0
            WHEN (CumulativeSum - @request) BETWEEN 0 AND Qty THEN (CumulativeSum - @request)
            ELSE Qty 
           END 
FROM CTE
WHERE CumulativeSum <= Qty + @request