【问题标题】:Left Join 3 Tables左连接 3 个表
【发布时间】:2014-10-29 17:02:24
【问题描述】:

我得到了 3 个不同的表(table1,table2,table3),我需要执行百分比和频率操作并输​​出一个 HTML 表。

表1

CatCodes1 | CatCodes2 | CatCodes3
----------+-----------+----------
75287     | 20220     | 65656
78922     | 20852     | 56666
75287     | 20220     | 62892
78922     | 20852     | 55665

表 2:应该只提取测试结果 =1

AllCatCodes  | Tested
-------------+---------
75287        |  1
78922        |  0
75287        |  0
78922        |  0
20220        |  1
62892        |  1
20852        |  NULL
65656        |  1

表 3

CodesCatAll | 
------------+
75287       |  
56666       |  
65656       |  
20220       | 

我需要输出一张像这样的表格

CatCode1(tab1) | % of CatCode(tab1) | Freq in All CatCode(tab2) | Percentage(tab2) | Freq in CodesCatAll(tab3) | Percentage(tab3) |
   75287
   78922     
   78992      
   Total          100%                     xxx                        100%            yyy                             100%                      

以下是我为获取 catcode1 和 %of catCode(table1) 而编写的代码。问题是如何添加其他两个表和频率。

$sqlCom = "select CatCodes1, CAST(count(*) * 100.0 / sum(count(*)) over()"; 
$sqlCom .= " AS DECIMAL(18,2)) from table1 group by CatCodes1"; 

【问题讨论】:

标签: php mysql sql sql-server database


【解决方案1】:

让我们试试这个。您需要将计算作为子查询进行。此外,您需要一个内部查询来计算数据集中包含多少条记录。然后有一个外部查询将所有内容连接在一起。

Original SQL Fiddle HERE.
Updated SQL Fiddle HERE.
Third updated SQL Fiddle HERE.

SELECT t1.CatCodes1 AS 'CatCode1(tab1)', t1.myPercent AS '% of CatCode(tab1)',
  ISNULL(t2.CountOfAllCatCodes, 0) AS 'Freq in All CatCode(tab2)',
  CASE 
    WHEN ttl.t2Ttl = 0 THEN 0
    ELSE CAST(ISNULL(t2.CountOfAllCatCodes, 0) * 100.0/ttl.t2Ttl AS DECIMAL(18,2))
  END AS 'Percentage(tab2)',
  ISNULL(t3.CountOfCodesCatAll, 0) AS 'Freq in CodesCatAll(tab3)',
  CASE 
    WHEN ttl.t3Ttl = 0 THEN 0
    ELSE CAST(ISNULL(t3.CountOfCodesCatAll, 0) * 100.0/ttl.t3Ttl AS DECIMAL(18,2))
  END AS 'Percentage(tab3)'
FROM (
  SELECT CatCodes1, CAST(COUNT(*) * 100.0 / SUM(COUNT(*)) OVER() AS DECIMAL(18,2)) AS myPercent
  FROM table1
  GROUP BY CatCodes1
) t1
LEFT OUTER JOIN (
  SELECT AllCatCodes, COUNT(*) AS CountOfAllCatCodes, CAST(COUNT(*) * 100.0 / SUM(COUNT(*)) OVER() AS DECIMAL(18,2)) AS myPercent2
  FROM table2
  WHERE ISNULL(Tested, 0) = 1
  GROUP BY AllCatCodes
) t2 ON t1.CatCodes1 = t2.AllCatCodes
LEFT OUTER JOIN (
  SELECT CodesCatAll, COUNT(*) AS CountOfCodesCatAll, CAST(COUNT(*) * 100.0 / SUM(COUNT(*)) OVER() AS DECIMAL(18,2)) AS myPercent3
  FROM table3
  GROUP BY CodesCatAll
) t3 ON t1.CatCodes1 = t3.CodesCatAll
CROSS JOIN (
  --Calculate total records which are matched...
  SELECT SUM(ISNULL(t2.CountOfAllCatCodes, 0)) as t2Ttl, SUM(ISNULL(t3.CountOfCodesCatAll, 0)) AS t3Ttl
  FROM (
    SELECT CatCodes1
    FROM table1
    GROUP BY CatCodes1
  ) t1
  LEFT OUTER JOIN (
    SELECT AllCatCodes, COUNT(*) AS CountOfAllCatCodes
    FROM table2
    WHERE ISNULL(Tested, 0) = 1
    GROUP BY AllCatCodes
  ) t2 ON t1.CatCodes1 = t2.AllCatCodes
  LEFT OUTER JOIN (
    SELECT CodesCatAll, COUNT(*) AS CountOfCodesCatAll
    FROM table3
    GROUP BY CodesCatAll
  ) t3 ON t1.CatCodes1 = t3.CodesCatAll
) ttl

注意:由于某种原因,SQL Fiddle 将“百分比(tab2)”字段计算为零。我已经上下检查了代码,找不到我的错误,正如您所见,'Percentage(tab3)' 的编写方式完全相同并且评估正确。您还可以看到 CountOfAllCatCodes 的计算结果为 2,而 ttl.t2Ttl 为 4,结果应该是 50%。所以,我不知道。

要填写页面上的 xxx 和 yyy 字段,请在构建表格时保留运行总计,或分别引用 t2Ttl 和 t3Ttl 字段。

编辑:我知道为什么有些百分比返回零。这是一个假定的类型转换问题。注意百分比的原始计算是这样的:

ISNULL(t2.CountOfAllCatCodes, 0)/ttl.t2Ttl * 100.0

所以,整数/整数 * 小数 --> [截断整数] * 小数 --> 小数。
或者,使用数字:2/4 * 100.0 --> 0 * 100.0 --> 0。

通过稍微切换公式,我改变了假设的数据类型:

ISNULL(t2.CountOfAllCatCodes, 0) * 100.0/ttl.t2Ttl

或者,如果我们愿意,我们可以在公式上使用 CAST 或 CONVERT 语句使其显式化。

回答您在评论中提出的问题:

如何阻止空值从表 1 中显示?

为了解决这个问题,无论何时从 Table1 中进行选择,都可以在 SQL 中添加一个 WHERE 子句来测试 NULL。假设您不希望 CatCodes1 字段上的 NULL 值,它会是这样的:

SELECT [whatever]
FROM Table1
WHERE CatCodes1 IS NOT NULL

你能解释一下查询在做什么吗?就像 case 语句、交叉连接一样,我们有 4 个左外连接。

现在您正在学习基本的 SQL 理论,这可能超出了原始问题的范围,但这里是:

CASE 语句用于根据各种条件评估字段的多种可能性。请参阅 CASE 声明中的 this link for Microsoft's documentation。在这种情况下,我使用 CASE 语句来防止“除以零”错误。您会看到,如果分母值 EVER 有可能为零,我们希望通过在实际执行计算之前测试零来确保防止此错误。如果可用,我将只使用 IF 类型语句:如果分母为零,则返回零,否则为分子/分母。由于 SQL 没有内联 IF 语句,因此我们使用 CASE 语句。

CROSS JOIN 是您需要非常小心的事情,但在这种情况下是合适的。我可以轻松计算出每个表中有多少条记录与 t1.CatCodes1 匹配,并且我可以轻松地计算出 t2 和 t3 表中存在多少条记录,但是我无法获得准确的 匹配 条记录数只要。为了解决这个问题,我做了一个单独的查询,只计算匹配的记录(ttl 表)。然后我 CROSS JOIN 到这个表,这样我们查询中的每一行都可以访问计算。 ttl 表作为分母计算匹配记录总数的百分比。

LEFT OUTER JOIN 用于获取一个表中的所有行,并且只获取第二个表中匹配的行。老实说,在这种情况下,我猜测这是否是正确的加入。它比 INNER JOIN 安全一点,因为只要记录存在于我们的主表中,我们就会在数据集中看到结果。但是,如果我们使用 INNER JOIN,则 ID 需要存在于所有三个表中才能显示在我们的结果中。你可以找到更多info about LEFT OUTER JOINS here...

如果您需要关于 SQL 正在做什么的任何其他解释,请告诉我...

【讨论】:

  • 是的,由于某种原因,我没有得到两个表的百分比。有点怪。我的 SQL 技能很低。试图获得它们,但可以在一夜之间得到它们:(
  • 我找出了零的原因并更新了代码。这应该可以帮助您解决问题。
  • 哇,你真是个天才。是的,我有几个问题。这些 ttl.t2Ttl 是什么,它们到底在做什么?此外,百分比不四舍五入到小数点后 2 位。还有两列具有相同的值,它们的用途是什么?另外,我们是否在表 2 中使用了经过测试的 = 1 条件?就像测试的地方 = 1
  • 天才有点多。我敢肯定有一些真正的天才可以用三行之类的方式解决这个问题。
  • 无论如何,对于您的问题:您说百分比字段不应基于 2 和 3 表中所有记录的计数,而应仅基于 2 和 3 表中的 MATCHING 记录。因此,ttl.t2Ttl 字段的工作是确定 Table2 中有多少记录匹配,以便我们可以得到一个准确的百分比,加起来是 100%。最后的列(来自 ttl.*)仅用于测试目的,因为我试图弄清楚为什么计算返回为零,而我知道它不应该是。
【解决方案2】:

我相信这会解决问题...您需要将计算作为子查询进行,并有一个外部查询将所有内容连接在一起。

SQL Fiddle here.

SELECT t1.CatCodes1 AS 'CatCode1(tab1)', t1.myPercent AS '% of CatCode(tab1)',
  ISNULL(t2.CountOfAllCatCodes, 0) AS 'Freq in All CatCode(tab2)', ISNULL(t2.myPercent, 0) AS 'Percentage(tab2)',
  ISNULL(t3.CountOfCodesCatAll, 0) AS 'Freq in CodesCatAll(tab3)', ISNULL(t3.myPercent, 0) AS 'Percentage(tab3)'
FROM (
  SELECT CatCodes1, CAST(COUNT(*) * 100.0 / SUM(COUNT(*)) OVER() AS DECIMAL(18,2)) AS myPercent
  FROM table1
  GROUP BY CatCodes1
) t1
LEFT OUTER JOIN (
  SELECT AllCatCodes, COUNT(*) AS CountOfAllCatCodes, CAST(COUNT(*) * 100.0 / SUM(COUNT(*)) OVER() AS DECIMAL(18,2)) AS myPercent
  FROM table2
  GROUP BY AllCatCodes
) t2 ON t1.CatCodes1 = t2.AllCatCodes
LEFT OUTER JOIN (
  SELECT CodesCatAll, COUNT(*) AS CountOfCodesCatAll, CAST(COUNT(*) * 100.0 / SUM(COUNT(*)) OVER() AS DECIMAL(18,2)) AS myPercent
  FROM table3
  GROUP BY CodesCatAll
) t3 ON t1.CatCodes1 = t3.CodesCatAll

【讨论】:

  • 使用所有 CatCode(tab2) 中的 Freq 时,tab2 的百分比应加起来为 100%。使用 CodesCatAll(tab3) 中的 Freq 在 tab3 中的百分比(加起来为 100%)也是如此。抱歉,如果不清楚。我稍微编辑了我的问题,以便清楚
  • 另外我如何获得最后一行的 xxx 和 yyy
  • 那么“百分比(tab2)”中的百分比不应该包括Table2中的所有行,而应该只包括Table2中的JOINED行?嗯,这更复杂。
  • 是的,它只会包含 table1 共有的行。
【解决方案3】:

看看这个页面http://sqlpro.developpez.com/cours/sqlaz/jointures/ 很抱歉,它是法语的,但阅读包含“join”的代码可能会对您有所帮助。

起初,只是尝试提取 3 个表上的数据,而不进行任何计算。 并显示:

echo '<pre>';
print_r($result);
echo '</pre>';

然后当结果表ok时,添加计算。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-31
    • 2014-02-04
    • 1970-01-01
    • 1970-01-01
    • 2019-03-29
    • 1970-01-01
    相关资源
    最近更新 更多