我有一个表,其中每一行都有一些字段,这些字段的ID与其他一些表中的其他数据相关。
我们称之为people
,每个人的ID都是city
,state
和country
。
因此,还有三个表格cities
,states
和countries
,其中每个表都有ID和名称。
当我选择某个人时,在单个查询中获取city
,state
和country
的名称的最简单方法是什么?
注意:我知道这可以通过连接实现,但是由于有更多相关的表,嵌套连接会使查询难以阅读,我想知道是否有更清洁的方法。该人也应该可以将这些字段清空。
答案 0 :(得分:2)
JOINS是真正做到这一点的唯一方法。
您可以更改架构,但无论如何问题都是一样的。
(一个城市总是在一个国家,总是在一个国家 - 所以人可以只引用city_id而不是全部三个。你仍然需要加入3个表格。)
答案 1 :(得分: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
答案 2 :(得分: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
答案 3 :(得分: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为空或空。
另一种方法是重新设计查找表。一个城市总是处于一个国家和一个国家。因此,您的city
表格将包含以下列:Id, Name
和state_id
。您的state
表格将为:Id, Name
和country_id
。 country
表格保持不变:Id
和Name
。
person
表现在只有1个ID: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;
注意最后两个OUTER JOINS的区别
答案 4 :(得分:0)
如果所涉及的表是参考表(即它们保存的查找数据在会话的生命周期内不会发生变化),根据应用程序的性质,您可以预先加载参考数据应用程序启动。然后您的查询不需要进行连接,而是返回id值,并且在您的应用程序中,您需要显示数据时对ID进行解码。
答案 5 :(得分:0)
最简单的解决方案是将名称用作city
,state
和country
中的主键。然后,您的person
表可以通过名称而不是假名“id
”来引用它们。这样,您就不需要进行连接,因为您的person
表已经具有所需的值。
存储字符串需要更多空间而不是4字节伪代码。但是你可能会发现这种权衡是有价值的,如果你受到连接的威胁,就像你看起来那样(顺便说一下,就像PHP程序员不愿意使用foreach
一样 - 连接是SQL的基础。同样的方式)。
此外,还有许多城市名称出现在多个州。因此,您的city
表应引用state
表,并使用这两列作为主键。
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键。
答案 6 :(得分:0)
标准SQL的缺点是返回数据需要采用表格格式。 但是,一些数据库供应商添加了一些功能,可以选择非表格格式的数据。我不知道MySQL是否知道这些功能。
答案 7 :(得分: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;
答案 8 :(得分:0)
创建一个视图,为您添加人员,城市,州和国家/地区。然后只需在所有其他连接中引用View。
类似的东西:
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
答案 9 :(得分:-1)
加入 答案。通过练习,他们将变得更具可读性
可能存在特殊情况,创建函数会对您有所帮助,例如您可以执行以下操作(在Oracle中,我不知道任何mysql):
您可以创建一个函数来返回给定城市州和国家/地区代码的格式化地址,然后您的查询变为
SELECT first_name, last_name, formated_address(city_id, state_id, country_id)
FROM people
WHERE some_where_clause;
其中formated_address
对城市州和国家/地区表进行单独查找,并在解码后的值之间放置分隔符,如果全部为空则返回“无地址”等等