我有一个完全按照这篇文章中描述的 SQL 查询。总而言之,它将读取所有指定偏移量的 Carboard。此查询在 MariaDB 数据库上执行。
现在,我的 C# ASP.NET 程序中有我的 Cardboard(ID、Cardboard_number、DateTime、Production_LineNumber)。我必须阅读使用每个纸板的所有生产流程(基本上是 Production.start <= cardboard.datetime <= production.end).
Oracle 数据库中的 Productions 表如下所示(我自己没有创建该表,并且我无法更改任何内容,因为它也在生产程序中使用):
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纸板位于生产开始和结束之间,并且生产与扫描纸板位于同一行。
请注意,相同的生产可能会出现多次,但时间戳不同(例如生产已暂停)。
如果您有两个表:都在 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 |