搜索多个列表以查找缺少的条目

时间:2008-11-06 09:36:48

标签: sql delphi comparison list

我有3个列表,我会在这里简单说明。

字母列表
一个

C

数字列表
1
2
3

混合
A,1个
A,2
B,2
B,3
C,1个
C,3

我需要知道缺少什么:
A,3
B,1个
C,2

信件清单有大约85个条目
并且数字列表有大约500个条目。

混合列表有大约75,000个条目。

我可以使用数据库查询(mysql 5.0)或Turbo Delphi 2006来处理文本文件。找到缺失的最佳方法是什么?

谢谢,
  戴夫

5 个答案:

答案 0 :(得分:3)

交叉连接会生成每个组合,因为您在SQL表中都有两个列表:

SELECT
  Letter + ',' + Number AS Combination
FROM
  NumberList,
  LetterList

使用组合结果(可能将其保存到临时表中),您可以使用NOT EXISTS查询来查找缺少的内容:

SELECT
  Combination
FROM
  AllCombinations AS a
WHERE
  NOT EXISTS 
  (SELECT 1 FROM MyCombitations AS m WHERE m.Combination = a.Combination)

这需要一个表MyCombitations,它列出了您实际拥有的所有组合,并希望根据完整列表进行检查。

如果你想加快速度,你应该在MyCombitations.Combination字段上使用永久的组合表和索引。对于重复查询,这绝对是可取的。

答案 1 :(得分:2)

无需创建额外的表格。以下查询也可以正常工作:

SELECT c.chr, n.num
FROM chars c, nums n
 WHERE NOT EXISTS (SELECT 1
                     FROM mix m
                    WHERE m.chr = c.chr AND m.num = n.num)

答案 2 :(得分:1)

75.000并不多。将字母列表和数字列表加载到两个单独的TStringLists中。使用适当的维度创建动态数组(索引将是这两个字符串列表的索引)。填补;填写(表格,资料。加载数据并标记数组中的每一行。输出所有未标记的元素。

在伪代码中(未经测试):

var
  i1, i2: integer;
  sl1, sl2: TStringList;
  cross: array of array of boolean;
begin
  // load data into sl1, sl2
  SetLength(cross, sl1.Count, sl2.Count);
  for i1 := 0 to sl1.Count - 1 do
    for i2 := 0 to sl2.Count - 1 do
      cross[i1, i2] := false;
  // for each element in 'combined' list
    // split it into elements s1, s2
    i1 := sl1.IndexOf(s1);
    i2 := sl2.IndexOf(s2);
    if (i1 < 0) or (i2 < 0) then
      // report error
    else
      cross[i1, i2] := true;
  for i1 := 0 to sl1.Count - 1 do
    for i2 := 0 to sl2.Count - 1 do
      if not cross[i1, i2] then
        // output sl1[i1], sl2[i2]
end;

答案 3 :(得分:1)

SELECT letter,number FROM lettersTable l , numbersTable n WHERE
(
    SELECT count(*) 
    FROM 
        (
            SELECT * 
            FROM combinationsTable 
            WHERE l.letter=combinationsTable.letter AND n.number = combinationsTable .number
        ) AS temp
) = 0;

这依赖于SELECT * FROM A,B测试所有组合(隐式交叉连接)。

答案 4 :(得分:1)

如果你可以对数据进行排序(Turbo powers SysTools有一个很好的排序例程,那么你可以使用两个输入列表和一个输出列表在代码中相当快地完成此操作)。这背后的概念很简单:

  1. 取两个列表,按相同方式排序
  2. 如果左侧小于右侧,则右侧缺少该值,因此将其添加到“缺失列表”并增加左侧的光标。
  3. 如果它们相等,则增加两者,
  4. 如果右侧小于左侧,则只增加右侧(可选择添加到“必须删除”列表)。
  5. 这个过程有时被称为“老大师/新大师”过程,并且速度非常快,因为你只能在两个名单上行走一次。

    简单示例:

    var
      ListL : tStringList; // the left list
      ListR : tSTringList; // the right list
      ListA : tSTringList; // the Add List (should start empty)
      ListD : tStringList; // the Delete list (should start empty)
      iCurL : integer;     // Left Cursor
      iCurR : integer;     // Right Cursor
      iRes  : integer;     // result of compare
    begin
      iCurL := 0;
      iCurR := 0;
      ListL := tStringList.create;
      ListR := tSTringList.create;
      ListA := tSTringList.create;
      ListD := tStringList.create;
      InitAndLoadLists(ListL,ListR,ListA,ListD);
      while (iCurL <= ListL.Count-1) and (iCurR <= ListR.Count-1) do
        begin
          iRes := CompareStr(ListL.Strings[iCurL],ListR.Strings[iCurR]);
          if iRes = 0 then
            begin
              inc(iCurL);
              inc(iCurR);
            end;
          if iRes < 0 then
            begin
              ListA.Add(ListL.Strings[iCurL]);
              inc(iCurL);
            end;
          if iRes > 0 then
            begin
              listD.Add(ListR.Strings[iCurR]);
              inc(iCurR);
            end;
        end;
      while (iCurL <= ListL.Count-1) do
        begin
          listA.Add(ListL.Strings[iCurL]);
          inc(iCurL);
        end;
      while (iCurR <= ListR.Count-1) do
        begin
          listD.Add(ListR.Strings[iCurR]);
          inc(iCurR);
        end;
      ShowMessage( 'ADDS' + ^M+^J + ListA.Text);
      ShowMessage( 'DELS' + ^M+^J + ListD.Text);
    end;
    

    以下代码是我用于测试的代码。这只是一个例子,但在现实世界的情况下,我会构建我的密钥,以便他们可以正确排序,正确填充数字,并在适当的情况下强制执行。如果您使用的是turbo power sort例程,则可以使用两种类型而不是两个列表,但最终效果是相同的。

    procedure InitAndLoadLists(ListL, ListR, ListA, ListD: TStringList);
    begin
      ListL.Add('A,1');
      ListL.Add('B,3');
      ListL.Add('C,2');
      ListR.Add('A,2');
      ListR.Add('B,3');
      ListR.Add('C,4');
    end;
    

    编辑:在Delphi 2009中测试代码并且行为正常。