让我们试试这个。您需要将计算作为子查询进行。此外,您需要一个内部查询来计算数据集中包含多少条记录。然后有一个外部查询将所有内容连接在一起。
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 正在做什么的任何其他解释,请告诉我...