4

各行に、他のテーブルの他のデータに関連する ID を持つフィールドがいくつかあるテーブルがあります。

peopleという名前で、各人が 、および の ID を持っているとcitystateましょうcountry

したがって、さらに 3 つのテーブル 、citiesstatesおよびcountriesそれぞれが ID と名前を持つことになります。

人を選択するとき、1 回のクエリで の名前を取得する最も簡単な方法は何ですか?citystatecountry

注:これは結合で可能であることはわかっていますが、関連するテーブルが増えるため、ネストされた結合によりクエリが読みにくくなります。よりクリーンな方法があるかどうか疑問に思っています。人がそれらのフィールドを空にすることも可能であるべきです。

4

10 に答える 10

2

JOINS は、これを実際に行う唯一の方法です。

スキーマを変更できるかもしれませんが、問題は同じです。

(City は常に State にあり、State は常に Country にあるため、Person は 3 つすべてではなく、city_id への参照を持つことができます。ただし、3 つのテーブルを結合する必要があります)。

于 2008-12-27T07:20:23.733 に答える
2

次の表を想定しています。

create table People
(
     ID        int          not null primary key auto_increment
    ,FullName  varchar(255) not null
    ,StateID   int 
    ,CountryID int 
    ,CityID    int 
)
;
create table States
(
     ID   int          not null primary key auto_increment
    ,Name varchar(255) not null
)
;
create table Countries
(
     ID   int          not null primary key auto_increment
    ,Name varchar(255) not null
)
;
create table Cities
(
     ID   int          not null primary key auto_increment
    ,Name varchar(255) not null
)
;

次のデータを使用:

insert into Cities(Name) values ('City 1'),('City 2'),('City 3');
insert into States(Name) values ('State 1'),('State 2'),('State 3');
insert into Countries(Name) values ('Country 1'),('Country 2'),('Country 3');
insert into People(FullName,CityID,StateID,CountryID) values ('Has Nothing'   ,null,null,null);
insert into People(FullName,CityID,StateID,CountryID) values ('Has City'      ,   1,null,null);
insert into People(FullName,CityID,StateID,CountryID) values ('Has State'     ,null,   2,null);
insert into People(FullName,CityID,StateID,CountryID) values ('Has Country'   ,null,null,   3);
insert into People(FullName,CityID,StateID,CountryID) values ('Has Everything',   3,   2,   1);

次に、このクエリは、あなたが求めているものを提供するはずです。

select 
 P.ID
,P.FullName
,Ci.Name as CityName
,St.Name as StateName
,Co.Name as CountryName
from People P
left Join Cities    Ci on Ci.ID = P.CityID
left Join States    St on St.ID = P.StateID
left Join Countries Co on Co.ID = P.CountryID
于 2008-12-27T19:16:13.290 に答える
1

結合するよりもクリーンな方法はありません。フィールドを空にすることが許可されている場合は、外部結合を使用してください

SELECT c.*, s.name AS state_name
  FROM customer c
  LEFT OUTER JOIN state s ON s.id = c.state
 WHERE c.id = 10
于 2008-12-27T09:34:40.670 に答える
1

与えられたスキーマの説明によると、単一のクエリで JOINS を使用する必要があります。

SELECT 
   p.first_name 
 , p.last_name
 , c.name as city
 , s.name as state
 , co.name as country 
FROM people p 
LEFT OUTER JOIN city c 
  ON p.city_id = c.id
LEFT OUTER JOIN state s 
  ON p.state_id = s.id
LEFT OUTER JOIN country co
  ON p.country_id = co.id; 

LEFT OUTER JOIN を使用すると、一部の ID が空白または空の場合でも、個人の詳細を取得できます。

もう 1 つの方法は、ルックアップ テーブルを再設計することです。都市は常に州にあり、国には州があります。したがって、cityテーブルには列 :Id, Namestate_id. あなたのstateテーブルは :Id, Namecountry_id. そしてcountryテーブルは同じままです:IdそしてName

テーブルのpersonid は 1 つだけになります。city_id

これで、クエリは次のようになります。

 SELECT 
   p.first_name 
 , p.last_name
 , c.name as city
 , s.name as state
 , co.name as country 
FROM people p 
LEFT OUTER JOIN city c 
  ON p.city_id = c.id
LEFT OUTER JOIN state s 
  ON c.state_id = s.id
LEFT OUTER JOIN country co
  ON s.country_id = co.id;

最後の 2 つの OUTER JOINS の違いに注目してください。

于 2008-12-29T19:15:31.760 に答える
0

人、市、州、国が参加するビューを作成します。次に、他のすべての結合でビューを参照します。

何かのようなもの:

CREATE VIEW FullPerson AS  
SELECT Person.*, City.Name, State.Name, Country.Name  
FROM  
  Person LEFT OUTER JOIN City ON Person.CityId = City.Id  
  LEFT OUTER JOIN State ON Person.StateId = State.Id  
  LEFT OUTER JOIN Country ON Person.CountryId = Country.Id

その後、他のクエリでは、次のことができます

SELECT FullPerson.*, Other.Value  
FROM FullPerson LEFT OUTER JOIN Other ON FullPerson.OtherId = Other.Id
于 2008-12-29T20:14:59.347 に答える
0

関連するテーブルが参照テーブル (つまり、セッションの存続期間中に変更されないルックアップ データを保持するテーブル) である場合、アプリケーションの性質に応じて、アプリケーションの起動時に参照データをプリロードできます。 . 次に、クエリで結合を行う必要はなく、代わりに ID 値を返します。アプリケーションでは、データを表示する必要があるときに ID のデコードを行います。

于 2008-12-27T07:43:23.453 に答える
0

すべて素晴らしい回答ですが、質問者は結合を使用したくないと述べました。Citiesある回答者が示したように、 、States、およびCountriesテーブルにIdおよびフィールドがあると仮定すると、次のDescriptionようなことができる可能性があります。

SELECT
   p.Name, c.Description, s.Description, ct.Description
FROM
   People p, Cities c, States s, Countries ct
WHERE
   p.Id = value AND
   c.Id = value AND
   s.Id = value AND
   ct.Id = value;
于 2008-12-29T19:26:32.347 に答える
0

city最も簡単な解決策は、 、state、およびで名前を主キーとして使用することcountryです。その後、personテーブルは疑似キー " " の代わりに名前でそれらを参照できますid。そうすれば、personテーブルには必要な値が既にあるため、結合を行う必要はありません。

4 バイトの疑似キーの代わりに文字列を格納するには、より多くのスペースが必要です。しかし、思ったほど結合の脅威にさらされている場合は、トレードオフの価値があることに気付くかもしれません (ちなみに、これは PHP プログラマーが使用するのをためらうようなものforeachです。結合は SQL の基本でもあります)。

また、複数の州にまたがる都市名も数多くあります。したがって、cityテーブルはテーブルを参照し、stateこれら 2 つの列を主キーとして使用する必要があります。

CREATE TABLE cities (
  city_name VARCHAR(30),
  state     CHAR(2),
  PRIMARY KEY (city_name, state),
  FOREIGN KEY (state) REFERENCES states(state)
);

CREATE TABLE persons (
  person_id    SERIAL PRIMARY KEY,
  ...other columns...
  city_name    VARCHAR(30),
  state        CHAR(2),
  country_name VARCHAR(30),
  FOREIGN KEY (city_name, state) REFERENCES cities(city_name, state),
  FOREIGN KEY (country_name) REFERENCES countries(country_name)
);

これはテクニックのほんの一例です。もちろん、複数の国に都市名がある場合や、州のない国がある場合など、これよりも複雑です。ポイントは、SQL では整数の疑似キーの使用を強制しないため、必要に応じて CHAR および VARCHAR キーを使用することです。

于 2008-12-27T08:57:11.307 に答える
0

標準 SQL の欠点は、返されるデータを表形式にする必要があることです。ただし、一部のデータベース ベンダーは、表形式以外のデータを選択できるようにする機能を追加しています。MySQL がそのような機能を認識しているかどうかはわかりません。

于 2008-12-27T10:30:53.177 に答える
-1

結合が答えです。練習すれば、より読みやすくなります。
関数を作成すると役立つ特別なケースがあるかもしれません。たとえば、次のことができます (Oracle では、mysql はわかりません)
: 、その後、クエリは次のようになります

SELECT first_name, last_name, formated_address(city_id, state_id, country_id) 
FROM people
WHERE some_where_clause;

whereformated_addressは、都市の状態と国のテーブルを個別に検索し、デコードされた値の間にセパレータを配置するか、すべてが空の場合は「住所なし」を返します。

于 2008-12-27T07:39:38.983 に答える