MySQL: считать записи по значению, а затем обновлять другой столбец с их количеством - PullRequest
3 голосов
/ 10 ноября 2011

Три очень связанных вопроса 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: подсчет записей из одной таблицы и затем обновление другой .Разница в том, что я хочу обновить ту же таблицу.

Однако полученный здесь ответ не работает:

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

Я получаю это сообщение об ошибке:

Вы не можете указать целевую таблицу 'dest' для обновления в предложении FROM

Похоже, мне нужно сделать это через другую временную таблицу.Можно ли это сделать без временной таблицы?

3) Как вариант выше, как я могу обновить столбец счетчиком людей по стране?Я обнаружил, что могу обновить глобальный счетчик примерно так:

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

Но здесь я хотел бы сбросить счетчик @i при изменении значения страны.

Есть ли способсделать это в MySQL, не переходя на полномасштабный процедурный код?

Ответы [ 4 ]

2 голосов
/ 10 ноября 2011

Ваш запрос на выборку должен выглядеть примерно так:

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)
2 голосов
/ 10 ноября 2011

1 ->

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

Извините, но не смог понять пункты 2 и 3.

1 голос
/ 10 ноября 2011

Я бы сделал это.

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

Вы можете добавить

where fellow_citizens > 0

1 голос
/ 10 ноября 2011

Вы пробовали это для обеих ваших проблем

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-запросов;но я думаю, что это может решить вашу проблему

...