这有点复杂,但我有2张桌子。假设结构是这样的:
*Table1*
ID
PhoneNumber1
PhoneNumber2
*Table2*
PhoneNumber
SomeOtherField
可以根据Table1.PhoneNumber1 - >连接表格。 Table2.PhoneNumber,或Table1.PhoneNumber2 - > Table2.PhoneNumber。
现在,我想获得一个结果集,其中包含PhoneNumber1,SomeOtherField,对应于PhoneNumber1,PhoneNumber2和SomeOtherField,对应PhoneNumber2。
我想到了两种方法 - 通过两次加入表格,或者在ON子句中加入一次OR。
方法1 :
SELECT t1.PhoneNumber1, t1.PhoneNumber2,
t2.SomeOtherFieldForPhone1, t3.someOtherFieldForPhone2
FROM Table1 t1
INNER JOIN Table2 t2
ON t2.PhoneNumber = t1.PhoneNumber1
INNER JOIN Table2 t3
ON t3.PhoneNumber = t1.PhoneNumber2
这似乎有效。
方法2 :
以某种方式有一个看起来有点像这样的查询 -
SELECT ...
FROM Table1
INNER JOIN Table2
ON Table1.PhoneNumber1 = Table2.PhoneNumber OR
Table1.PhoneNumber2 = Table2.PhoneNumber
我还没有让它工作,我不确定是否有办法。
实现这一目标的最佳方法是什么?这两种方式都不简单或直观......有没有更简单的方法来做到这一点?这个要求一般如何实施?
答案 0 :(得分:131)
首先,我会尝试重构这些表,以避免使用电话号码作为自然键。我不是自然键的粉丝,这是一个很好的例子。自然键,尤其是电话号码之类的东西,可以随时更改。发生更改时更新数据库将是一个巨大的,容易出错的问题。 *
方法1 正如您所描述的那样,这是您最好的选择。由于命名方案和短别名,它看起来有点简洁但是......在多次连接同一个表或使用子查询等时,别名是你的朋友。
我会稍微清理一下:
SELECT t.PhoneNumber1, t.PhoneNumber2,
t1.SomeOtherFieldForPhone1, t2.someOtherFieldForPhone2
FROM Table1 t
JOIN Table2 t1 ON t1.PhoneNumber = t.PhoneNumber1
JOIN Table2 t2 ON t2.PhoneNumber = t.PhoneNumber2
我做了什么:
* DBA避免更新自然键的麻烦的一种方法是不指定主键和外键约束,这进一步加剧了db设计不佳的问题。我实际上经常看到这一点。
答案 1 :(得分:4)
除非Phone1或(更有可能)phone2可以为null,否则第一个是好的。在这种情况下,您希望使用左连接而不是内连接。
当您有一个包含两个电话号码字段的表时,这通常是一个不好的迹象。通常这意味着您的数据库设计存在缺陷。
答案 2 :(得分:2)
第一种方法是正确的方法,并将做你需要的。但是,对于内部联接,如果Table1
中存在两个电话号码,则只会从Table2
中选择行。您可能需要执行LEFT JOIN
,以便选择Table1
中的所有行。如果电话号码不匹配,则SomeOtherField
将为空。如果您想确保至少有一个匹配的电话号码,则可以WHERE t2.PhoneNumber IS NOT NULL OR t3.PhoneNumber IS NOT NULL
第二种方法可能会出现问题:如果Table2
同时包含PhoneNumber1
和PhoneNumber2
会怎样?选择哪一行?根据您的数据,外键等,这可能是也可能不是问题。
答案 3 :(得分:2)
您可以使用UNION
组合两个联接:
SELECT Table1.PhoneNumber1 as PhoneNumber, Table2.SomeOtherField as OtherField
FROM Table1
JOIN Table2
ON Table1.PhoneNumber1 = Table2.PhoneNumber
UNION
SELECT Table1.PhoneNumber2 as PhoneNumber, Table2.SomeOtherField as OtherField
FROM Table1
JOIN Table2
ON Table1.PhoneNumber2 = Table2.PhoneNumber
答案 4 :(得分:2)
我的问题是显示记录,即使没有或只有一个电话号码(完整地址簿)。因此,我使用LEFT JOIN从左侧获取所有记录,即使右侧没有相应的记录。对我来说,这适用于 Microsoft Access SQL(它们需要括号!)
SELECT t.PhoneNumber1, t.PhoneNumber2, t.PhoneNumber3
t1.SomeOtherFieldForPhone1, t2.someOtherFieldForPhone2, t3.someOtherFieldForPhone3
FROM
(
(
Table1 AS t LEFT JOIN Table2 AS t3 ON t.PhoneNumber3 = t3.PhoneNumber
)
LEFT JOIN Table2 AS t2 ON t.PhoneNumber2 = t2.PhoneNumber
)
LEFT JOIN Table2 AS t1 ON t.PhoneNumber1 = t1.PhoneNumber;
答案 5 :(得分:0)
const { API } = withSSRContext(context)
let movieData
try {
movieData = await API.graphql({
query: listMovies,
authMode: "AMAZON_COGNITO_USER_POOLS"
});
console.log('movieData: ', movieData)
} catch (err) {
console.log("error fetching movies: ", err)
}
return {
props: {
movies: movieData ? movieData.data.listMovies.items : null
}
}
}```
SELECT
T1.ID
T1.PhoneNumber1,
T1.PhoneNumber2
T2A.SomeOtherField AS "SomeOtherField of PhoneNumber1",
T2B.SomeOtherField AS "SomeOtherField of PhoneNumber2"
FROM
Table1 T1
LEFT JOIN Table2 T2A ON T1.PhoneNumber1 = T2A.PhoneNumber
LEFT JOIN Table2 T2B ON T1.PhoneNumber2 = T2B.PhoneNumber
WHERE
T1.ID = 'FOO';
或 LEFT JOIN
也返回相同的结果。使用 PostgreSQL 13.1.1 测试成功。