Пожалуйста, помогите мне разработать SQL-запрос для этой проблемы - PullRequest
0 голосов
/ 18 марта 2010

alt text

Для определенного имени я хочу получить другие имена, которые жили в трех или более городах, в которых жил этот человек.

Ответы [ 9 ]

12 голосов
/ 18 марта 2010

это то, что вы должны сделать:

измените базу данных, чтобы получить таблицу городов:

city(id int, name varchar)

и пользовательская таблица:

user(id int, name varchar, ...)

и таблица user_city:

user_city(user_id int, city_id int)

, что само по себе устранит ограничение в 10 городов на пользователя.

чтобы найти города, в которых жил пользователь:

select city_id form user_city where user_id = ?

как теперь найти пользователей, которые живут в 3 или более городах из этого списка? Один из способов сделать это - подсчитать количество городов из списка, в котором жил каждый пользователь, например:

select user_id,count(*) n 
from user_city 
where city_id in (select city_id 
                  from user_city 
                  where user_id = ?) 
group by user_id having n >= 3;

Я действительно не проверял это, но оно должно работать.

вам также придется выяснить, как индексировать эти таблицы.

4 голосов
/ 18 марта 2010

Для выполнения вашего запроса вам потребуется binomial(10,3)^2 ИЛИ условия. Это 14 400. Вы не хотите этого делать.

2 голосов
/ 18 марта 2010

Уважая вашу просьбу не перепроектировать базу данных

Моя неопробованная идея, сейчас нет возможности проверить ее

Создайте представление (имя, город), объединив select name, c1, select name, c2 и т. Д. *

Тогда:

select m2.name from myview m1
inner join myview m2 on m1.city = m2.city
where m1.name = @Name AND m2.Name!=@Name
group by m2.name
having count(m2.name) > 2 
2 голосов
/ 18 марта 2010

Вам нужно переделать свой стол вместо

имя, город1, город2, город3, город4, город5, город6, город7, город8, город9, город10

это должно быть больше похоже на

Person, City, rank
------------------
name , city1 ,1
name , city2 ,2 
name , city3 ,3 
name , city4 ,4 
name , city5 ,5 
name , city6 ,6 
name , city7 ,7 
name , city8 ,8 
name , city9 ,9 
name , city10,10

и прислушайтесь к советам TomTom и узнайте о нормализации данных!

1 голос
/ 18 марта 2010

Попробуйте что-то вроде этого:

SELECT PersonName,COUNT(*) AS CountOf
    FROM (SELECT PersonName,city1 FROM PersonCities WHERE city1 IS NOT NULL
          UNION SELECT PersonName,city2 FROM PersonCities WHERE city2 IS NOT NULL
          UNION SELECT PersonName,city3 FROM PersonCities WHERE city3 IS NOT NULL
          UNION SELECT PersonName,city4 FROM PersonCities WHERE city4 IS NOT NULL
          UNION SELECT PersonName,city5 FROM PersonCities WHERE city5 IS NOT NULL
          ...
         ) dt
    WHERE dt.city1 IN (SELECT city1 FROM PersonCities WHERE PersonName=..SearchPerson.. AND city1 IS NOT NULL
                       UNION SELECT city2 FROM PersonCities WHERE PersonName=..SearchPerson.. AND city2 IS NOT NULL
                       UNION SELECT city3 FROM PersonCities WHERE PersonName=..SearchPerson.. AND city3 IS NOT NULL
                       UNION SELECT city4 FROM PersonCities WHERE PersonName=..SearchPerson.. AND city4 IS NOT NULL
                       UNION SELECT city5 FROM PersonCities WHERE PersonName=..SearchPerson.. AND city5 IS NOT NULL
                       ...
                       )
        AND PersonName!=@SearchPerson
    GROUP BY PersonName
    HAVING COUNT(*)>=3

У меня нет mysql, поэтому здесь он работает с использованием SQL Server:

DECLARE @PersonCities table(PersonName varchar(10), city1 varchar(10), city2 varchar(10), city3 varchar(10), city4 varchar(10), city5 varchar(10))
INSERT INTO @PersonCities VALUES ('Joe','AAA','BBB','CCC', NULL, NULL)
INSERT INTO @PersonCities VALUES ('Pat','BBB','DDD','EEE','FFF','GGG')
INSERT INTO @PersonCities VALUES ('Sam','FFF','BBB', NULL, NULL, NULL)
INSERT INTO @PersonCities VALUES ('Ron','HHH','DDD','EEE','FFF', NULL)
INSERT INTO @PersonCities VALUES ('Don','FFF','ZZZ','QQQ', NULL, NULL)

DECLARE @SearchPerson varchar(10)
SET @SearchPerson='Pat'

SELECT PersonName,COUNT(*) AS CountOf
    FROM (SELECT PersonName,city1 FROM @PersonCities WHERE city1 IS NOT NULL
          UNION SELECT PersonName,city2 FROM @PersonCities WHERE city2 IS NOT NULL
          UNION SELECT PersonName,city3 FROM @PersonCities WHERE city3 IS NOT NULL
          UNION SELECT PersonName,city4 FROM @PersonCities WHERE city4 IS NOT NULL
          UNION SELECT PersonName,city5 FROM @PersonCities WHERE city5 IS NOT NULL
         ) dt
    WHERE dt.city1 IN (SELECT city1 FROM @PersonCities WHERE PersonName=@SearchPerson AND city1 IS NOT NULL
                       UNION SELECT city2 FROM @PersonCities WHERE PersonName=@SearchPerson AND city2 IS NOT NULL
                       UNION SELECT city3 FROM @PersonCities WHERE PersonName=@SearchPerson AND city3 IS NOT NULL
                       UNION SELECT city4 FROM @PersonCities WHERE PersonName=@SearchPerson AND city4 IS NOT NULL
                       UNION SELECT city5 FROM @PersonCities WHERE PersonName=@SearchPerson AND city5 IS NOT NULL
                       )
        AND PersonName!=@SearchPerson
    GROUP BY PersonName
    HAVING COUNT(*)>=3

ВЫВОД:

PersonName 
---------- -----------
Ron        3

(1 row(s) affected)
1 голос
/ 18 марта 2010

Да.

Вы отправляете таблицу обратно тому, кто ее разработал, с комментарием, чтобы научиться проектировать таблицы.Первая нормальная форма, нормализация.

Как только таблица следует правилам SQL, запрос довольно прост.

0 голосов
/ 18 марта 2010

Разбивка этих данных на три таблицы для обеспечения более гибкого отношения «многие ко многим».

person таблица имен магазинов
city стол для хранения городов
person_city для связи двух (многих со многими)

Чтобы найти других людей, которые жили в 3 или более городах, которые имеет Навин:

SELECT name FROM (
    SELECT
        p.name, COUNT(DISTINCT(city_id)) AS lived
    FROM person p 
    JOIN person_city pc ON (pc.person_id = p.person_id) 
    JOIN city c ON (c.city_id = pc.city_id) 
    WHERE city_id IN (
        SELECT c2.city_id 
        FROM city c2 
        JOIN person_city pc2 ON (c2.city_id = pc2.city_id) 
        JOIN person p2 ON (p2.person_id = pc2.person_id) 
        WHERE p2.name = 'navin' 
    )
    GROUP BY person_id HAVING lived >= 3
) AS multihome 
WHERE name <> 'navin';
0 голосов
/ 18 марта 2010

Попробуйте это:

<таблица> Человек
PersonId, PersonName |

<стол> Город
CityId, CityName |

<таблица> LivedIn
LivedInId, PersonId, CityId

Логически вы бы сделали следующие вещи для каждого сценария:

  1. Найдите человека, прожившего в максимальном количестве разных городов:
    Составьте список PersonId (всех людей)
    Повторите это и посчитайте количество городов, в которых жил каждый человек
    Найти максимальное количество городов, в которых живет каждый человек
    Найти имя человека, связанное с personId, у которого было максимум городов

  2. Найти всех людей, которые проживали в 3 или более городах как человек, отдавший себе
    Давайте назовем человека Бобом
    Составьте список всех городов (CityIds), в которых жил Боб.
    Составьте список, который включает в себя personId и общие города (возможно, HashMap в Java)
    Выполните итерацию по таблице LivedIn и обновите счетчик числа городов, которые часто встречаются
    Найти всех людей, чей счет больше 3

Я бы сделал это с комбинацией Java и SQL, но я не очень хорош в обоих случаях, поэтому не могу дать вам код здесь без необходимости искать много вещей.

0 голосов
/ 18 марта 2010

Вам необходимо нормализовать вашу базу данных.

При этом вы получите столбцы

Имя, Город (необязательно CityOrder).

После этого вам нужно будет найти способ объединить эти результаты в то, что вам нужно. Делая это, вы должны понимать, присоединиться, считать и группировать по.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...