迭代 C# 列表并在数据库中为每个元素执行 SELECT 语句 - 更有效的方法?

问题描述 投票:0回答:1

我有一个完全按照这篇文章中描述的 SQL 查询。总而言之,它将读取所有指定偏移量的 Carboard。此查询在 MariaDB 数据库上执行。
现在,我的 C# ASP.NET 程序中有我的 Cardboard(ID、Cardboard_number、DateTime、Production_LineNumber)。我必须阅读使用每个纸板的所有生产流程(基本上是 Production.start <= cardboard.datetime <= production.end).

Oracle 数据库中的 Productions 表如下所示(我自己没有创建该表,并且我无法更改任何内容,因为它也在生产程序中使用):

  • 生产数量(数量)
  • POSNR(数字)
  • 日期时间(时间戳(6))
  • PROCESS_ACTIVE(VARCHAR2(1))
  • 生产线(数量)

PROCESS_ACTIVE 列像一个标志一样使用,当启动生产过程时,将插入一行,其中 DATETIME=sysdate,PROCESS_ACTIVE = 1,停止的行用 sysdate,PROCESS_ACTIVE = 0 指示。

我创建了一个总结我的流程的查询,因此我得到每个 Production_NUMBER 和 POSNR 的开始和结束:

SELECT * 
FROM
(
    SELECT PRODUCTION_NUMBER, POSNR, PROCESS_ACTIVE, PRODUCTION_LINE, DATETIME as START, LEAD(DATETIME, 1, SYSDATE) OVER (ORDER BY DATETIME ASC) AS END
    FROM ssq_lauftr
    GROUP BY PRODUCTION_NUMBER, POSNR, PROCESS_ACTIVE, PRODUCTION_LINE, DATETIME
    ORDER BY DATETIME 
)
WHERE PROCESS_ACTIVE = 1

我在我的 C# 代码中迭代从 MariaDB 检索到的所有 Cardboard,并对每个 Cardboard 执行此查询(其中 cardboard 是从我的 C# 循环中注入的对象):

SELECT * 
FROM
(
    SELECT PRODUCTION_NUMBER, POSNR, PROCESS_ACTIVE, PRODUCTION_LINE, DATETIME as START, LEAD(DATETIME, 1, SYSDATE) OVER (ORDER BY DATETIME ASC) AS END
    FROM ssq_lauftr
    WHERE PRODUCTION_LINE = cardboard.PRODUCTION_LINENUMBER and DATETIME <= cardboard.DATETIME
    GROUP BY PRODUCTION_NUMBER, POSNR, PROCESS_ACTIVE, PRODUCTION_LINE, DATETIME
    ORDER BY DATETIME 
)
WHERE PROCESS_ACTIVE = 1 AND cardboard.DATETIME <= END

在纸板数量较少的情况下效果很好。

这个解决方案的问题是,如果我有很多纸板,读取所有作品的整个功能将花费太长时间。有没有办法(例如使用 PLSQL)使这个过程更加高效?上面的 SQL 语句相当快,但是在 C# 中迭代列表并将结果添加到我的 ProductionSet 会大大减慢应用程序的速度。

编辑:
纸板存储在 MariaDB 中,而产品则存储在 Oracle DB 中。 我当前用于所描述功能的 C# 代码如下所示:

Cardboards = [.. _mariaDB.Cardboards.FromSql($@"
    SET @cb_num = {request.Cardboard_Number};
    select *
    from (
        SELECT *,
        sum(Cardboard_Number LIKE CONCAT(@cb_num, '%')) over (
            partition by ProductionLine_Number
            order by timestamp, id
            rows BETWEEN {CardboardOffset} preceding AND {CardboardOffset} following
        ) matches
        from cardboards
    ) cardboards_with_matches
    where matches
")];

HashSet<Production> productionSet = [];

for(int i = 0; i < Cardboards.Count(); i++)
{
    productionSet.UnionWith(_oracleDB.Production.FromSqlRaw($@"
        SELECT * 
        FROM
        (
            SELECT PRODUCTION_NUMBER, POSNR, PROCESS_ACTIVE, PRODUCTION_LINE, DATETIME as START, LEAD(DATETIME, 1, SYSDATE) OVER (ORDER BY DATETIME ASC) AS END
            FROM Productions
            WHERE PRODUCTION_LINE = {Cardboards.ElementAt(i).ProductionLine_Number} and {Cardboards.ElementAt(i).DateTime} <= cardboard.DATETIME
            GROUP BY PRODUCTION_NUMBER, POSNR, PROCESS_ACTIVE, PRODUCTION_LINE, DATETIME
            ORDER BY DATETIME 
        )
        WHERE PROCESS_ACTIVE = 1 AND {Cardboards.ElementAt(i).DateTime} <= END
    "));
}

MariaDB fiddle - 适用于 Cardboards 的 Fiddle
OracleDB fiddle - Fiddle for Productions(不是在 fiddle 中运行,而是在 Oracle SQL Developer 中运行,老实说我不知道那里的问题)

分解来说,基本上当用户搜索 Cardboard“WDL-005943998-1”时,预期输出将是整个 Cardboard 的数据(在 MariaDB 中搜索)和 Production_NUMBER = 461618 的生产,作为 DateTime纸板位于生产开始和结束之间,并且生产与扫描纸板位于同一行。

请注意,相同的生产可能会出现多次,但时间戳不同(例如生产已暂停)。

c# sql oracle
1个回答
0
投票

如果您有两个表:都在 Oracle 数据库中;或者从 Oracle 数据库访问 MariaDB 数据库(即通过数据库链接),然后您可以使用查询找到两个表之间的所有关系:

WITH production_bounds (production_number, posnr, process_active, production_line, start_dt, end_dt) AS (
  SELECT PRODUCTION_NUMBER,
         POSNR,
         PROCESS_ACTIVE,
         PRODUCTION_LINE,
         DATETIME as start_dt,
         LEAD(DATETIME, 1, SYSTIMESTAMP) OVER (
           PARTITION BY production_line
           ORDER BY DATETIME ASC
         ) AS end_dt
  FROM   productions
)
SELECT p.production_number,
       p.posnr,
       p.process_active,
       p.production_line,
       p.start_dt,
       p.end_dt,
       c.id,
       c.cardboard_number
FROM   production_bounds p
       INNER JOIN cardboard c
       ON     p.production_line = c.productionline_number
          AND c.date_time BETWEEN p.start_dt AND p.end_dt

对于示例数据(Oracle 中的两个表):

CREATE TABLE cardboard
(
    id int,
    Cardboard_Number varchar2(100),
    date_Time TIMESTAMP(0),
    ProductionLine_Number int
);

INSERT INTO cardboard VALUES 
(2,'WDL-005943998-1', TIMESTAMP '2014-08-05 10:03:32', 1),
(4,'spL1ml82N4o',TIMESTAMP '2024-02-29 17:13:54', 1),
(5,'WDL-005943998-1',TIMESTAMP '2024-03-01 09:44:42', 1),
(6,'WDL-005943998-1',TIMESTAMP '2024-03-01 10:34:57', 1),
(7,'950024027237',TIMESTAMP '2024-03-01 10:44:57', 1),
(8,'950024027237',TIMESTAMP '2024-03-01 10:52:57', 1),
(9,'WDL-005943998-1',TIMESTAMP '2024-03-01 13:58:43', 2),
(10,'WDL-005943998-1',TIMESTAMP '2024-03-01 13:58:46', 2),
(11,'spL1ml82N4o',TIMESTAMP '2024-03-01 14:09:43', 2),
(12,'WDL-005943998-1',TIMESTAMP '2024-03-12 15:48:36', 2);

CREATE TABLE Productions
(   
  PRODUCTION_NUMBER NUMBER, 
  POSNR NUMBER, 
  DATETIME  TIMESTAMP(0), 
  PROCESS_ACTIVE VARCHAR2(1),
  PRODUCTION_LINE NUMBER
);

BEGIN
INSERT INTO Productions(PRODUCTION_NUMBER, POSNR, DATETIME, PROCESS_ACTIVE, PRODUCTION_LINE)
  VALUES (461793, 1, TO_TIMESTAMP('2014-08-04 09:01:41', 'YYYY-MM-DD HH24:MI:SS'), '1', 1);
INSERT INTO Productions(PRODUCTION_NUMBER, POSNR, DATETIME, PROCESS_ACTIVE, PRODUCTION_LINE)
  VALUES (461793, 1, TO_TIMESTAMP('2014-08-04 11:01:41', 'YYYY-MM-DD HH24:MI:SS'), '0', 1);
INSERT INTO Productions(PRODUCTION_NUMBER, POSNR, DATETIME, PROCESS_ACTIVE, PRODUCTION_LINE)
  VALUES (461618, 2, TO_TIMESTAMP('2014-08-05 10:01:41', 'YYYY-MM-DD HH24:MI:SS'), '1', 1);
INSERT INTO Productions(PRODUCTION_NUMBER, POSNR, DATETIME, PROCESS_ACTIVE, PRODUCTION_LINE)
  VALUES (461619, 2, TO_TIMESTAMP('2014-08-05 10:02:46', 'YYYY-MM-DD HH24:MI:SS'), '1', 2);
INSERT INTO Productions(PRODUCTION_NUMBER, POSNR, DATETIME, PROCESS_ACTIVE, PRODUCTION_LINE)
  VALUES (461618, 2, TO_TIMESTAMP('2014-08-05 10:05:09', 'YYYY-MM-DD HH24:MI:SS'), '0', 1);
INSERT INTO Productions(PRODUCTION_NUMBER, POSNR, DATETIME, PROCESS_ACTIVE, PRODUCTION_LINE)
  VALUES (461619, 2, TO_TIMESTAMP('2014-08-05 10:07:46', 'YYYY-MM-DD HH24:MI:SS'), '0', 2);
INSERT INTO Productions(PRODUCTION_NUMBER, POSNR, DATETIME, PROCESS_ACTIVE, PRODUCTION_LINE)
  VALUES (461818, 1, TO_TIMESTAMP('2014-08-14 22:53:12', 'YYYY-MM-DD HH24:MI:SS'), '1', 1);
INSERT INTO Productions(PRODUCTION_NUMBER, POSNR, DATETIME, PROCESS_ACTIVE, PRODUCTION_LINE)
  VALUES (461818, 1, TO_TIMESTAMP('2014-08-14 23:25:30', 'YYYY-MM-DD HH24:MI:SS'), '0', 1);
END;
/

输出:

生产数量 POSNR 进程_活动 生产线 START_DT END_DT 身份证 CARDBOARD_NUMBER
461618 2 1 1 2014-08-05 10:01:41. 2014-08-05 10:05:09.000000 2 WDL-005943998-1
461818 1 0 1 2014-08-14 23:25:30. 2024-03-28 12:53:28.569815 4 spL1ml82N4o
461818 1 0 1 2014-08-14 23:25:30. 2024-03-28 12:53:28.569815 5 WDL-005943998-1
461818 1 0 1 2014-08-14 23:25:30. 2024-03-28 12:53:28.569815 6 WDL-005943998-1
461818 1 0 1 2014-08-14 23:25:30. 2024-03-28 12:53:28.569815 7 950024027237
461818 1 0 1 2014-08-14 23:25:30. 2024-03-28 12:53:28.569815 8 950024027237
461619 2 0 2 2014-08-05 10:07:46. 2024-03-28 12:53:28.569815 9 WDL-005943998-1
461619 2 0 2 2014-08-05 10:07:46. 2024-03-28 12:53:28.569815 10 WDL-005943998-1
461619 2 0 2 2014-08-05 10:07:46. 2024-03-28 12:53:28.569815 11 spL1ml82N4o
461619 2 0 2 2014-08-05 10:07:46. 2024-03-28 12:53:28.569815 12 WDL-005943998-1

如果您想搜索具有特定

cardboard_number
的活动行,请添加这些过滤器:

WITH production_bounds (production_number, posnr, process_active, production_line, start_dt, end_dt) AS (
  SELECT PRODUCTION_NUMBER,
         POSNR,
         PROCESS_ACTIVE,
         PRODUCTION_LINE,
         DATETIME as start_dt,
         LEAD(DATETIME, 1, SYSTIMESTAMP) OVER (
           PARTITION BY production_line
           ORDER BY DATETIME ASC
         ) AS end_dt
  FROM   productions
)
SELECT p.production_number,
       p.posnr,
       p.process_active,
       p.production_line,
       p.start_dt,
       p.end_dt,
       c.id,
       c.cardboard_number
FROM   production_bounds p
       INNER JOIN cardboard c
       ON     p.production_line = c.productionline_number
          AND c.date_time BETWEEN p.start_dt AND p.end_dt
WHERE  cardboard_number = 'WDL-005943998-1'
AND    process_active = 1

输出:

生产数量 POSNR 进程_活动 生产线 START_DT END_DT 身份证 CARDBOARD_NUMBER
461618 2 1 1 2014-08-05 10:01:41. 2014-08-05 10:05:09.000000 2 WDL-005943998-1

小提琴

© www.soinside.com 2019 - 2024. All rights reserved.