MySQL:按值对记录进行计数,然后用其计数更新另一列

发布于 2024-12-15 06:41:04 字数 1191 浏览 2 评论 0原文

三个非常相关的 SQL 问题(我实际上使用的是 mySQL):

假设一个人员表有两列名称,国家

1)我如何显示有同胞的人?我可以按国家/地区显示公民数量:

select country, count(*) as fellow_citizens 
from people 
group by country

但我似乎无法显示 Fellow_citizens > 的记录。 1.以下内容无效:

select name, country, count(*) as fellow_citizens 
from people 
group by country 
where fellow_citizens > 1;

...并且不会是我想要的,因为我不想将人们分组。

2)为了解决上述问题,我想到将 Fellow_citizens 存储在一个新列中。 这听起来像是诸如 MySQL: Count 等问题的变体来自一个表的记录,然后更新另一个表。不同的是我想更新同一张表。

然而,那里给出的答案在这里不起作用:

update people as dest 
set fellow_citizens = 
    (select count(*) from people as src where src.country = dest.country);

我收到此错误消息:

您无法在 FROM 子句中指定要更新的目标表“dest”

似乎我需要通过另一个临时表来执行此操作。没有临时表可以做到吗?

3)作为上述的变体,如何按国家/地区更新包含人数统计器的列?我发现我可以使用以下内容更新全局计数器:

set @i:=0; update people set counter = @i:=@i+1 order by country;

但是在这里,当国家/地区的值发生变化时,我想重置我的@i计数器。

有没有一种方法可以在 mySQL 中做到这一点,而无需使用成熟的过程代码?

Three very related SQL questions (I am actually using mySQL):

Assuming a people table with two columns name, country

1) How can I show the people who have fellow citizens? I can display the count of citizens by country:

select country, count(*) as fellow_citizens 
from people 
group by country

But I can't seem to show those records for which fellow_citizens is > 1. The following is invalid:

select name, country, count(*) as fellow_citizens 
from people 
group by country 
where fellow_citizens > 1;

... and would not be what I want any way since I don't want to group people.

2) To solve the above, I had the idea to store fellow_citizens in a new column.
This sounds like a variation on questions such as MySQL: Count records from one table and then update another. The difference is that I want to update the same table.

However the answer given there doesn't work here:

update people as dest 
set fellow_citizens = 
    (select count(*) from people as src where src.country = dest.country);

I get this error message:

You can't specify target table 'dest' for update in FROM clause

It seems like I need to through another temporary table to do that. Can it be done without a temporary table?

3) As a variant of the above, how can I update a column with a people counter by country? I found I can update a global counter with something like:

set @i:=0; update people set counter = @i:=@i+1 order by country;

But here I would like to reset my @i counter when the value of country changes.

Is there a way to do that in mySQL without going to full-blown procedural code?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

苦笑流年记忆 2024-12-22 06:41:04

您选择的查询应类似于:

SELECT name, country, count(*) as fellow_citizens  
FROM people  
GROUP BY country  
HAVING fellow_citizens > 1; 

推荐的解决方案
您不想分组,您只是想为每个人重复计数。
这些数据没有标准化,这样的代码并不是一个很好的方法。
但是,以下选择将为您提供所有人员及其计数:

SELECT p.* 
     , s.fellow_citizens
FROM people p
INNER JOIN (
  SELECT country, count(*) as fellow_citizens
  FROM people  
  GROUP BY country  
  HAVING count(*) > 1) s ON (s.country = p.country)

如果您不需要实际计数,只需要来自拥有超过 1 个公民的国家/地区的人员,则编写此查询的另一种方法是(此可能比以前的方法更快,您必须使用您的数据进行测试):

SELECT p.* 
FROM people p
WHERE EXISTS
      ( SELECT *
        FROM people p2  
        WHERE p2.country = p.country 
          AND p2.PK <> p.PK         -- the Primary Key of the table 
      )

仅在遇到缓慢情况时才执行此操作
如果您想使用更新语句将计数包含到表中,我建议您使用单独的计数表,因为至少这在某种程度上标准化了。

INSERT INTO people_counts (country, pcount)
  SELECT p.country, count(*) as peoplecount
  FROM people p
  GROUP BY p.country
ON DUPLICATE KEY pcount = VALUES(pcount)

然后,您可以将计数表与人员数据连接起来以加快选择速度。

SELECT p.*, c.pcount
FROM people p
INNER JOIN people_counts c ON (p.country = c.country)

Your select query should look something like:

SELECT name, country, count(*) as fellow_citizens  
FROM people  
GROUP BY country  
HAVING fellow_citizens > 1; 

Recommended solution
You don't want to group, you just want to repeat the count for every person.
This data is not normalized and code like this is not a great way to do things.
However the following select will give you all the people and their counts:

SELECT p.* 
     , s.fellow_citizens
FROM people p
INNER JOIN (
  SELECT country, count(*) as fellow_citizens
  FROM people  
  GROUP BY country  
  HAVING count(*) > 1) s ON (s.country = p.country)

If you don't want the actual count, just people from countries with more than 1 citizen, another way to write this query is (this may be faster than previous method, you have to test with your data):

SELECT p.* 
FROM people p
WHERE EXISTS
      ( SELECT *
        FROM people p2  
        WHERE p2.country = p.country 
          AND p2.PK <> p.PK         -- the Primary Key of the table 
      )

Only do this if you are facing slowness
If you want to include the counts into the table using a update statement I suggest you use a separate count table, because at least that's somewhat normalized.

INSERT INTO people_counts (country, pcount)
  SELECT p.country, count(*) as peoplecount
  FROM people p
  GROUP BY p.country
ON DUPLICATE KEY pcount = VALUES(pcount)

Then you can join the counts table with the people data to speed up the select.

SELECT p.*, c.pcount
FROM people p
INNER JOIN people_counts c ON (p.country = c.country)
在风中等你 2024-12-22 06:41:04

1->

select country, count(*) as fellow_citizens 
from people 
group by country 
having fellow_citizens > 1

抱歉,但无法真正理解第2点和第3点。

1 ->

select country, count(*) as fellow_citizens 
from people 
group by country 
having fellow_citizens > 1

Sorry, but could not really understand points 2 and 3.

画▽骨i 2024-12-22 06:41:04

我会这样做。

create view citizencount as
select country, count(*) citizens 
from people 
group by country 

然后你的查询变成(类似)

select p.personid, p.country, cc.citizens -1 fellow_citizens
from people p
join citizencount cc on
  cc.country = p.country

然后你可能想添加

其中 Fellow_citizens > 0

I would do this.

create view citizencount as
select country, count(*) citizens 
from people 
group by country 

Then your Query becomes (Something like)

select p.personid, p.country, cc.citizens -1 fellow_citizens
from people p
join citizencount cc on
  cc.country = p.country

You might then want to add

where fellow_citizens > 0

心奴独伤 2024-12-22 06:41:04

你有没有尝试过这个来解决你的两个问题

select name, fellow_citizens
from people left join  
(select country, count(*) as fellow_citizens  
 from people group by country  
 having fellow_citizens > 1) as citizens  
 on people.country = citizens.country  

我不太擅长编写sql查询;但我认为这可以解决你的问题

Have you tried this for both of your problem

select name, fellow_citizens
from people left join  
(select country, count(*) as fellow_citizens  
 from people group by country  
 having fellow_citizens > 1) as citizens  
 on people.country = citizens.country  

I am not very good at writing sql query; but I think this can solve your problem

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文