数据库、关系查询
Database, relational query
化学品有一个商品名(这是通常所说的)和一个实际的化学名称。我需要查找商品名称,找到其正确的化学名称,然后获取该化学品的特性。例如:
$tradeName = "Voranol"
if $tradeName == "Voranol" then
$productName = "Polyether Polyol"
$flare = "List I"
$bay = "1"
$listPos = 3
EndIf
我有一个包含大量产品的 .au3 文件。它工作正常,但做起来有点乏味 if $tradeName == "Name1" or $tradeName == "Name2" or $tradeName == "Name4" or $tradeName == "Name5"
。我还需要能够以编程方式对其进行编辑。这是我现在使用的:
if $product == "dowanol pmb" or $product == "dowanol pma" or $product == "dipropylene glycol" or $product == "dowanol pnp" or $productCheck2 == "dowanol pmb" or $productCheck2 == "dowanol pma" or $productCheck2 == "dipropylene glycol" or $productCheck2 == "dowanol pnp" then
$result = "DIPROPYLENE GLYCOL"
$bay = 4
$useFlare = 1
$listPos = 2
elseif $product == "glycol blend" then
$result = "GLYCOL"
$bay = 3
$useFlare = 2
$listPos = 1
elseif $product == "isopar e" or $product == "isopar c" or $product == "isopar h" or $productCheck2 == "isopar h" then
$result = "PETROLEUM NAPTHA"
$bay = 5
$useFlare = 0
$listPos = 1
EndIf
; Note: 0 = No Flare, 1 = Normal Flare, 2 = CAS Flare
Autoit 中最好的数据库解决方案是 SQLite。
如果你想像专业人士那样做,你应该使用 SQLite。
#include <SQLite.au3>
#include <SQLite.dll.au3>
Local $hQuery, $aRow
_SQLite_Startup()
ConsoleWrite("_SQLite_LibVersion=" & _SQLite_LibVersion() & @CRLF)
_SQLite_Open()
; Without $sCallback it's a resultless statement
_SQLite_Exec(-1, "Create table tblTest (a,b int,c single not null);" & _
"Insert into tblTest values ('1',2,3);" & _
"Insert into tblTest values (Null,5,6);")
Local $d = _SQLite_Exec(-1, "Select rowid,* From tblTest", "_cb") ; _cb will be called for each row
Func _cb($aRow)
For $s In $aRow
ConsoleWrite($s & @TAB)
Next
ConsoleWrite(@CRLF)
; Return $SQLITE_ABORT ; Would Abort the process and trigger an @error in _SQLite_Exec()
EndFunc ;==>_cb
_SQLite_Close()
_SQLite_Shutdown()
; Output:
; 1 1 2 3
; 2 5 6
作为更简单的解决方案,我建议使用 INI 文件作为数据库。
[Voranol]
ProductName=Polyether Polyol
Flare=List I
Bay=1
ListPos=3
[Chem2]
ProductName=..
...
然后
; Read the INI section names. This will return a 1 dimensional array.
Local $aArray = IniReadSectionNames($sFilePath)
; Check if an error occurred.
If Not @error Then
; Enumerate through the array displaying the section names.
For $i = 1 To $aArray[0]
MsgBox($MB_SYSTEMMODAL, "", "Section: " & $aArray[$i])
Next
EndIf
现在 windows INI 文件大小 (32kb) 有限制。
这意味着,如果违反该限制,某些 Autoit INI 功能将无法工作。
这可以通过使用您自己的 INI 函数来解决:
Func _IniReadSectionNamesEx($hFile)
Local $iSize = FileGetSize($hFile) / 1024
If $iSize <= 31 Then
Local $aNameRead = IniReadSectionNames($hFile)
If @error Then Return SetError(@error, 0, '')
Return $aNameRead
EndIf
Local $aSectionNames = StringRegExp(@CRLF & FileRead($hFile) & @CRLF, '(?s)\n\s*\[(.*?)\]s*\r', 3)
If IsArray($aSectionNames) = 0 Then Return SetError(1, 0, 0)
Local $nUbound = UBound($aSectionNames)
Local $aNameReturn[$nUbound + 1]
$aNameReturn[0] = $nUbound
For $iCC = 0 To $nUBound - 1
$aNameReturn[$iCC + 1] = $aSectionNames[$iCC]
Next
Return $aNameReturn
EndFunc
Func _IniReadSectionEx($hFile, $vSection)
Local $iSize = FileGetSize($hFile) / 1024
If $iSize <= 31 Then
Local $aSecRead = IniReadSection($hFile, $vSection)
If @error Then Return SetError(@error, 0, '')
Return $aSecRead
EndIf
Local $sFRead = @CRLF & FileRead($hFile) & @CRLF & '['
$vSection = StringStripWS($vSection, 7)
Local $aData = StringRegExp($sFRead, '(?s)(?i)\n\s*\[\s*' & $vSection & '\s*\]\s*\r\n(.*?)\[', 3)
If IsArray($aData) = 0 Then Return SetError(1, 0, 0)
Local $aKey = StringRegExp(@LF & $aData[0], '\n\s*(.*?)\s*=', 3)
Local $aValue = StringRegExp(@LF & $aData[0], '\n\s*.*?\s*=(.*?)\r', 3)
Local $nUbound = UBound($aKey)
Local $aSection[$nUBound +1][2]
$aSection[0][0] = $nUBound
For $iCC = 0 To $nUBound - 1
$aSection[$iCC + 1][0] = $aKey[$iCC]
$aSection[$iCC + 1][1] = $aValue[$iCC]
Next
Return $aSection
EndFunc
数据库选项的另一种替代方法是使用 XML 文档来存储产品(化学品)信息。
您可以使用 XPath 轻松查询 XML 以获得产品 name/properties。维护文件也相当容易。您甚至可以创建一个 XML 架构来验证以确保您的文件在修改后仍然有效。
AutoIt 中 XML 的处理可以通过几种不同的方式完成:
- 正在创建一个 MSXML 对象
- 运行 类似 xmlstarlet
的命令行工具
- 从命令行使用 XPath/XQuery/XSLT 处理器(即 java 到 运行 Saxon)
运行 像 Saxon 这样的东西可能对你的需要有点过分了。
MSXML 还不错,应该已经存在多个 UDF。
Xmlstarlet 将是我的投票。 (注意:我以前没有以这种方式使用过 xmlstarlet。我是 Saxon 的超级粉丝,几乎只使用它。特别是对于 AutoIt,我结合使用了 MSXML 和 Saxon;Saxon 到将复杂数据转换为更小、更简单的子集,然后 MSXML 对该子集执行简单的 xpath 查询。但是,如果我打算做这样的事情,我会认真考虑 xmlstarlet。 )
此外,如果您的数据增长到单个 XML 文件没有意义的程度,您始终可以将其拆分为一组较小的文件;个别产品也许。您可能还会达到将这些文件加载到实际的 XML 数据库中可能有意义的程度(eXistdb 是一个选项)。
这是您的 XML(架构和实例)的一个简单示例:
XSD (products.xsd)
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="products">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" ref="product"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="product">
<xs:complexType>
<xs:sequence>
<xs:element ref="name"/>
<xs:element ref="tradenames"/>
</xs:sequence>
<xs:attribute name="bay" use="required" type="xs:integer"/>
<xs:attribute name="listpos" use="required" type="xs:integer"/>
<xs:attribute name="useflare" use="required" type="xs:integer"/>
</xs:complexType>
</xs:element>
<xs:element name="tradenames">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" ref="name"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="name" type="xs:string"/>
</xs:schema>
XML (products.xml)
<products xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="products.xsd">
<product bay="4" useflare="1" listpos="2">
<name>DIPROPYLENE GLYCOL</name>
<tradenames>
<name>dowanol pmb</name>
<name>dowanol pma</name>
<name>dipropylene glycol</name>
<name>dowanol pnp</name>
</tradenames>
</product>
<product bay="3" useflare="2" listpos="1">
<name>GLYCOL</name>
<tradenames>
<name>glycol blend</name>
</tradenames>
</product>
<product bay="5" useflare="0" listpos="1">
<name>PETROLEUM NAPTHA</name>
<tradenames>
<name>isopar e</name>
<name>isopar c</name>
<name>isopar h</name>
</tradenames>
</product>
</products>
这里有一点 AutoIt,它使用 MSXML 来演示加载 XML(针对 XSD 进行验证)并搜索商品名称包含 "glycol".
AutoIt
;~ AutoIt Version: 3.3.14.2
;String to search on.
$searchString = "glycol"
ConsoleWrite("Search string: '" & $searchString & "'" & @CRLF)
;XPath for searching trade names. Search string is injected (code injection; escaping of strings would be a very good idea!).
$xpath_tradename = "/products/product[tradenames/name[contains(.,'" & $searchString & "')]]"
ConsoleWrite("XPath: '" & $xpath_tradename & "'" & @CRLF)
$msxml = ObjCreate('MSXML2.DOMDocument.6.0')
If IsObj($msxml) Then
$msxml.async = False
$msxml.validateOnParse = True
$msxml.resolveExternals = True
$msxml.setProperty("SelectionLanguage", "XPath")
$msxml.load('products.xml')
If $msxml.parseError.errorCode = 0 Then
$prods = $msxml.SelectNodes($xpath_tradename)
If IsObj($prods) And $prods.Length > 0 Then
ConsoleWrite("Number of products found: '" & $prods.Length & "'" & @CRLF)
For $prod In $prods
ConsoleWrite(@CRLF & "------ PRODUCT ------" & @CRLF)
ConsoleWrite("Product name: '" & $prod.SelectSingleNode('name').text & "'" & @CRLF)
ConsoleWrite("Product bay: '" & $prod.getAttribute('bay') & "'" & @CRLF)
Next
ConsoleWrite(@CRLF)
Else
ConsoleWrite("PRODUCT NOT FOUND" & @CRLF)
EndIf
Else
MsgBox(17, 'Error', 'Error opening XML file: ' & @CRLF & @CRLF & $msxml.parseError.reason)
SetError($msxml.parseError.errorCode)
EndIf
EndIf
控制台输出
Search string: 'glycol'
XPath: '/products/product[tradenames/name[contains(.,'glycol')]]'
Number of products found: '2'
------ PRODUCT ------
Product name: 'DIPROPYLENE GLYCOL'
Product bay: '4'
------ PRODUCT ------
Product name: 'GLYCOL'
Product bay: '3'
I need to look up a trade name, find its proper chemical name, then get properties of that chemical.
关系查询(SQLite)
- SQL as understood by SQLite.
- 如果要求仅限于插入、编辑和查询,SQLite database management tool may suffice. AutoIt SQLite functions are documented as per User-defined function-reference:
- (创建和)使用
_SQLite_Open()
打开数据库。
- 使用
_SQLite_Exec()
. 创建 table 、索引和视图(并插入记录)
- 使用
_SQLite_GetTable2d()
return 的查询结果作为二维数组。
结构
SQLite data types. Inserting records to product
and substance
table may be .
Table product
定义商品名称。
id
name
1
dowanol pmb
2
dowanol pma
3
dipropylene glycol
4
dowanol pnp
5
glycol blend
6
isopar e
7
isopar c
8
isopar h
9
Polyether Polyol
10
Voranol
创作:
CREATE TABLE IF NOT EXISTS product (
id INTEGER PRIMARY KEY,
name TEXT UNIQUE
);
插入记录:
INSERT INTO product (name) VALUES ('dowanol pmb');
Table substance
定义化学名称(和特性)。
id
name
flare
bay
1
Polyether Polyol
1
1
2
DIPROPYLENE GLYCOL
1
4
3
GLYCOL
2
3
4
PETROLEUM NAPHTA
0
5
创作:
CREATE TABLE IF NOT EXISTS substance (
id INTEGER PRIMARY KEY,
name TEXT UNIQUE,
flare INTEGER,
bay INTEGER
);
插入记录:
INSERT INTO substance (name, flare, bay) VALUES ('Polyether Polyol', 1, 1);
Tablerelation
定义 product
和 substance
table 的记录之间的关系(使用 foreign keys)。
id
product
substance
1
1
2
2
2
2
3
3
2
4
4
2
5
5
3
6
6
4
7
7
4
8
8
4
9
9
4
10
10
1
创作:
CREATE TABLE IF NOT EXISTS relation (
id INTEGER PRIMARY KEY,
product INTEGER REFERENCES product(id),
substance INTEGER REFERENCES substance(id),
UNIQUE( /* Constraint applies to *combination* of columns. */
product,
substance
)
);
插入记录:
INSERT INTO relation (
product,
substance
) VALUES (
(SELECT id FROM product WHERE name = 'dowanol pmb'),
(SELECT id FROM substance WHERE name = 'DIPROPYLENE GLYCOL')
);
或者只是:
INSERT INTO relation (product, substance) VALUES (0, 1);
查看view_relation
View (stored query), joining (combines) product
和 substance
tables' 字段,根据 relation
table 的记录(作为虚拟table,否定每个查询都需要包含基础 JOIN
运算符。
name_product
name_substance
flare
bay
dowanol pmb
DIPROPYLENE GLYCOL
1
4
dowanol pma
DIPROPYLENE GLYCOL
1
4
dipropylene glycol
DIPROPYLENE GLYCOL
1
4
dowanol pnp
DIPROPYLENE GLYCOL
1
4
glycol blend
GLYCOL
2
3
isopar e
PETROLEUM NAPTHA
0
5
isopar c
PETROLEUM NAPTHA
0
5
isopar h
PETROLEUM NAPTHA
0
5
Polyether Polyol
PETROLEUM NAPTHA
0
5
Voranol
Polyether Polyol
1
1
创作:
CREATE VIEW IF NOT EXISTS view_relation AS
SELECT
product.name AS name_product,
substance.name AS name_substance,
substance.flare,
substance.bay
FROM
relation
LEFT OUTER JOIN product ON relation.product = product.id
LEFT OUTER JOIN substance ON relation.substance = substance.id
ORDER BY
product.id ASC
;
按商号查询
name_product
name_substance
flare
bay
Voranol
Polyether Polyol
1
1
查询:
SELECT
*
FROM
view_relation
WHERE
name_product = 'Voranol'
;
或(无视图):
SELECT
product.name AS name_product,
substance.name AS name_substance,
substance.flare,
substance.bay
FROM
relation
WHERE
product.name = 'Voranol'
LEFT OUTER JOIN product ON relation.product = product.id
LEFT OUTER JOIN substance ON relation.substance = substance.id
;
按物质查询
name_product
name_substance
flare
bay
dowanol pmb
DIPROPYLENE GLYCOL
1
4
dowanol pma
DIPROPYLENE GLYCOL
1
4
dipropylene glycol
DIPROPYLENE GLYCOL
1
4
dowanol pnp
DIPROPYLENE GLYCOL
1
4
查询:
SELECT
*
FROM
view_relation
WHERE
name_substance = 'DIPROPYLENE GLYCOL'
;
或(无视图):
SELECT
product.name AS name_product,
substance.name AS name_substance,
substance.flare,
substance.bay
FROM
relation
WHERE
substance.name = 'DIPROPYLENE GLYCOL'
LEFT OUTER JOIN product ON relation.product = product.id
LEFT OUTER JOIN substance ON relation.substance = substance.id
;
AutoIt
创建(并将记录插入)单个 table 并查询它的示例:
#include <SQLite.au3>
#include <SQLite.dll.au3>
#include <Array.au3>
Global Const $g_iRecords = 50
Global Const $g_sFileDb = @ScriptDir & '\example.sqlite'
Global $g_aCreate = [ _
'CREATE TABLE IF NOT EXISTS example (id INTEGER PRIMARY KEY, name TEXT UNIQUE);' & @LF, _
'--CREATE INDEX IF NOT EXISTS index_example_name ON example(name);' & @LF _
]
Global Const $g_sInsert = 'INSERT INTO example (name) VALUES (%i);\n'
Global Const $g_sTransact1 = 'BEGIN TRANSACTION;' & @LF
Global Const $g_sTransact2 = 'END TRANSACTION;' & @LF
Global Const $g_sQuery = 'SELECT * FROM example ORDER BY id ASC;'
Global Const $g_sMsgError = 'sqlite.dll not found.' & @LF
Global $g_hDb = 0
Main()
Func Main()
Local $sQuery = ''
Local $iResultCol = 0
Local $iResultRow = 0
Local $aResult
For $i1 = 0 To UBound($g_aCreate, 1) -1
$sQuery &= $g_aCreate[$i1]
Next
For $i1 = 1 To $g_iRecords
$sQuery &= StringFormat($g_sInsert, _SQLite_FastEscape('example' & $i1))
Next
$sQuery = $g_sTransact1 & $sQuery & $g_sTransact2
ConsoleWrite($sQuery)
_SQLite_Startup()
If @error Then
ConsoleWrite($g_sMsgError)
Exit
EndIf
_SQLite_Open($g_sFileDb)
_SQLite_Exec($g_hDb, $sQuery)
_SQLite_GetTable2d($g_hDb, $g_sQuery, $aResult, $iResultRow, $iResultCol)
_SQLite_Close($g_hDb)
_SQLite_Shutdown()
_ArrayDisplay($aResult)
Exit
EndFunc
化学品有一个商品名(这是通常所说的)和一个实际的化学名称。我需要查找商品名称,找到其正确的化学名称,然后获取该化学品的特性。例如:
$tradeName = "Voranol"
if $tradeName == "Voranol" then
$productName = "Polyether Polyol"
$flare = "List I"
$bay = "1"
$listPos = 3
EndIf
我有一个包含大量产品的 .au3 文件。它工作正常,但做起来有点乏味 if $tradeName == "Name1" or $tradeName == "Name2" or $tradeName == "Name4" or $tradeName == "Name5"
。我还需要能够以编程方式对其进行编辑。这是我现在使用的:
if $product == "dowanol pmb" or $product == "dowanol pma" or $product == "dipropylene glycol" or $product == "dowanol pnp" or $productCheck2 == "dowanol pmb" or $productCheck2 == "dowanol pma" or $productCheck2 == "dipropylene glycol" or $productCheck2 == "dowanol pnp" then
$result = "DIPROPYLENE GLYCOL"
$bay = 4
$useFlare = 1
$listPos = 2
elseif $product == "glycol blend" then
$result = "GLYCOL"
$bay = 3
$useFlare = 2
$listPos = 1
elseif $product == "isopar e" or $product == "isopar c" or $product == "isopar h" or $productCheck2 == "isopar h" then
$result = "PETROLEUM NAPTHA"
$bay = 5
$useFlare = 0
$listPos = 1
EndIf
; Note: 0 = No Flare, 1 = Normal Flare, 2 = CAS Flare
Autoit 中最好的数据库解决方案是 SQLite。
如果你想像专业人士那样做,你应该使用 SQLite。
#include <SQLite.au3>
#include <SQLite.dll.au3>
Local $hQuery, $aRow
_SQLite_Startup()
ConsoleWrite("_SQLite_LibVersion=" & _SQLite_LibVersion() & @CRLF)
_SQLite_Open()
; Without $sCallback it's a resultless statement
_SQLite_Exec(-1, "Create table tblTest (a,b int,c single not null);" & _
"Insert into tblTest values ('1',2,3);" & _
"Insert into tblTest values (Null,5,6);")
Local $d = _SQLite_Exec(-1, "Select rowid,* From tblTest", "_cb") ; _cb will be called for each row
Func _cb($aRow)
For $s In $aRow
ConsoleWrite($s & @TAB)
Next
ConsoleWrite(@CRLF)
; Return $SQLITE_ABORT ; Would Abort the process and trigger an @error in _SQLite_Exec()
EndFunc ;==>_cb
_SQLite_Close()
_SQLite_Shutdown()
; Output:
; 1 1 2 3
; 2 5 6
作为更简单的解决方案,我建议使用 INI 文件作为数据库。
[Voranol]
ProductName=Polyether Polyol
Flare=List I
Bay=1
ListPos=3
[Chem2]
ProductName=..
...
然后
; Read the INI section names. This will return a 1 dimensional array.
Local $aArray = IniReadSectionNames($sFilePath)
; Check if an error occurred.
If Not @error Then
; Enumerate through the array displaying the section names.
For $i = 1 To $aArray[0]
MsgBox($MB_SYSTEMMODAL, "", "Section: " & $aArray[$i])
Next
EndIf
现在 windows INI 文件大小 (32kb) 有限制。 这意味着,如果违反该限制,某些 Autoit INI 功能将无法工作。
这可以通过使用您自己的 INI 函数来解决:
Func _IniReadSectionNamesEx($hFile)
Local $iSize = FileGetSize($hFile) / 1024
If $iSize <= 31 Then
Local $aNameRead = IniReadSectionNames($hFile)
If @error Then Return SetError(@error, 0, '')
Return $aNameRead
EndIf
Local $aSectionNames = StringRegExp(@CRLF & FileRead($hFile) & @CRLF, '(?s)\n\s*\[(.*?)\]s*\r', 3)
If IsArray($aSectionNames) = 0 Then Return SetError(1, 0, 0)
Local $nUbound = UBound($aSectionNames)
Local $aNameReturn[$nUbound + 1]
$aNameReturn[0] = $nUbound
For $iCC = 0 To $nUBound - 1
$aNameReturn[$iCC + 1] = $aSectionNames[$iCC]
Next
Return $aNameReturn
EndFunc
Func _IniReadSectionEx($hFile, $vSection)
Local $iSize = FileGetSize($hFile) / 1024
If $iSize <= 31 Then
Local $aSecRead = IniReadSection($hFile, $vSection)
If @error Then Return SetError(@error, 0, '')
Return $aSecRead
EndIf
Local $sFRead = @CRLF & FileRead($hFile) & @CRLF & '['
$vSection = StringStripWS($vSection, 7)
Local $aData = StringRegExp($sFRead, '(?s)(?i)\n\s*\[\s*' & $vSection & '\s*\]\s*\r\n(.*?)\[', 3)
If IsArray($aData) = 0 Then Return SetError(1, 0, 0)
Local $aKey = StringRegExp(@LF & $aData[0], '\n\s*(.*?)\s*=', 3)
Local $aValue = StringRegExp(@LF & $aData[0], '\n\s*.*?\s*=(.*?)\r', 3)
Local $nUbound = UBound($aKey)
Local $aSection[$nUBound +1][2]
$aSection[0][0] = $nUBound
For $iCC = 0 To $nUBound - 1
$aSection[$iCC + 1][0] = $aKey[$iCC]
$aSection[$iCC + 1][1] = $aValue[$iCC]
Next
Return $aSection
EndFunc
数据库选项的另一种替代方法是使用 XML 文档来存储产品(化学品)信息。
您可以使用 XPath 轻松查询 XML 以获得产品 name/properties。维护文件也相当容易。您甚至可以创建一个 XML 架构来验证以确保您的文件在修改后仍然有效。
AutoIt 中 XML 的处理可以通过几种不同的方式完成:
- 正在创建一个 MSXML 对象
- 运行 类似 xmlstarlet 的命令行工具
- 从命令行使用 XPath/XQuery/XSLT 处理器(即 java 到 运行 Saxon)
运行 像 Saxon 这样的东西可能对你的需要有点过分了。
MSXML 还不错,应该已经存在多个 UDF。
Xmlstarlet 将是我的投票。 (注意:我以前没有以这种方式使用过 xmlstarlet。我是 Saxon 的超级粉丝,几乎只使用它。特别是对于 AutoIt,我结合使用了 MSXML 和 Saxon;Saxon 到将复杂数据转换为更小、更简单的子集,然后 MSXML 对该子集执行简单的 xpath 查询。但是,如果我打算做这样的事情,我会认真考虑 xmlstarlet。 )
此外,如果您的数据增长到单个 XML 文件没有意义的程度,您始终可以将其拆分为一组较小的文件;个别产品也许。您可能还会达到将这些文件加载到实际的 XML 数据库中可能有意义的程度(eXistdb 是一个选项)。
这是您的 XML(架构和实例)的一个简单示例:
XSD (products.xsd)
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="products">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" ref="product"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="product">
<xs:complexType>
<xs:sequence>
<xs:element ref="name"/>
<xs:element ref="tradenames"/>
</xs:sequence>
<xs:attribute name="bay" use="required" type="xs:integer"/>
<xs:attribute name="listpos" use="required" type="xs:integer"/>
<xs:attribute name="useflare" use="required" type="xs:integer"/>
</xs:complexType>
</xs:element>
<xs:element name="tradenames">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" ref="name"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="name" type="xs:string"/>
</xs:schema>
XML (products.xml)
<products xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="products.xsd">
<product bay="4" useflare="1" listpos="2">
<name>DIPROPYLENE GLYCOL</name>
<tradenames>
<name>dowanol pmb</name>
<name>dowanol pma</name>
<name>dipropylene glycol</name>
<name>dowanol pnp</name>
</tradenames>
</product>
<product bay="3" useflare="2" listpos="1">
<name>GLYCOL</name>
<tradenames>
<name>glycol blend</name>
</tradenames>
</product>
<product bay="5" useflare="0" listpos="1">
<name>PETROLEUM NAPTHA</name>
<tradenames>
<name>isopar e</name>
<name>isopar c</name>
<name>isopar h</name>
</tradenames>
</product>
</products>
这里有一点 AutoIt,它使用 MSXML 来演示加载 XML(针对 XSD 进行验证)并搜索商品名称包含 "glycol".
AutoIt
;~ AutoIt Version: 3.3.14.2
;String to search on.
$searchString = "glycol"
ConsoleWrite("Search string: '" & $searchString & "'" & @CRLF)
;XPath for searching trade names. Search string is injected (code injection; escaping of strings would be a very good idea!).
$xpath_tradename = "/products/product[tradenames/name[contains(.,'" & $searchString & "')]]"
ConsoleWrite("XPath: '" & $xpath_tradename & "'" & @CRLF)
$msxml = ObjCreate('MSXML2.DOMDocument.6.0')
If IsObj($msxml) Then
$msxml.async = False
$msxml.validateOnParse = True
$msxml.resolveExternals = True
$msxml.setProperty("SelectionLanguage", "XPath")
$msxml.load('products.xml')
If $msxml.parseError.errorCode = 0 Then
$prods = $msxml.SelectNodes($xpath_tradename)
If IsObj($prods) And $prods.Length > 0 Then
ConsoleWrite("Number of products found: '" & $prods.Length & "'" & @CRLF)
For $prod In $prods
ConsoleWrite(@CRLF & "------ PRODUCT ------" & @CRLF)
ConsoleWrite("Product name: '" & $prod.SelectSingleNode('name').text & "'" & @CRLF)
ConsoleWrite("Product bay: '" & $prod.getAttribute('bay') & "'" & @CRLF)
Next
ConsoleWrite(@CRLF)
Else
ConsoleWrite("PRODUCT NOT FOUND" & @CRLF)
EndIf
Else
MsgBox(17, 'Error', 'Error opening XML file: ' & @CRLF & @CRLF & $msxml.parseError.reason)
SetError($msxml.parseError.errorCode)
EndIf
EndIf
控制台输出
Search string: 'glycol'
XPath: '/products/product[tradenames/name[contains(.,'glycol')]]'
Number of products found: '2'
------ PRODUCT ------
Product name: 'DIPROPYLENE GLYCOL'
Product bay: '4'
------ PRODUCT ------
Product name: 'GLYCOL'
Product bay: '3'
I need to look up a trade name, find its proper chemical name, then get properties of that chemical.
关系查询(SQLite)
- SQL as understood by SQLite.
- 如果要求仅限于插入、编辑和查询,SQLite database management tool may suffice. AutoIt SQLite functions are documented as per User-defined function-reference:
- (创建和)使用
_SQLite_Open()
打开数据库。 - 使用
_SQLite_Exec()
. 创建 table 、索引和视图(并插入记录)
- 使用
_SQLite_GetTable2d()
return 的查询结果作为二维数组。
结构
SQLite data types. Inserting records to product
and substance
table may be
Table product
定义商品名称。
id | name |
---|---|
1 | dowanol pmb |
2 | dowanol pma |
3 | dipropylene glycol |
4 | dowanol pnp |
5 | glycol blend |
6 | isopar e |
7 | isopar c |
8 | isopar h |
9 | Polyether Polyol |
10 | Voranol |
创作:
CREATE TABLE IF NOT EXISTS product (
id INTEGER PRIMARY KEY,
name TEXT UNIQUE
);
插入记录:
INSERT INTO product (name) VALUES ('dowanol pmb');
Table substance
定义化学名称(和特性)。
id | name | flare | bay |
---|---|---|---|
1 | Polyether Polyol | 1 | 1 |
2 | DIPROPYLENE GLYCOL | 1 | 4 |
3 | GLYCOL | 2 | 3 |
4 | PETROLEUM NAPHTA | 0 | 5 |
创作:
CREATE TABLE IF NOT EXISTS substance (
id INTEGER PRIMARY KEY,
name TEXT UNIQUE,
flare INTEGER,
bay INTEGER
);
插入记录:
INSERT INTO substance (name, flare, bay) VALUES ('Polyether Polyol', 1, 1);
Tablerelation
定义 product
和 substance
table 的记录之间的关系(使用 foreign keys)。
id | product | substance |
---|---|---|
1 | 1 | 2 |
2 | 2 | 2 |
3 | 3 | 2 |
4 | 4 | 2 |
5 | 5 | 3 |
6 | 6 | 4 |
7 | 7 | 4 |
8 | 8 | 4 |
9 | 9 | 4 |
10 | 10 | 1 |
创作:
CREATE TABLE IF NOT EXISTS relation (
id INTEGER PRIMARY KEY,
product INTEGER REFERENCES product(id),
substance INTEGER REFERENCES substance(id),
UNIQUE( /* Constraint applies to *combination* of columns. */
product,
substance
)
);
插入记录:
INSERT INTO relation (
product,
substance
) VALUES (
(SELECT id FROM product WHERE name = 'dowanol pmb'),
(SELECT id FROM substance WHERE name = 'DIPROPYLENE GLYCOL')
);
或者只是:
INSERT INTO relation (product, substance) VALUES (0, 1);
查看view_relation
View (stored query), joining (combines) product
和 substance
tables' 字段,根据 relation
table 的记录(作为虚拟table,否定每个查询都需要包含基础 JOIN
运算符。
name_product | name_substance | flare | bay |
---|---|---|---|
dowanol pmb | DIPROPYLENE GLYCOL | 1 | 4 |
dowanol pma | DIPROPYLENE GLYCOL | 1 | 4 |
dipropylene glycol | DIPROPYLENE GLYCOL | 1 | 4 |
dowanol pnp | DIPROPYLENE GLYCOL | 1 | 4 |
glycol blend | GLYCOL | 2 | 3 |
isopar e | PETROLEUM NAPTHA | 0 | 5 |
isopar c | PETROLEUM NAPTHA | 0 | 5 |
isopar h | PETROLEUM NAPTHA | 0 | 5 |
Polyether Polyol | PETROLEUM NAPTHA | 0 | 5 |
Voranol | Polyether Polyol | 1 | 1 |
创作:
CREATE VIEW IF NOT EXISTS view_relation AS
SELECT
product.name AS name_product,
substance.name AS name_substance,
substance.flare,
substance.bay
FROM
relation
LEFT OUTER JOIN product ON relation.product = product.id
LEFT OUTER JOIN substance ON relation.substance = substance.id
ORDER BY
product.id ASC
;
按商号查询
name_product | name_substance | flare | bay |
---|---|---|---|
Voranol | Polyether Polyol | 1 | 1 |
查询:
SELECT
*
FROM
view_relation
WHERE
name_product = 'Voranol'
;
或(无视图):
SELECT
product.name AS name_product,
substance.name AS name_substance,
substance.flare,
substance.bay
FROM
relation
WHERE
product.name = 'Voranol'
LEFT OUTER JOIN product ON relation.product = product.id
LEFT OUTER JOIN substance ON relation.substance = substance.id
;
按物质查询
name_product | name_substance | flare | bay |
---|---|---|---|
dowanol pmb | DIPROPYLENE GLYCOL | 1 | 4 |
dowanol pma | DIPROPYLENE GLYCOL | 1 | 4 |
dipropylene glycol | DIPROPYLENE GLYCOL | 1 | 4 |
dowanol pnp | DIPROPYLENE GLYCOL | 1 | 4 |
查询:
SELECT
*
FROM
view_relation
WHERE
name_substance = 'DIPROPYLENE GLYCOL'
;
或(无视图):
SELECT
product.name AS name_product,
substance.name AS name_substance,
substance.flare,
substance.bay
FROM
relation
WHERE
substance.name = 'DIPROPYLENE GLYCOL'
LEFT OUTER JOIN product ON relation.product = product.id
LEFT OUTER JOIN substance ON relation.substance = substance.id
;
AutoIt
创建(并将记录插入)单个 table 并查询它的示例:
#include <SQLite.au3>
#include <SQLite.dll.au3>
#include <Array.au3>
Global Const $g_iRecords = 50
Global Const $g_sFileDb = @ScriptDir & '\example.sqlite'
Global $g_aCreate = [ _
'CREATE TABLE IF NOT EXISTS example (id INTEGER PRIMARY KEY, name TEXT UNIQUE);' & @LF, _
'--CREATE INDEX IF NOT EXISTS index_example_name ON example(name);' & @LF _
]
Global Const $g_sInsert = 'INSERT INTO example (name) VALUES (%i);\n'
Global Const $g_sTransact1 = 'BEGIN TRANSACTION;' & @LF
Global Const $g_sTransact2 = 'END TRANSACTION;' & @LF
Global Const $g_sQuery = 'SELECT * FROM example ORDER BY id ASC;'
Global Const $g_sMsgError = 'sqlite.dll not found.' & @LF
Global $g_hDb = 0
Main()
Func Main()
Local $sQuery = ''
Local $iResultCol = 0
Local $iResultRow = 0
Local $aResult
For $i1 = 0 To UBound($g_aCreate, 1) -1
$sQuery &= $g_aCreate[$i1]
Next
For $i1 = 1 To $g_iRecords
$sQuery &= StringFormat($g_sInsert, _SQLite_FastEscape('example' & $i1))
Next
$sQuery = $g_sTransact1 & $sQuery & $g_sTransact2
ConsoleWrite($sQuery)
_SQLite_Startup()
If @error Then
ConsoleWrite($g_sMsgError)
Exit
EndIf
_SQLite_Open($g_sFileDb)
_SQLite_Exec($g_hDb, $sQuery)
_SQLite_GetTable2d($g_hDb, $g_sQuery, $aResult, $iResultRow, $iResultCol)
_SQLite_Close($g_hDb)
_SQLite_Shutdown()
_ArrayDisplay($aResult)
Exit
EndFunc