【问题标题】:SQL about join tables关于连接表的 SQL
【发布时间】:2019-09-16 11:53:44
【问题描述】:

有 2 个表 - table1 和 table2 我想知道相应范围内的等级的计数数

表1

╔════╦═════╗
║ id ║ val ║
╠════╬═════╣
║  1 ║ 80  ║
║  2 ║ 75  ║
║  3 ║ 72  ║
║  4 ║ 85  ║
║  5 ║ 70  ║
║  6 ║ 80  ║
║  7 ║ 76  ║
╚════╩═════╝

表2

╔═══════╦══════════╗
║ grade ║ boundary ║
╠═══════╬══════════╣
║  A    ║ 85       ║
║  B    ║ 80       ║
║  C    ║ 75       ║
║  D    ║ 70       ║
║  E    ║ 65       ║
║  F    ║  0       ║
╚═══════╩══════════╝

我怎样才能得到这样的结果:

╔═══════╦════════╗
║ grade ║ total  ║
╠═══════╬════════╣
║  A    ║ 1      ║
║  B    ║ 2      ║
║  C    ║ 2      ║
║  D    ║ 2      ║
║  E    ║ 0      ║
║  F    ║ 0      ║
╚═══════╩════════╝

我以前用 PHP 做,但我只想用 SQL 做 我不熟悉复杂的连接语句。

【问题讨论】:

  • 能否请您发布您已经尝试过的 SQL,以便我们可以帮助您找到不工作的地方?如果您一般都在为 JOIN 苦苦挣扎,请查看the w3schools page on this topic

标签: mysql sql join group-by


【解决方案1】:
select table2.grade, ifnull(total, 0) as total from table2 left join (
    select grade, count(*) as total from (
        select table2.grade from table1 join table2
        on table2.boundary = (select max(boundary) from table2 where boundary <= table1.val)
    ) sq
    group by grade
) sq on table2.grade = sq.grade
order by grade;

See DB Fiddle

【讨论】:

  • 我也喜欢这个答案!
【解决方案2】:

是的,这是非常可行的。我个人会更改 table2 结构以包含上限和下限。

假设您不能这样做,此解决方案使用允许直接边界的 CTE 进行模拟。我还使用了一个子查询来显示没有人口的成绩——如果你不关心零记录的行,你可以忽略这一点。

这是 SQL Server 语法 (http://sqlfiddle.com/#!18/f1e9b/1),但原理应该适用于大多数 RDBMS :) 享受

--setup
create table scores (

  id integer,
  val integer
  );

create table boundaries (

  grade varchar(max),
  boundary integer
  );

INSERT INTO scores values (1,80);
INSERT INTO scores values (2,75);
INSERT INTO scores values (3,72);
INSERT INTO scores values (4,85);
INSERT INTO scores values (5,70);
INSERT INTO scores values (6,80);
INSERT INTO scores values (7,76);

INSERT INTO boundaries values ('A',85);
INSERT INTO boundaries values ('B',80);
INSERT INTO boundaries values ('C',75);
INSERT INTO boundaries values ('D',70);
INSERT INTO boundaries values ('E',65);
INSERT INTO boundaries values ('F',0);

--query
with rangesCTE as (
SELECT 
  grade
  , boundary as lowerBoundary
  , coalesce (LAG (boundary,1) OVER (ORDER BY boundary desc),100) AS higherBoundary
FROM boundaries)

select 
  boundaries.grade
  , coalesce (sq.total,0) as total
from boundaries 
left join (
  select 
    rangesCTE.grade as grade
    , count(*) as total
  from scores
  left join rangesCTE on scores.val >= rangesCTE.lowerBoundary and scores.val < rangesCTE.higherBoundary
  group by rangesCTE.grade
) sq on boundaries.grade = sq.grade

【讨论】:

  • 最后我添加了upper_boundary这一列 虽然Ronald的解决方案很好,但是处理时间太慢了。
  • 谢谢,我很高兴能帮上忙 :) 如果您最终使用此功能,请随时投票或接受我的回答!我喜欢 Ronald 的回答,但有时更多的代码和更好的设置意味着更好的性能/结果!
  • 但 CTE 仅在 MySql 8.0 中受支持,我没有让自己对 CTE 可用性做出任何假设。
  • 好点罗纳德 - 无论哪种方式,我认为海报更改 DDL 是正确的(假设他可以!)这是这里最快的方式 - 肯定比领先/落后更快。当然,您实际上并不需要 CTE,您当然也可以使用子查询,但是任何需要计算的东西都比只需要读取的东西要慢 :)
【解决方案3】:

这可以使用简单的右连接来完成。

SELECT t2.grade,count(t1.val) FROM table1 t1
right join table2 t2
on t1.val=t2.boundary
GROUP by t2.grade,t1.val
order by t2.grade ASC

1- 下面的代码只会加入表格并选择所有列。

SELECT * FROM table1 t1
right  join table2 t2
on t1.val=t2.boundary

2- 添加groupby会根据等级对元素进行分组,统计重复数据。

SELECT t2.grade,count(t1.val) FROM table1 t1
right join table2 t2
on t1.val=t2.boundary
GROUP by t2.grade,t1.val
order by t2.grade ASC

【讨论】:

  • 使用该代码,table1 中 id 为 3 或 7 的行将如何计算?
  • 此代码无法工作 - 值和范围之间的直接匹配是可能的,但不能预期。
猜你喜欢
  • 1970-01-01
  • 2011-06-10
  • 1970-01-01
  • 2023-02-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多