特定の名前について、この人が住んでいた 3 つ以上の都市に住んでいた他の名前を取得したいと考えています。
9 に答える
これはあなたがすべきことです:
都市テーブルを持つようにデータベースを再設計します。
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 つ以上の都市に住んでいるユーザーを見つけるにはどうすればよいでしょうか。これを行う 1 つの方法は、次のように、各ユーザーが住んでいたリストから都市の数を数えることです。
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;
私はこれを実際にテストしませんでしたが、うまくいくはずです。
また、それらのテーブルにインデックスを付ける方法を理解する必要があります。
binomial(10,3)^2
クエリを実行するには OR 条件が必要です。それは 14 400 です。あなたはそれをしたくありません。
代わりにテーブルを再設計する必要があります
名前 , 都市 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 のアドバイスを受けて、データの正規化について学びましょう!
データベースを再設計しないというあなたの要求を尊重します
まだ試していない私のアイデア、今すぐテストする方法はありません
ユニオンなどでビュー(名前、都市)を作成し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
うん。
テーブルをデザインする方法を学ぶために、コメントを付けてテーブルをデザインした人にテーブルを送り返します。第一正規形、正規化。
テーブルがSQLルールに従うと、クエリは非常に簡単になります。
次のようなことを試してください:
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)
これを試して:
<テーブル>Person
<フィールド>PersonId、PersonName |
<テーブル>都市
<フィールド>CityId、CityName |
<テーブル>LivedIn
<フィールド>LivedInId、PersonId、CityId
論理的には、シナリオごとに次のことを行います。
さまざまな都市の最大数に住んでいる人を見つける:
PersonId(すべての人)のリストを作成します
それを繰り返し、各人が住んでいた都市の数を数えます人が住んで
いる最大の都市
を見つけます人の名前を見つけます最大の都市を持っていたpersonIdに関連する3つ以上の都市に住んでいたすべての人をギブパーソンとして検索する人を
ボブと呼びましょう
ボブが住んでいたすべての都市(CityIds)
のリストを作成します。personIdと一般的な都市(JavaのHashMapなど)を含むリストを作成します。 )
LivedInテーブルを反復処理し、一般的な都市の数を更新します。数
が3を超えるすべての人を検索します。
私はJavaとSQLの組み合わせでこれを行いますが、どちらもあまり得意ではないので、多くのことを調べなくてもここでコードを提供することはできません。
データベースを正規化する必要があります。
そうすることで、列を取得できます
名前、都市(オプションでCityOrder)。
その後、これらの結果を必要なものに組み合わせる方法を見つける必要があります。これを行うには、Join、Count、Groupbyを理解する必要があります。
このデータを 3 つのテーブルに分割して、より柔軟な多対多の関係を提供します。
person
名前を格納するテーブル2 つを関連付ける
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';