T-SQL——关于XML类型_SQL解析XML
0.前提背景
0.1 背景
新接手一个MES,这个MES系统的整体架构是基于WPF,
其中这个架构中的接口或存储过程中的数据都是以XML格式进行传递的
所以经常出现传递一个XML类型的数据到存储过程中,然后在存储过程中进行解析
故整理一下关于SQL解析XML的方式,方便查阅
0.2 关于XML类型
-
关于XML的基本概念
- 元素:
<Student><Name>Tom</Name></Student>
,这里的Name就是元素 - 属性:
<Student Name="Tom"/>
,这里的Name就是属性 - 文本:
<Name>Tom</Name>
,这里的Tom就是文本 - 无论是采用元素还是属性的方式表达数据信息,最终表达的效果是一样的。但是,我们要注意:应该尽量避免使用属性。对于大多数情况,推荐将实体属性转为XML元素。这符合XML的最佳实践,提供了更好的可读性和可维护性
- 0.属性难以阅读和维护。请尽量使用元素来描述数据。而仅仅使用属性来提供与数据无关的信息
- 1.属性无法包含多重的值(元素可以)
- 2.属性值不能包含子节点(元素可以)
- 3.属性不易扩展(为未来的变化)
- 4.对比下面两种XML格式的区别:仅在属性较少且数据结构简单的情况下,使用属性可以提高XML的简洁性
- 元素:
-
推荐:
<Class Count=2> <ClassId>1<ClassId> <ClassName>1班</ClassName> <Student> <Id>1001</Id> <Name>Tom</Name > <Age>30</Age> </Student> <Student> <Id>1002</Id> <Name>Jerry</Name > <Age>30</Age> </Student> </Class>
-
不推荐
<Class Classid="1" ClassName="1班" Count="2"> <Student Id="1001" Name="Tom" Age="30" /> <Student Id="1002" Name="Jerry" Age="30" /> </Class>
-
数据库中为什么要使用XML类型?
- 1.如果数据结构明确,则关系模型最适合数据存储,若是数据结构是非结构化的或者是未知的,则可以保存为XML数据
- 2.将数据存储在 XML 列中还有其他好处, 包括让引擎确定数据格式是否正确或有效,以及支持对 XML 数据进行精细查询和更新。
- 3.存储数据的精确副本。 这对于特殊用途的应用(如法律文档)很有用。 大多数应用不需要完全相同的副本,且 XML 内容(InfoSet 保真度)即可满足需要
-
操作XML的方法:通过使用
nodes
和modify
方法,可以直接在XML数据上执行XPath
表达式进行读取、更新、插入和删除操作- 读取节点:使用
nodes()
方法和v
alue()` 方法。 - 更新节点:使用
modify()
方法的 replace value of 子句。 - 插入节点:使用
modify()
方法的 insert 子句。 - 删除节点:使用
modify()
方法的 delete 子句。
- 读取节点:使用
0.3 XPATH基础语法
-
说明:XPath 是一门在 XML 文档中查找信息的语言。XPath 可用来在 XML 文档中对元素和属性进行遍历。
-
XPath语法:参考XPath 语法
- XPATH是XQuery 的基础,其获取指定节点的语法很强大,这里不罗列了,详见上述参考连接
- 下面的示例,仅仅是如何获取节点和获取元素属性,其他的并没有使用太多的XPATH语法。
- 因为我的使用场景不太一样,我只是将XML类型当做存储过程的参数,并完整的解析为表值,所以并不涉及太多对XML的操作
- 其二,我看网上好多是都直接在XML中筛选查找指定的节点,我还是习惯将XML结构转为表值,在用SQL进行筛选操作
1.构造测试数据
- 定义实体类
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public List<string> Hobbies { get; set; }
public Address StudentAddress { get; set; }
public List<Course> ListCourse { get; set; }
}
//这里使用XmlAttribute将Address中的属性定义为XML中的属性
//示例开发中不建议这么做,这里只是为了演示
[XmlType("Address")]
public class Address
{
[XmlAttribute("Code")]
public int Code { get; set; }
[XmlAttribute("Region")]
public string Region { get; set; }
[XmlAttribute("City")]
public string City { get; set; }
[XmlAttribute("Province")]
public string Province { get; set; }
}
//这里使用XmlElement将Course中的属性定义为片为XML中的元素
[XmlType("Course")]
public class Course
{
[XmlElement("CourseId")]
public int CourseId { get; set; }
[XmlElement("CourseName")]
public string CourseName { get; set; }
}
- 创建一个实例,并序列化为XML
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;
Student student = new Student()
{
Id = 1,
Age = 30,
Name = "Tom",
Hobbies = new List<string>() { "Baskball", "Football" },
StudentAddress = new Address() { Code = 1, Region = "HuoDong", Province ="JiangSu",City ="Suzhou" },
ListCourse = new List<Course>() { new Course() { CourseId = 100, CourseName="Chinese" },new Course() { CourseId = 101, CourseName = "Math" } }
};
XmlSerializer serializer = new XmlSerializer(typeo(Student));
using (StringWriter writer = new StringWriter())
{
serializer.Serialize(writer, student);
string xmlStudent = writer.ToString();
Console.WriteLine(xmlStudent);
}
2.SQL读取XML节点及属性
- 声明一个XML类型,并初始化
DECLARE @xml XML;
SET @xml='
<Student>
<Id>1</Id>
<Name>Tom</Name>
<Age>30</Age>
<Hobbies>
<string>Baskball</string>
<string>Football</string>
</Hobbies>
<StudentAddress Code="1" Region="HuoDong" City="Suzhou" Province="JiangSu" />
<ListCourse>
<Course>
<CourseId>100</CourseId>
<CourseName>Chinese</CourseName>
</Course>
<Course>
<CourseId>101</CourseId>
<CourseName>Math</CourseName>
</Course>
</ListCourse>
</Student>';
- 解析Student对象的常规属性
--解析Student
SELECT x.value('./Id[1]', 'int') AS Id
,x.value('./Name[1]', 'nvarchar(100)') AS Name
,x.value('./Age[1]', 'int') AS Age
FROM @xml.nodes('/Student') T(x);
结果:
Id | Name | Age |
---|---|---|
1 | Tom | 30 |
- 解析List
类型属性
--解析Hobbies(这种方式无意义,因为Hobbies中的元素个数不确定)
SELECT x.value('string[1]', 'nvarchar(100)') AS Hobby1, x.value('string[2]', 'nvarchar(100)') AS Hobby2
FROM @xml.nodes('/Student/Hobbies') T(x);
结果:
Hobby1 | Hobby2 |
---|---|
Baskball | Football |
--解析Hobbies
SELECT x.value('.', 'nvarchar(100)') AS Hobbies FROM @xml.nodes('/Student/Hobbies/string') T(x);
结果:
Hobbies |
---|
Baskball |
Football |
- 解析自定义类型Address
注意:我们在序列化的时候,Address类中的属性Code,Region,City,Province全部是使用特性[XmlAttribute],故这些属性在XML中为标签的属性
--解析StudenAddress
SELECT x.value('@Code', 'nvarchar(100)') AS Code
,x.value('@Region', 'nvarchar(100)') AS Region
,x.value('@City', 'nvarchar(100)') AS City
,x.value('@Province', 'nvarchar(100)') AS Province
FROM @xml.nodes('/Student/StudentAddress') T(x);
结果:
Code | Region | City | Province |
---|---|---|---|
1 | HuoDong | Suzhou | JiangSu |
- 解析自定义类型Course
注意:我们的序列化的时候,Course类中的属性CourseId,CourseName全部(默认)是使用特性[XmlElement],故这些属性在XML中为标签
--解析ListCourse
SELECT x.value('(CourseId/text())[1]', 'int') AS CourseId
,x.value('(CourseName/text())[1]', 'nvarchar(50)') AS CourseName
FROM @xml.nodes('/Student/ListCourse/Course') AS T(x);
结果:
CourseId | CourseName |
---|---|
100 | Chinese |
101 | Math |
3.SQL编辑XML节点
3.1 SQL更新XML节点
示例:更新 CourseId 为 100 的 CourseName 为 "English"
DECLARE @xml XML;
SET @xml = '
<ListCourse>
<Course>
<CourseId>100</CourseId>
<CourseName>Chinese</CourseName>
</Course>
<Course>
<CourseId>101</CourseId>
<CourseName>Math</CourseName>
</Course>
</ListCourse>';
-- 更新 CourseId 为 100 的 CourseName 为 "English"
SET @xml.modify('
replace value of (/ListCourse/Course[CourseId=100]/CourseName/text())[1] with "English"
');
-- 读取更新后的 XML
SELECT
T.c.value('(CourseId/text())[1]', 'int') AS CourseId,
T.c.value('(CourseName/text())[1]', 'nvarchar(50)') AS CourseName
FROM
@xml.nodes('/ListCourse/Course') AS T(c);
结果:
CourseId | CourseName |
---|---|
100 | English |
101 | Math |
3.2 插入新节点
示例:插入一个新的 Course 节点
DECLARE @xml XML;
SET @xml = '
<ListCourse>
<Course>
<CourseId>100</CourseId>
<CourseName>Chinese</CourseName>
</Course>
<Course>
<CourseId>101</CourseId>
<CourseName>Math</CourseName>
</Course>
</ListCourse>';
-- 插入一个新的 Course 节点
SET @xml.modify('
insert <Course>
<CourseId>102</CourseId>
<CourseName>Science</CourseName>
</Course>
as last into (/ListCourse)[1]
');
-- 读取更新后的 XML
SELECT
T.c.value('(CourseId/text())[1]', 'int') AS CourseId,
T.c.value('(CourseName/text())[1]', 'nvarchar(50)') AS CourseName
FROM
@xml.nodes('/ListCourse/Course') AS T(c);
结果:
CourseId | CourseName |
---|---|
100 | Chinese |
101 | Math |
102 | Science |
3.3 删除节点
示例:删除 CourseId 为 101 的 Course 节点
DECLARE @xml XML;
SET @xml = '
<ListCourse>
<Course>
<CourseId>100</CourseId>
<CourseName>Chinese</CourseName>
</Course>
<Course>
<CourseId>101</CourseId>
<CourseName>Math</CourseName>
</Course>
</ListCourse>';
-- 删除 CourseId 为 101 的 Course 节点
SET @xml.modify('
delete /ListCourse/Course[CourseId=101]
');
-- 读取更新后的 XML
SELECT
T.c.value('(CourseId/text())[1]', 'int') AS CourseId,
T.c.value('(CourseName/text())[1]', 'nvarchar(50)') AS CourseName
FROM
@xml.nodes('/ListCourse/Course') AS T(c);
结果:
CourseId | CourseName |
---|---|
100 | Chinese |
4.对XML的节点做一些判断
- 首先,我们还是可以将XML的节点数据转为表值,使用SQL进行统计判断,但是这里还是罗列一些直接针对XML的判断方法
4.1 判断是否存在指定类型的节点
- 判断ListCourse节点下是否存在Course节点
DECLARE @xml XML='<ListCourse>
<Course>
<CourseId>100</CourseId>
<CourseName>Chinese</CourseName>
</Course>
</ListCourse>';
SELECT CASE @xml.exist('ListCourse/Course')WHEN 1 THEN 'true' ELSE 'false' END AS IsExist;
--结果:
IsExist
--------
true
4.2 统计指定类型的节点数量
- 得到XML类型中某个节点下子节点的数量,这在需要验证或处理特定数量的参数时非常有用
这里演示统计ListCourse节点下Course节点的数量
DECLARE @xml XML =
'<ListCourse>
<Course>
<CourseId>100</CourseId>
<CourseName>Chinese</CourseName>
</Course>
<Course>
<CourseId>101</CourseId>
<CourseName>Math</CourseName>
</Course>
</ListCourse>'
SELECT c.value('count(/ListCourse/Course)','int') AS CourseCount FROM @xml.nodes('/ListCourse') T(c)
SELECT @xml.value('count(/ListCourse/Course)','int') AS CourseCount
--结果:
2
5.示例—:一个使用XML类型参数的存储过程
说明:
-
这个是一个解析客户端传来的XML的简单示例,该XML数据是ERP下发工单到MES的参数
实际开发中是创建一个存储过程,该存储过程的参数是XML类型的,然后该存储过程中的解析XML,并进行一些处理
这个XML参数格式,并不是最佳的实践方式,还是应该使用元素表示数据而不是使用属性表示数据。 -
解析XML看似繁琐,但是因为参数是XML类型的,可以让存储过程一次性接受大量的结构化的数据,故可以一次性将所需的参数都传递到存储过程
尤其是开发接口的时候,接口参数为一个XML格式的字符串,然后直接使用该字符串作为存储过程的参数,
之后整个接口的调整,比如说增加字段等,都不需要再次修改接口的代码,直接修改存储过程即可。 -
同时还有一个有点:XML类型的元素是可扩展的。若是前端传递的XML中添加了新的元素,这里的解析XML的代码并不会报错。这也是XML的优势之一,就是可以在不中断应用程序的情况下进行扩展。
DECLARE @xml XML;
SET @xml='
<mm_wo_order>
<id>102457</id>
<code>BZSC0000001724</code>
<type>标准生产订单</type>
<date>2025-01-22 15:47:12</date>
<factory_code>100</factory_code>
<quantity></quantity>
<customer_code></customer_code>
<create_user>创建者</create_user>
<create_time>2025-01-20 17:05:37.317</create_time>
<remark></remark>
<status>已审核</status>
<cp_list>
<cp line_id="102475" item_code="CA000966" quantity="6.0000000000" uom="Pcs" plan_start_date="2025-01-20 00:00:00" so_order_code="XSDD003178" so_order_line="116727">
<item line_id="160470" item_code="C18010100118" quantity="6.0000000000" unit_qty="1.000000000000000" uom="Pcs"/>
<item line_id="160471" item_code="C23040200075" quantity="6.0000000000" unit_qty="1.000000000000000" uom="Pcs"/>
<item line_id="160472" item_code="C18010100062" quantity="6.0000000000" unit_qty="1.000000000000000" uom="Pcs"/>
<item line_id="160473" item_code="C18010100119" quantity="6.0000000000" unit_qty="1.000000000000000" uom="Pcs"/>
<item line_id="160474" item_code="C23040200045" quantity="6.0000000000" unit_qty="1.000000000000000" uom="Pcs"/>
<item line_id="160475" item_code="C13040100007" quantity="30.0000000000" unit_qty="5.000000000000000" uom="G"/>
<item line_id="160476" item_code="C08070300031" quantity="6.0000000000" unit_qty="1.000000000000000" uom="Pcs"/>
<item line_id="160477" item_code="C20040100006" quantity="13.0000000000" unit_qty="2.166666666666666" uom="Pcs"/>
<item line_id="160478" item_code="C02020101527" quantity="6.0000000000" unit_qty="1.000000000000000" uom="Pcs"/>
<item line_id="160479" item_code="C16020100270" quantity="18.0000000000" unit_qty="3.000000000000000" uom="Pcs"/>
<item line_id="160480" item_code="C21010200038" quantity="6.0000000000" unit_qty="1.000000000000000" uom="Pcs"/>
<item line_id="160481" item_code="C20040100030" quantity="55.0000000000" unit_qty="9.166666666666666" uom="Pcs"/>
<item line_id="160482" item_code="C20040200011" quantity="25.0000000000" unit_qty="4.166666666666666" uom="Pcs"/>
<item line_id="160483" item_code="C18010100121" quantity="6.0000000000" unit_qty="1.000000000000000" uom="Pcs"/>
<item line_id="160484" item_code="C23010100101" quantity="6.0000000000" unit_qty="1.000000000000000" uom="Pcs"/>
<item line_id="160485" item_code="C16040100018" quantity="6.0000000000" unit_qty="1.000000000000000" uom="Pcs"/>
<item line_id="160486" item_code="C23060200006" quantity="6.0000000000" unit_qty="1.000000000000000" uom="Pcs"/>
<item line_id="160487" item_code="C08020200128" quantity="6.0000000000" unit_qty="1.000000000000000" uom="Pcs"/>
<item line_id="160488" item_code="C23040200029" quantity="6.0000000000" unit_qty="1.000000000000000" uom="Pcs"/>
<item line_id="160489" item_code="C23030200006" quantity="6.0000000000" unit_qty="1.000000000000000" uom="Pcs"/>
<item line_id="160490" item_code="C18010100134" quantity="6.0000000000" unit_qty="1.000000000000000" uom="Pcs"/>
<item line_id="160491" item_code="C02020101427" quantity="6.0000000000" unit_qty="1.000000000000000" uom="Pcs"/>
<item line_id="160492" item_code="C23040200042" quantity="6.0000000000" unit_qty="1.000000000000000" uom="Pcs"/>
<item line_id="160493" item_code="C23080300008" quantity="6.0000000000" unit_qty="1.000000000000000" uom="Pcs"/>
<item line_id="160494" item_code="C27020100080" quantity="6.0000000000" unit_qty="1.000000000000000" uom="Pcs"/>
<item line_id="160495" item_code="C23090100219" quantity="12.0000000000" unit_qty="2.000000000000000" uom="Pcs"/>
<item line_id="160496" item_code="C20040100031" quantity="13.0000000000" unit_qty="2.166666666666666" uom="Pcs"/>
<item line_id="160497" item_code="C23080300007" quantity="6.0000000000" unit_qty="1.000000000000000" uom="Pcs"/>
<item line_id="160498" item_code="C10080100044" quantity="6.0000000000" unit_qty="1.000000000000000" uom="Pcs"/>
<item line_id="160499" item_code="C27030100371" quantity="6.0000000000" unit_qty="1.000000000000000" uom="Pcs"/>
<seq line_id="104276" seq_code="10" seq_name="组装" ok_qty="6.0000000000" uom="Pcs" eqp_mpu="10.6830000000" man_mpu="10.6830000000"/>
<seq line_id="104277" seq_code="20" seq_name="测试" ok_qty="6.0000000000" uom="Pcs" eqp_mpu="23.4830000000" man_mpu="3.7170000000"/>
<seq line_id="104278" seq_code="30" seq_name="包装" ok_qty="6.0000000000" uom="Pcs" eqp_mpu="1.5830000000" man_mpu="1.5830000000"/>
</cp>
</cp_list>
</mm_wo_order>';
--获取工单主表信息
IF OBJECT_ID('tempdb..#tempMa') IS NOT NULL DROP TABLE #tempMa;
SELECT x.value('./id[1]', 'bigint') AS Id
,x.value('./code[1]', 'nvarchar(50)') AS Code
,x.value('./factory_code[1]', 'nvarchar(50)') AS Factory_Code
,x.value('./customer_code[1]', 'nvarchar(50)') AS Customer_Code
,x.value('./type[1]', 'nvarchar(50)') AS Type
,x.value('./date[1]', 'date') AS Date
,x.value('./create_user[1]', 'nvarchar(50)') AS Create_User
,x.value('./create_time[1]', 'datetime') AS Create_Time
,x.value('./status[1]', 'nvarchar(50)') AS Status
,x.value('./remark[1]', 'nvarchar(500)') AS Remark
INTO #tempMa
FROM @xml.nodes('/mm_wo_order') t(x);
SELECT * FROM #tempMa;
--获取明细表中的item(材料)的主表信息
IF OBJECT_ID('tempdb..#tempCp') IS NOT NULL DROP TABLE #tempCp;
SELECT x.value('@line_id[1]', 'nvarchar(50)') line_id
,x.value('@item_code[1]', 'nvarchar(50)') item_code
,x.value('@quantity[1]', 'decimal(19,6)') quantity
,x.value('@uom[1]', 'nvarchar(50)') uom
,x.value('@plan_start_date[1]', 'date') plan_start_date
,x.value('@so_order_code[1]', 'nvarchar(50)') so_order_code
,x.value('@so_order_line[1]', 'nvarchar(50)') so_order_line
INTO #tempCp
FROM @xml.nodes('//cp_list/cp') t(x);
SELECT * FROM #tempCp;
--获取明细表中的item的信息
IF OBJECT_ID('tempdb..#tempItem') IS NOT NULL DROP TABLE #tempItem;
SELECT x.value('../@line_id[1]', 'nvarchar(50)') cp_line_id
,x.value('@line_id[1]', 'nvarchar(50)') line_id
,x.value('@item_code[1]', 'nvarchar(50)') item_code
,x.value('@quantity[1]', 'decimal(19,6)') quantity
,x.value('@unit_qty[1]', 'decimal(19,6)') unit_qty
,x.value('@close_qty[1]', 'decimal(19,6)') close_qty
,x.value('@uom[1]', 'nvarchar(50)') uom
,x.value('@status[1]', 'nvarchar(50)') status
INTO #tempItem
FROM @xml.nodes('//cp_list/cp/item') t(x);
--获取工序的明细表信息
SELECT * FROM #tempItem;
IF OBJECT_ID('tempdb..#tempSeq') IS NOT NULL DROP TABLE #tempSeq;
SELECT x.value('../@line_id[1]', 'nvarchar(50)') cp_line_id
,x.value('@line_id[1]', 'nvarchar(50)') line_id
,x.value('@seq_code[1]', 'nvarchar(50)') seq_code
,x.value('@seq_name[1]', 'nvarchar(50)') seq_name
,x.value('@ok_qty[1]', 'decimal(19,6)') ok_qty
,x.value('@ng_qty[1]', 'decimal(19,6)') ng_qty
,x.value('@uom[1]', 'nvarchar(50)') uom
,x.value('@status[1]', 'nvarchar(50)') status
,x.value('@man_mpu[1]', 'decimal(19,6)') man_mpu
,x.value('@eqp_mpu[1]', 'decimal(19,6)') eqp_mpu
INTO #tempSeq
FROM @xml.nodes('//cp_list/cp/seq') t(x);
SELECT * FROM #tempSeq;
- 结果
| Id | Code | Factory_Code | Customer_Code | Type | Date | Create_User | Create_Time | Status | Remark |
| ------ | -------------- | ------------ | ------------- | ------ | --------- | ----------- | ----------------------- | ------ | ------ |
| 102457 | BZSC0000001724 | 100 | | 标准生产订单 | 2025/1/22 | 创建者 | 2025-01-20 17:05:37.317 | 已审核 |
| line_id | item_code | quantity | uom | plan_start_date | so_order_code | so_order_line |
| ------- | --------- | -------- | ---- | --------------- | ------------- | ------------- |
| 102475 | CA000966 | 6 | Pcs | 2025/1/20 | XSDD003178 | 116727 |
| cp_line_id | line_id | item_code | quantity | unit_qty | close_qty | uom | status |
| ---------- | ------- | ------------ | -------- | -------- | --------- | ---- | ------ |
| 102475 | 160470 | C18010100118 | 6 | 1 | | Pcs | |
| 102475 | 160471 | C23040200075 | 6 | 1 | | Pcs | |
| 102475 | 160472 | C18010100062 | 6 | 1 | | Pcs | |
| 102475 | 160473 | C18010100119 | 6 | 1 | | Pcs | |
| 102475 | 160474 | C23040200045 | 6 | 1 | | Pcs | |
| 102475 | 160475 | C13040100007 | 30 | 5 | | G | |
| 102475 | 160476 | C08070300031 | 6 | 1 | | Pcs | |
| 102475 | 160477 | C20040100006 | 13 | 2.166667 | | Pcs | |
| 102475 | 160478 | C02020101527 | 6 | 1 | | Pcs | |
| 102475 | 160479 | C16020100270 | 18 | 3 | | Pcs | |
| 102475 | 160480 | C21010200038 | 6 | 1 | | Pcs | |
| 102475 | 160481 | C20040100030 | 55 | 9.166667 | | Pcs | |
| 102475 | 160482 | C20040200011 | 25 | 4.166667 | | Pcs | |
| 102475 | 160483 | C18010100121 | 6 | 1 | | Pcs | |
| 102475 | 160484 | C23010100101 | 6 | 1 | | Pcs | |
| 102475 | 160485 | C16040100018 | 6 | 1 | | Pcs | |
| 102475 | 160486 | C23060200006 | 6 | 1 | | Pcs | |
| 102475 | 160487 | C08020200128 | 6 | 1 | | Pcs | |
| 102475 | 160488 | C23040200029 | 6 | 1 | | Pcs | |
| 102475 | 160489 | C23030200006 | 6 | 1 | | Pcs | |
| 102475 | 160490 | C18010100134 | 6 | 1 | | Pcs | |
| 102475 | 160491 | C02020101427 | 6 | 1 | | Pcs | |
| 102475 | 160492 | C23040200042 | 6 | 1 | | Pcs | |
| 102475 | 160493 | C23080300008 | 6 | 1 | | Pcs | |
| 102475 | 160494 | C27020100080 | 6 | 1 | | Pcs | |
| 102475 | 160495 | C23090100219 | 12 | 2 | | Pcs | |
| 102475 | 160496 | C20040100031 | 13 | 2.166667 | | Pcs | |
| 102475 | 160497 | C23080300007 | 6 | 1 | | Pcs | |
| 102475 | 160498 | C10080100044 | 6 | 1 | | Pcs | |
| 102475 | 160499 | C27030100371 | 6 | 1 | | Pcs | |
| cp_line_id | line_id | seq_code | seq_name | ok_qty | ng_qty | uom | status | man_mpu | eqp_mpu |
| ---------- | ------- | -------- | -------- | ------ | ------ | ---- | ------ | ------- | ------- |
| 102475 | 104276 | 10 | 组装 | 6 | | Pcs | | 10.683 | 10.683 |
| 102475 | 104277 | 20 | 测试 | 6 | | Pcs | | 3.717 | 23.483 |
| 102475 | 104278 | 30 | 包装 | 6 | | Pcs | | 1.583 | 1.583 |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
2020-02-11 .NET异步程序设计——异步委托
2019-02-11 《SQL CookBook 》笔记-第二章-查询结果排序