考虑以下示例代码。这不完全是 MWE,因为它包含完全不必要的元素。
我想合并两个 datatool 数据库,corrDB
然后docDB
垂直(按行)合并,然后按键列对它们进行排序RowID
。最后一部分,我想我知道该怎么做,大概。虽然我不确定是否\dtlletterindexcompare
使用正确的比较方法对 xxxx.xx.xx.yy 形式的键进行排序,其中 x 是整数,y 是数字。我不知道是否应该就此提出单独的问题,但无论如何,请随时发表评论。
\documentclass{article}
\usepackage{datatool}
\usepackage{datagidx}
\usepackage{array}
\usepackage{filecontents}
\usepackage{longtable}
\newcounter{tabenum}\setcounter{tabenum}{0}
\newcommand{\colhead}[1]{\multicolumn{1}{>{\bfseries}l}{#1}}
\newcommand{\nextnuml}[1]{\refstepcounter{tabenum}\thetabenum.\label{#1}}
\newcommand*{\checkmissing}[1]{\DTLifnull{#1}{}{#1}}
\newcommand{\PrintDocTable}[3][]{%
% #1 = list of rowIDs
% #2 = database to search
% #3 =caption
\begin{longtable}{r l p{1in} c c p{3.5in}}
\caption{#3}\\
& \colhead{Date} & \colhead{From} & \colhead{To} & \colhead{Subject}\\\hline\endhead
\DTLforeach
[%
\ifblank{#1}{\boolean{true}}{\DTLisSubString{#1}{\RowID}}
]
{#2}{%
\RowID=RowID,%
\Date=Date,%
\From=From,%
\To=To,%
\Subject=Subject%
}{%
\nextnuml{\RowID} & \Date & \checkmissing{\From} & \checkmissing{\To} & \Subject \\
}%
\end{longtable}
}%
\newcommand{\PrintCorrTable}[3][]{%
% #1 = list of rowIDs
% #2 = database to searchc
% #3 =caption
\begin{longtable}{r l p{1.5in} l l p{2.5in}}
\caption{#3}\\
& \colhead{Date} & \colhead{From} & \colhead{To} & \colhead{Subject}\\\hline\endhead
\DTLforeach
[%
\ifblank{#1}{\boolean{true}}{\DTLisSubString{#1}{\RowID}}
]
{#2}{%
\RowID=RowID,%
\Date=Date,%
\From=From,%
\To=To,%
\Subject=Subject%
}{%
\nextnuml{\RowID} & \Date & \From & \To & \Subject \\
}%
\end{longtable}
}%
\begin{document}
\begin{filecontents*}{corr.csv}
2011.09.09.ab, Sep 09 2011, AB, CD , more stuff
2011.09.26.xy, Sep 26 2011, XY, WZ , some more stuff
2011.09.26.ab, Sep 26 2011, AB, CD , yet more stuff
2011.09.09, Sep 09 2011, CD, AB , stuff
\end{filecontents*}
\begin{filecontents*}{doc.csv}
2011.09.26.cd, Sep 26 2011, Doc 1
2011.09.26.ce, Sep 26 2011, Doc 2
2011.09.26.zz, Sep 26 2011, Doc 3
\end{filecontents*}
\DTLloaddb[noheader,keys={RowID,Date,Subject}]{docDB}{doc.csv}
\newtermaddfield[docDB]{From}{From}{}
\newtermaddfield[docDB]{To}{To}{}
\PrintDocTable{docDB}{Documents}
\DTLloaddb[noheader,keys={RowID,Date,From,To,Subject}]{corrDB}{corr.csv}
\dtlsort{RowID}{corrDB}{\dtlletterindexcompare}
\PrintCorrTable{corrDB}{Correspondence}
\end{document}
答案1
合并表格datatool
不受原生支持。您必须在外部处理表格,或者创建一个表示要合并的表格的并集的新表格。下面使用后一种方法:
\documentclass{article}
\usepackage{datatool}
\usepackage{datagidx}
\usepackage{array}
\usepackage{filecontents}
\usepackage{longtable}
\newcounter{tabenum}\setcounter{tabenum}{0}
\newcommand{\colhead}[1]{\multicolumn{1}{>{\bfseries}l}{#1}}
\newcommand{\nextnuml}[1]{\refstepcounter{tabenum}\thetabenum.}
\newcommand*{\checkmissing}[1]{\DTLifnull{#1}{}{#1}}
\newcommand{\PrintDocTable}[3][]{%
% #1 = list of rowIDs
% #2 = database to search
% #3 = caption
\begin{longtable}{r l p{1in} c c p{3.5in}}
\caption{#3} \\
& \colhead{Date} & \colhead{From} & \colhead{To} & \colhead{Subject} \\
\hline
\endhead
\DTLforeach
[%
\ifblank{#1}{\boolean{true}}{\DTLisSubString{#1}{\RowID}}
]
{#2}{%
\RowID=RowID,%
\Date=Date,%
\From=From,%
\To=To,%
\Subject=Subject%
}{%
\nextnuml{\RowID} & \Date & \checkmissing{\From} & \checkmissing{\To} & \Subject \\
}%
\end{longtable}
}%
\newcommand{\PrintCorrTable}[3][]{%
% #1 = list of rowIDs
% #2 = database to searchc
% #3 = caption
\begin{longtable}{r l p{1.5in} l l p{2.5in}}
\caption{#3} \\
& \colhead{Date} & \colhead{From} & \colhead{To} & \colhead{Subject} \\
\hline
\endhead
\DTLforeach
[%
\ifblank{#1}{\boolean{true}}{\DTLisSubString{#1}{\RowID}}
]
{#2}{%
\RowID=RowID,%
\Date=Date,%
\From=From,%
\To=To,%
\Subject=Subject%
}{%
\nextnuml{\RowID} & \Date & \From & \To & \Subject \\
}%
\end{longtable}
}%
\begin{document}
\begin{filecontents*}{corr.csv}
2011.09.09.ab, Sep 09 2011, AB, CD , more stuff
2011.09.26.xy, Sep 26 2011, XY, WZ , some more stuff
2011.09.26.ab, Sep 26 2011, AB, CD , yet more stuff
2011.09.09, Sep 09 2011, CD, AB , stuff
\end{filecontents*}
\begin{filecontents*}{doc.csv}
2011.09.26.cd, Sep 26 2011, Doc 1
2011.09.26.ce, Sep 26 2011, Doc 2
2011.09.26.zz, Sep 26 2011, Doc 3
\end{filecontents*}
\DTLloaddb[noheader,keys={RowID,Date,Subject}]{docDB}{doc.csv}
\newtermaddfield[docDB]{From}{From}{}
\newtermaddfield[docDB]{To}{To}{}
\PrintDocTable{docDB}{Documents}
\DTLloaddb[noheader,keys={RowID,Date,From,To,Subject}]{corrDB}{corr.csv}
\dtlsort{RowID}{corrDB}{\dtlletterindexcompare}
\PrintCorrTable{corrDB}{Correspondence}
\makeatletter
% Merge two tables
\DTLnewdb{docDBcorrDB}% Create new merged table
% Read all entries from docDB and insert into docDBcorrDB
\DTLforeach*{docDB}{\docDBRowID=RowID,\docDBDate=Date,\docDBSubject=Subject}{
\DTLnewrow{docDBcorrDB}
{\let\DTLnewdbentry\relax% Avoid expansion of \DTLnewdbentry when using \protected@xdef below
\protected@xdef\insertnewdbentry{%
\DTLnewdbentry{docDBcorrDB}{RowID}{\docDBRowID}%
\DTLnewdbentry{docDBcorrDB}{Date}{\docDBDate}%
\DTLnewdbentry{docDBcorrDB}{Subject}{\docDBSubject}%
}}\insertnewdbentry
}
% Read all entries from corrDB and insert into docDBcorrDB
\DTLforeach*{corrDB}{\corrDBRowID=RowID,\corrDBDate=Date,\corrDBFrom=From,\corrDBTo=To,\corrDBSubject=Subject}{
\DTLnewrow{docDBcorrDB}
{\let\DTLnewdbentry\relax% Avoid expansion of \DTLnewdbentry when using \protected@xdef below
\protected@xdef\insertnewdbentry{%
\DTLnewdbentry{docDBcorrDB}{RowID}{\corrDBRowID}%
\DTLnewdbentry{docDBcorrDB}{Date}{\corrDBDate}%
\DTLnewdbentry{docDBcorrDB}{From}{\corrDBFrom}%
\DTLnewdbentry{docDBcorrDB}{To}{\corrDBTo}%
\DTLnewdbentry{docDBcorrDB}{Subject}{\corrDBSubject}%
}}\insertnewdbentry
}
\makeatother
% Sort database
\dtlsort{RowID}{docDBcorrDB}{\dtlletterindexcompare}
% Print new merged table
\begin{longtable}{r l p{1.5in} l l p{2.5in}}
\caption{Merge table (Documents + Correspondence)} \\
& \colhead{Date} & \colhead{From} & \colhead{To} & \colhead{Subject} \\
\hline
\endhead
\DTLforeach
{docDBcorrDB}{%
\RowID=RowID,%
\Date=Date,%
\From=From,%
\To=To,%
\Subject=Subject%
}{%
\nextnuml{\RowID} & \Date & \checkmissing{\From} & \checkmissing{\To} & \Subject \\
}%
\end{longtable}
\end{document}
当然,由于没有and/or字段,因此数据库的构建docDBcorrDB
会使用一些docDB
and的知识。但是,这对于查询构造来说很常见,无论如何都需要一些调整。无论哪种方式,您都必须分别处理每个表以获取信息,无论它们是否具有相同的结构。corrDB
docDB
From
To
合并背后的主要原理是从第一个数据库中逐个读取条目并构造一个“新条目”(以 的形式\insertnewdbentry
)。让我们看看这是如何执行的。以下是第一个表的主要构造(带有行号):
1: \DTLforeach*{docDB}{\docDBRowID=RowID,\docDBDate=Date,\docDBSubject=Subject}{
2: \DTLnewrow{docDBcorrDB}
3: {\let\DTLnewdbentry\relax% Avoid expansion of \DTLnewdbentry when using \protected@xdef below
4: \protected@xdef\insertnewdbentry{%
5: \DTLnewdbentry{docDBcorrDB}{RowID}{\docDBRowID}%
6: \DTLnewdbentry{docDBcorrDB}{Date}{\docDBDate}%
7: \DTLnewdbentry{docDBcorrDB}{Subject}{\docDBSubject}%
8: }}\insertnewdbentry
9: }
我们使用 循环遍历每个条目(第 1 行)\DTLforeach
。使用带星号的版本是因为数据库只能读取,不能写入。每个字段都分配给特定的宏(字段RowID
将分配给\docDBRowID
,...)。对于读取的每条记录,我们在合并的数据库中创建一个新记录(第 2 行)。下一个块(第 3-8 行)旨在将单个记录(在本例中包含 3 个不同的字段)添加到新的合并表中。它\insertnewdbentry
在组内创建。但是,由于它是使用 创建的,因此实际定义将是全局的。使用扩展初始化\...xdef
的原因是因为每个字段的值在放入数据库之前必须进行扩展。也就是说,如果您刚刚使用x
def
\DTLnewdbentry{docDBcorrDB}{RowID}{\docDBRowID}
第一条记录的字段RowID
将具有值\docDBRowID
,而不是2011.09.26.cd
,因为宏\docDBRowID
在存储之前未展开;\...xdef
确保扩展。使用\protected@xdef
确保某些需要(或已经使用)\protect
ion 的宏不会展开。然而,这确实要求构造被一个\makeatletter
...\makeatother
一对。现在棘手的部分是展开\docDBRowID
但不展开\DTLnewdbentry
... 解决这个问题的简单方法是将其设置为\relax
(第 3 行)。这样 a\protected@xdef
就不会展开它(因为\relax
不可扩展)但它会展开\docDBRowID
。当组关闭时(第 8 行),的值\DTLnewdbentry
将恢复到它原本应该的值。因此,\insertnewdbentry
将包含 的扩展版本\docDBRowID
,\docDBDate
并且\docDBSubject
保持\DTLnewdbentry
完整。最后,在\insertnewdbentry
构造之后,它被执行(仍然是第 8 行)现在将正确的值插入新数据库。
对第一个数据库以及第二个数据库中的每个记录重复此过程。
最终docDBcorrDB
构建的数据库将像任何其他数据库一样进行处理。
这datatool
用户指南在第 38 页提到了有关此扩展问题的一些内容,但也提供了一种解决方法(上面未包括)。设置布尔开关\dtlexpandnewvalue
将确保值被扩展前它们被插入到数据库中。使用这种方法,如果你使用
\dtlexpandnewvalue% Values to be inserted into database should be expanded first
% Merge two tables
\DTLnewdb{docDBcorrDB}% Create new merged table
% Read all entries from docDB and insert into docDBcorrDB
\DTLforeach*{docDB}{\docDBRowID=RowID,\docDBDate=Date,\docDBSubject=Subject}{
\DTLnewrow{docDBcorrDB}
\DTLnewdbentry{docDBcorrDB}{RowID}{\docDBRowID}%
\DTLnewdbentry{docDBcorrDB}{Date}{\docDBDate}%
\DTLnewdbentry{docDBcorrDB}{Subject}{\docDBSubject}%
}
% Read all entries from corrDB and insert into docDBcorrDB
\DTLforeach*{corrDB}{\corrDBRowID=RowID,\corrDBDate=Date,\corrDBFrom=From,\corrDBTo=To,\corrDBSubject=Subject}{
\DTLnewrow{docDBcorrDB}
\DTLnewdbentry{docDBcorrDB}{RowID}{\corrDBRowID}%
\DTLnewdbentry{docDBcorrDB}{Date}{\corrDBDate}%
\DTLnewdbentry{docDBcorrDB}{From}{\corrDBFrom}%
\DTLnewdbentry{docDBcorrDB}{To}{\corrDBTo}%
\DTLnewdbentry{docDBcorrDB}{Subject}{\corrDBSubject}%
}