请帮我设计一个sql查询来解决这个问题

发布于 2024-08-25 14:15:26 字数 139 浏览 4 评论 0原文

alt text

对于特定名称,我想获取居住在三个或更多城市的其他名称被这个人住过。

alt text

For a particular name i want to fetch other names who have lived in three or more cities lived by this person.

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

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

发布评论

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

评论(9

盛夏已如深秋| 2024-09-01 14:15:26

这就是你应该做的:

重新设计你的数据库以拥有一个城市表:

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;

我没有真正测试过这个,但它应该可以工作。

您还必须弄清楚如何为这些表建立索引。

this is what you should do:

redesign your database to have a city table:

city(id int, name varchar)

and a user table:

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

and a user_city table:

user_city(user_id int, city_id int)

that alone will eliminate the limit of 10 cities per user.

to find the cities lived in by a user:

select city_id form user_city where user_id = ?

now how you would find users that lives in 3 or more cities from that list?
one way to do it would be to count the number of cities from the list each user lived in, something like:

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;

I didn't really test this, but it should work.

you will also have to figure out how to index those tables.

冷…雨湿花 2024-09-01 14:15:26

您需要使用binomial(10,3)^2 OR 条件来执行查询。那是 14 400。你不想这样做。

You'd need binomial(10,3)^2 OR conditions to do your query. Thats 14 400. You do not want to do that.

仅此而已 2024-09-01 14:15:26

您需要重新设计您的表,而不是

name 、 city1 、 city2 、 city3 、city4 、 city5 、city6 、 city7 、 city8 、 city9 city10 ,

它应该更像

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 的建议并了解数据规范化!

You need to redesign your table instaed of

name , city1 , city2 , city3 ,city4 , city5 ,city6 , city7 , city8 , city9 city10

it should be more like

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

and take TomTom's advice and learn about data normalization!

深海少女心 2024-09-01 14:15:26

尊重您不重新设计数据库的请求

我未经尝试的想法,现在无法测试

通过联合 select name, c1 创建视图(名称,城市)选择名称、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 

Respecting your request to not redesign the database

My untried idea, no way to test it right now

Make a view (name, city) by unioning select name, c1, select name, c2 etc...

Then:

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 
戏剧牡丹亭 2024-09-01 14:15:26

是的。

您可以将表格发送回设计者,并附上评论以了解如何设计表格。第一范式,规范化。

一旦表遵循 SQL 规则,查询就非常容易。

Yeah.

You send the table back to whoever designed it with a comment to learn hwo to design tables. First normal form, normalization.

Once the table follows SQL rules, the query is pretty easy.

生死何惧 2024-09-01 14:15:26

尝试这样的操作:

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)

Try something like this:

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

I don't have mysql, so here it is running using 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

OUTPUT:

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

(1 row(s) affected)
终陌 2024-09-01 14:15:26

您需要标准化您的数据库。

执行此操作,您将获得

“名称”、“城市”列(可选的“城市顺序”)。

之后,您需要找到一种方法将这些结果组合成您需要的结果。为此,您需要了解连接、计数和分组依据。

You need to normalize your database.

Doing that you will get the columns

Name, City (optionally CityOrder).

After that you will need to find a way to combine these results into what you need. Doing this you'll need to understand Join, Count and Group by.

悟红尘 2024-09-01 14:15:26

试试这个:

<表>人
<字段>人员 ID、人员名称 |

<表>城市
<字段>城市 ID、城市名称 |

<表>曾住过
<字段> LivedInId、PersonId、CityId

从逻辑上讲,您将为每个场景执行以下操作:

  1. 查找居住在最大数量的不同城市的人:
    制作 PersonId 的列表(所有人)
    迭代并计算每个人居住的城市数量
    查找有人居住的最多城市
    查找与拥有最多城市的 personId 相关的人名

  2. 查找居住在 3 个或更多城市的所有人员作为给定人员
    我们称这个人为鲍勃
    列出 Bob 居住过的所有城市(CityId)。
    制作一个包含 personId 和常见城市的列表(可能是 Java 中的 HashMap)
    迭代 LivedIn 表并更新常见城市的数量
    查找计数大于 3 的所有人员

我会结合使用 Java 和 SQL 来完成此操作,但我对这两者都不太擅长,因此无法在此处为您提供代码,而不必查看很多东西向上。

Try this:

< table > Person
< fields > PersonId, PersonName |

< table > City
< fields > CityId, CityName |

< table > LivedIn
< fields > LivedInId, PersonId, CityId

Logically you would do the following things for each scenario:

  1. Find the person who has lived in the maximum number of different cities:
    Make a list of the PersonId's (all people)
    Iterate over that and count the number of cities each person lived in
    Find the maximum cities lived in by anyone person
    Find the person name related to the personId that had the max cities

  2. Find all people that lived in 3 or more cities as a give person
    Let's call the person Bob
    Make a list of all cities (the CityIds) that Bob lived in.
    Make a list which includes personId, and common cities (maybe a HashMap in Java)
    Iterate over the LivedIn table and update the count of how many cities are common
    Find all the people who have a count greater than 3

I would do this with a combination of Java and SQL but I am not that good with either so can't give you the code here without having to look a lot of stuff up.

何处潇湘 2024-09-01 14:15:26

将此数据分为三个表以提供更灵活的多对多关系。

person 用于存储姓名的表
用于存储城市的city
person_city 将两者关联起来(多对多)

要检索曾居住在 navin 拥有的 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';

Breaking this data out into three tables to provide a more flexible many-to-many relationship.

person table to store names
city table to store cities
person_city to relate the two (many to many)

To retrieve other people who have lived in 3 or more cities that navin has:

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