合并来自不同文件但具有相同列的两个数据工具数据库

合并来自不同文件但具有相同列的两个数据工具数据库

考虑以下示例代码。这不完全是 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会使用一些docDBand的知识。但是,这对于查询构造来说很常见,无论如何都需要一些调整。无论哪种方式,您都必须分别处理每个表以获取信息,无论它们是否具有相同的结构。corrDBdocDBFromTo

合并背后的主要原理是从第一个数据库中逐个读取条目并构造一个“新条目”(以 的形式\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的原因是因为每个字段的值在放入数据库之前必须进行扩展。也就是说,如果您刚刚使用xdef

\DTLnewdbentry{docDBcorrDB}{RowID}{\docDBRowID}

第一条记录的字段RowID将具有值\docDBRowID,而不是2011.09.26.cd,因为宏\docDBRowID在存储之前未展开;\...xdef确保扩展。使用\protected@xdef确保某些需要(或已经使用)\protection 的宏不会展开。然而,这确实要求构造被一个\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}%
}

相关内容