【问题标题】:SQLite can't find a way to avoid Cartesian ProductSQLite 找不到避免笛卡尔积的方法
【发布时间】:2013-10-15 13:57:27
【问题描述】:

我正在编写一个查询,在其中计算 2 个不同表的总和,这些表具有外键约束 (1:n)。

所以有一张桌子Kunde 持有客户。每个Customer 都由Adm 维护。每个Kunde 有N 个不同的事务(PbsRow),而每个事务包含N 个不同的产品(WarengruppeVK)。每笔交易都有一个月和一年(MonatJahr

我需要的是包含以下信息的结果: 1) Adm 的名称,2) 2013 年属于该特定 Adm 的客户之一的所有 sollfrachthandling 值的总和,3) 属于的所有 nettodb_basis 值的总和该客户在 2013 年的 PbsRows 之一,4 和 5) 与 2) 和 3) 仅在 2012 年相同

我已经尝试了不同的方法,但是当我使用下一个表进行联接时,我总是得到一个具有 sollfrachthandling 值的笛卡尔积。

请看我的查询:

SELECT vj.*,
       j.*,
       adm.ZNAME
FROM ZADM adm,
  (SELECT k.ZADMITARBEITER AS admidvj,
          SUM(vk.ZNETTO) AS summeVJ,
          SUM(vk.ZDB_BASIS) AS summeDBVJ,
          SUM(p.ZSOLLFRACHT) AS sollfrachtVJ,
          SUM(p.ZHANDLING) AS handlingVJ
   FROM ZWARENGRUPPEVK vk
   LEFT JOIN ZPBSROW p ON p.Z_PK=vk.ZPBSROW
   LEFT JOIN ZKUNDE k ON k.Z_PK=p.ZKUNDE
   WHERE ZJAHR=2012
     AND ZMONAT>=1
     AND ZMONAT<=6
   GROUP BY k.ZADMITARBEITER) vj,
  (SELECT k.ZADMITARBEITER AS admidj,
          SUM(vk.ZNETTO) AS summeJ,
          SUM(vk.ZDB_BASIS) AS summeDBJ,
          SUM(p.ZSOLLFRACHT) AS sollfrachtJ,
          SUM(p.ZHANDLING) AS handlingJ
   FROM ZWARENGRUPPEVK vk
   LEFT JOIN ZPBSROW p ON p.Z_PK=vk.ZPBSROW
   LEFT JOIN ZKUNDE k ON k.Z_PK=p.ZKUNDE
   WHERE ZJAHR=2013
     AND ZMONAT>=1
     AND ZMONAT<=6
   GROUP BY k.ZADMITARBEITER) j
WHERE vj.admidvj=j.admidj
  AND vj.admidvj=adm.Z_PK

我可以做些什么来避免这个笛卡尔积?当我从结果中删除 WarengruppeVK-table 时,sollfrachthandling 的值是正确的。

提前致谢。

编辑: 以下是一些示例。

这是我从上面的查询中得到的结果:

这是我删除第一个连接时的结果:

您会注意到 sollfrachtVJhandlingVJ 现在不同了。它们取自笛卡尔积发生的PbsRow。所以这2个值实际上是正确的,但我还需要我注释掉的2个值的总和。

这是我删除那个 Join 后的 SQL 语句:

SELECT vj.*,
       j.*,
       adm.ZNAME
FROM ZADM adm,
  (SELECT k.ZADMITARBEITER AS admidvj,
          --          SUM(vk.ZNETTO) AS summeVJ,
--          SUM(vk.ZDB_BASIS) AS summeDBVJ,

          SUM(p.ZSOLLFRACHT) AS sollfrachtVJ,
          SUM(p.ZHANDLING) AS handlingVJ
   FROM -- ZWARENGRUPPEVK vk
 ZPBSROW p -- LEFT JOIN ZPBSROW p ON p.Z_PK=vk.ZPBSROW

   LEFT JOIN ZKUNDE k ON k.Z_PK=p.ZKUNDE
   WHERE ZJAHR=2012
     AND ZMONAT>=1
     AND ZMONAT<=6
   GROUP BY k.ZADMITARBEITER) vj,
  (SELECT k.ZADMITARBEITER AS admidj,
          SUM(vk.ZNETTO) AS summeJ,
          SUM(vk.ZDB_BASIS) AS summeDBJ,
          SUM(p.ZSOLLFRACHT) AS sollfrachtJ,
          SUM(p.ZHANDLING) AS handlingJ
   FROM ZWARENGRUPPEVK vk
   LEFT JOIN ZPBSROW p ON p.Z_PK=vk.ZPBSROW
   LEFT JOIN ZKUNDE k ON k.Z_PK=p.ZKUNDE
   WHERE ZJAHR=2013
     AND ZMONAT>=1
     AND ZMONAT<=6
   GROUP BY k.ZADMITARBEITER) j
WHERE vj.admidvj=j.admidj
  AND vj.admidvj=adm.Z_PK

编辑 2

好的,这是包含正确结果的 SQL 语句,但缺少 4 列。

SELECT vj.*,
       j.*,
       adm.ZNAME
FROM ZADM adm,
  (SELECT k.ZADMITARBEITER AS admidvj,
          SUM(p.ZSOLLFRACHT) AS sollfrachtVJ,
          SUM(p.ZHANDLING) AS handlingVJ
   FROM ZPBSROW p
   LEFT JOIN ZKUNDE k ON k.Z_PK=p.ZKUNDE
   WHERE ZJAHR=2012
     AND ZMONAT>=1
     AND ZMONAT<=6
   GROUP BY k.ZADMITARBEITER) vj,
  (SELECT k.ZADMITARBEITER AS admidj,
          SUM(p.ZSOLLFRACHT) AS sollfrachtJ,
          SUM(p.ZHANDLING) AS handlingJ
   FROM ZPBSROW p
   LEFT JOIN ZKUNDE k ON k.Z_PK=p.ZKUNDE
   WHERE ZJAHR=2013
     AND ZMONAT>=1
     AND ZMONAT<=6
   GROUP BY k.ZADMITARBEITER) j
WHERE vj.admidvj=j.admidj
  AND vj.admidvj=adm.Z_PK

如您所见,summeJsummeVJsummeDBJsummeDBVJ 不包括在内,这就是问题所在。此结果中的所有值都是正确的,但我的结果中还需要包含这 4 个值。我上面结果的第一个屏幕截图包含正确的 summeJsummeVJsummeDBJsummeDBVJ 值,但不正确的 handlingJhandlingVJsollfrachtJsollfrachtVJ 值。

编辑 3:

我终于找到了一种方法来做到这一点。这是有效的查询。这只是几个子查询:

    SELECT ((summeJ-summeVJ)/summeVJ*100) AS abwNetto,
       (summeJ-summeVJ) AS abwNettoAbs,
       ((summeDBJ-summeDBVJ)/summeDBVJ*100) AS abwDB,
       (summeDBJ-summeDBVJ) AS abwDBAbs,
       t0.*,
       t1.*,
       adm.ZNAME
FROM ZADM adm,
  (SELECT vj.*,
          j.*
   FROM
     (SELECT k.ZADMITARBEITER AS admidvj,
             SUM(p.ZSOLLFRACHT) AS sollfrachtVJ,
             SUM(p.ZHANDLING) AS handlingVJ
      FROM ZPBSROW p
      LEFT JOIN ZKUNDE k ON k.Z_PK=p.ZKUNDE
      WHERE ZJAHR=2012
        AND ZMONAT>=1
        AND ZMONAT<=6
      GROUP BY k.ZADMITARBEITER) vj
   LEFT JOIN
     (SELECT k.ZADMITARBEITER AS admidj,
             SUM(p.ZSOLLFRACHT) AS sollfrachtJ,
             SUM(p.ZHANDLING) AS handlingJ
      FROM ZPBSROW p
      LEFT JOIN ZKUNDE k ON k.Z_PK=p.ZKUNDE
      WHERE ZJAHR=2013
        AND ZMONAT>=1
        AND ZMONAT<=6
      GROUP BY k.ZADMITARBEITER) j ON vj.admidvj = j.admidj) t0,
  (SELECT vj.*,
          j.*
   FROM
     (SELECT k.ZADMITARBEITER AS admidvj,
             SUM(vk.ZNETTO) AS summeVJ,
             SUM(vk.ZDB_BASIS) AS summeDBVJ
      FROM ZPBSROW p
      LEFT JOIN ZWARENGRUPPEVK vk ON vk.ZPBSROW=p.Z_PK
      LEFT JOIN ZKUNDE k ON k.Z_PK=p.ZKUNDE
      WHERE ZJAHR=2012
        AND ZMONAT>=1
        AND ZMONAT<=6
      GROUP BY k.ZADMITARBEITER) vj
   LEFT JOIN
     (SELECT k.ZADMITARBEITER AS admidj,
             SUM(vk.ZNETTO) AS summeJ,
             SUM(vk.ZDB_BASIS) AS summeDBJ
      FROM ZPBSROW p
      LEFT JOIN ZWARENGRUPPEVK vk ON vk.ZPBSROW=p.Z_PK
      LEFT JOIN ZKUNDE k ON k.Z_PK=p.ZKUNDE
      WHERE ZJAHR=2013
        AND ZMONAT>=1
        AND ZMONAT<=6
      GROUP BY k.ZADMITARBEITER) j ON vj.admidvj = j.admidj) t1
WHERE t0.admidvj=t1.admidvj
  AND t0.admidvj=adm.Z_PK

【问题讨论】:

  • 请展示一些示例记录和预期结果。
  • 我添加了一些示例记录:-)。谢谢
  • 你说这些结果是错误的。请显示一些您真正想要的正确结果,以及计算它们的源记录。
  • 好的,我希望这会有所帮助。

标签: sql sqlite cartesian-product


【解决方案1】:

您的连接的问题是所有内容都连接在一起。 您应该改用独立的标量子查询:

SELECT name,
       (SELECT SUM(WarengruppeVK.netto)
        FROM Kunde
        JOIN PbsRow ON Kunde.PK = PbsRow.kunde
        JOIN WarengruppeVK ON PbsRow.PK = WarengruppeVK.pbsrow
        WHERE Kunde.admitarbeiter = Adm.PK
          AND PbsRow.jahr = 2012
       ) AS vj_netto,
       (SELECT SUM(PbsRow.sollfracht)
        FROM Kunde
        JOIN PbsRow ON Kunde.PK = PbsRow.kunde
        WHERE Kunde.admitarbeiter = Adm.PK
          AND PbsRow.jahr = 2012
       ) AS vj_sollfracht
       (SELECT SUM(WarengruppeVK.netto)
        FROM Kunde
        JOIN PbsRow ON Kunde.PK = PbsRow.kunde
        JOIN WarengruppeVK ON PbsRow.PK = WarengruppeVK.pbsrow
        WHERE Kunde.admitarbeiter = Adm.PK
          AND PbsRow.jahr = 2013
       ) AS j_netto,
       (SELECT SUM(PbsRow.sollfracht)
        FROM Kunde
        JOIN PbsRow ON Kunde.PK = PbsRow.kunde
        WHERE Kunde.admitarbeiter = Adm.PK
          AND PbsRow.jahr = 2013
       ) AS j_sollfracht
FROM Adm

【讨论】:

  • 是的,我也想通了,想知道除了分离查询是否还有其他解决方案。谢谢你的回答。
猜你喜欢
  • 1970-01-01
  • 2023-03-06
  • 2017-05-27
  • 2019-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多