php - 左连接 3 个表

标签 php mysql sql sql-server database

我有 3 个不同的表(表 1、表 2、表 3),我需要执行百分比和频率运算并输出一个 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       | 

我需要放一张看起来像这样的 table

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"; 

最佳答案

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

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 显示空值?

要解决此问题,无论何时从表 1 中进行选择,都应在 SQL 测试 NULL 中添加一个 WHERE 子句。假设您不想在 CatCodes1 字段上使用 NULL 值,它会像这样:

SELECT [whatever]
FROM Table1
WHERE CatCodes1 IS NOT NULL

能否请您向我解释一下查询在做什么?与 case 语句、交叉连接一样,我们有 4 个左外部连接。

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

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

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

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

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

关于php - 左连接 3 个表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25674066/

相关文章:

php - 使用 PHPUnit 对 Doctrine 对象进行单元测试

javascript - 使用sequelize从两个模型表获取数据

mysql - 不能在 mysql 中创建表,因为它们都相互依赖?

mysql - SQL 查询 - 使用带有限制的 SUM 函数进行选择

java - Mysql查询组装

php - 将 Composer 与私有(private) VCS 一起使用时,它会无限请求授权

java - 通过android和php向mysql数据库插入空白记录

php - 按列值对 MySQL 结果进行排序

php - 了解数据库表的 JSON 输出

sql - 管理分层数据 "error :REPEAT' 不是可识别的内置函数名称。”