我想根据条件连接两个表。
表 A:
+--------+-------------+------+
| prefix | Destination | rate |
+----------------------+------+
| 56 | Monn | 25 |
| 5602 | Monn M1 | 23 |
| 5604 | Monn M3 | 44 |
| 5607 | Monn M1 | 23 |
| 5625 | Monn M2 | 22 |
| 23 | Xpia | 0.3 |
| 238 | Xpia F3 | 0.9 |
+--------+-------------+------+
表 B:
+--------+-------------+------+
| prefix | Destination | rate |
+----------------------+------+
| 56 | Monn | 75 |
| 560 | Monn M1x | 49 |
| 5607 | Monn M1 | 03 |
| 56254 | Monn M2 | 9.5 |
| 23 | Xpia | 1.3 |
| 2301 | Xpia T1 | 2.4 |
| 2302 | Xpia T2 | 3.5 |
| 2381 | Xpia F | 8.9 |
+--------+-------------+------+
期望的输出:
表 C:
+--------+-------------+------+
| prefix | Destination | rate |
+----------------------+------+
| 56 | Monn | 75 |
| 5602 | Monn M1 | 49 |
| 5604 | Monn M3 | 49 |
| 5607 | Monn M1 | 03 |
| 5625 | Monn M2 | 9.5 |
| 23 | Xpia | 1.3 |
| 238 | Xpia F3 | 8.9 |
+--------+-------------+------+
注意以下条件:
- 我只想使用表
A
的Prefix
和Destination
列。 - 我只想使用表
B
的rate
列。 - 如果表
A
的Prefix
= 表B的Prefix
,则复制rate
- 如果在表
B
中找不到表A
的prefix
,则复制的
(仅返回最长字符串的值)。rate
表B
中以A
的prefix
开头的前缀 - 如果表 A 的
prefix
不在表 B 中,则表 B 中前缀的复制率(其中表 A 的前缀为 a)从表 B 中的前缀开始。(仅返回最长字符串的值)
如果满足条件 4 和 5,则只返回最长前缀的速率。
我有这个查询,但它不工作。我意识到我需要一个更复杂的查询。
INSERT INTO Table C(prefix,destination, rate)
SELECT Table A.prefix, Table A.destination, Table B.rate
FROM Table A, Table B
WHERE Table B.prefix= SUBSTRING(Table A.prefix, 1, length(Table B.prefix))
最佳答案
免责声明:下面的回答很长,所以我首先要引起你的注意,最后的查询会产生与你想要的结果相匹配的结果。这是 SQL Fiddle .
好吧,在我看来,解决这个问题的最佳方式是一次满足一项要求。
I want to use only Prefix and Destination columns of table A.
这只是一个简单的选择语句:
SELECT a.prefix, a.destination
FROM tableA a;
I want to use only rate column of table B.
我们也可以很容易地添加它。请注意,我现在所拥有的只是创建一个笛卡尔积,但随着我们添加更多要求,它会理顺:
SELECT a.prefix, a.destination, b.rate
FROM tableA a, tableB b;
If Prefix of table A = Prefix of table B, then copy rate.
我将上面的内容更改为在 select 子句中使用相关子查询,如果它具有与 tableA 的前缀匹配的前缀,则提取速率。这将为任何不匹配的值设置 null(暂时):
SELECT a.prefix, a.destination,
(SELECT b.rate FROM tableB b WHERE b.prefix = a.prefix) AS rate
FROM tableA a;
If prefix of table A is not found in table B, then copy rate of prefix in table B that starts with prefix of table A (return only the longest string's value).
为此,我暂时离开并编写了从 B 获取费率的查询,其中前缀以表 A 的前缀开头,忘记了之前的条件。我像你一样使用了 substring 函数,但按长度降序排列以获得最大的一个:
SELECT a.prefix, a.destination,
(SELECT b.rate FROM tableB b WHERE b.prefix =
SUBSTRING(a.prefix, 1, LENGTH(b.prefix)) ORDER BY LENGTH(b.prefix) DESC LIMIT 1) AS rate
FROM tableA a;
现在,您可以采用该选择查询和上面的查询,并使用 COALESCE
函数获取第一个非空值。因此,第 3 步中返回空值的那些将被第 4 步中的替换(如果仍然存在非空值):
SELECT a.prefix, a.destination, COALESCE(
(SELECT b.rate FROM tableB b WHERE b.prefix = a.prefix),
(SELECT b.rate FROM tableB b WHERE b.prefix = SUBSTRING(a.prefix, 1, LENGTH(b.prefix)) ORDER BY LENGTH(b.prefix) DESC LIMIT 1)) AS rate
FROM tableA a;
If prefix of table A is not in table B then copy rate of prefix in table B where prefix of table A starts with a prefix in table B. (return only longest string's value).
好吧,我们可以做与上一个相同的事情,除了操纵子查询来检查相反的表。另外,COALESCE函数没有参数限制,所以我们可以把它作为第三个参数添加进去。如果第一个返回 null,它将尝试第二个。如果返回 null,它将尝试第三个。这是最终查询:
SELECT a.prefix, a.destination, COALESCE(
(SELECT b.rate FROM tableB b WHERE b.prefix = a.prefix),
(SELECT b.rate FROM tableB b WHERE b.prefix = SUBSTRING(a.prefix, 1, LENGTH(b.prefix)) ORDER BY LENGTH(b.prefix) DESC LIMIT 1),
(SELECT b.rate FROM tableB b WHERE a.prefix = SUBSTRING(b.prefix, 1, LENGTH(a.prefix)) ORDER BY LENGTH(a.prefix) DESC LIMIT 1)) AS rate
FROM tableA a;
将我的结果与您的结果进行比较时,我注意到上面没有考虑同时满足 4 和 5,在这种情况下我们希望采用最长的前缀。虽然可能有更简洁的方式来编写它,但我只是编写了以下 case 语句:
SELECT a.prefix, a.destination,
CASE WHEN
(SELECT b.rate FROM tableB b WHERE b.prefix = a.prefix) IS NOT NULL
THEN
(SELECT b.rate FROM tableB b WHERE b.prefix = a.prefix)
ELSE
CASE WHEN
((SELECT b.rate FROM tableB b WHERE b.prefix = SUBSTRING(a.prefix, 1, LENGTH(b.prefix)) ORDER BY LENGTH(b.prefix) DESC LIMIT 1) IS NOT NULL)
AND
((SELECT b.rate FROM tableB b WHERE a.prefix = SUBSTRING(b.prefix, 1, LENGTH(a.prefix)) ORDER BY LENGTH(a.prefix) DESC LIMIT 1) IS NOT NULL)
THEN
CASE WHEN
(SELECT LENGTH(b.prefix) FROM tableB b WHERE b.prefix = SUBSTRING(a.prefix, 1, LENGTH(b.prefix)) ORDER BY LENGTH(b.prefix) DESC LIMIT 1)
>
(SELECT LENGTH(a.prefix) FROM tableB b WHERE a.prefix = SUBSTRING(b.prefix, 1, LENGTH(a.prefix)) ORDER BY LENGTH(a.prefix) DESC LIMIT 1)
THEN
(SELECT b.rate FROM tableB b WHERE b.prefix = SUBSTRING(a.prefix, 1, LENGTH(b.prefix)) ORDER BY LENGTH(b.prefix) DESC LIMIT 1)
ELSE
(SELECT b.rate FROM tableB b WHERE a.prefix = SUBSTRING(b.prefix, 1, LENGTH(a.prefix)) ORDER BY LENGTH(a.prefix) DESC LIMIT 1)
END
ELSE
COALESCE(
(SELECT b.rate FROM tableB b WHERE b.prefix = SUBSTRING(a.prefix, 1, LENGTH(b.prefix)) ORDER BY LENGTH(b.prefix) DESC LIMIT 1),
(SELECT b.rate FROM tableB b WHERE a.prefix = SUBSTRING(b.prefix, 1, LENGTH(a.prefix)) ORDER BY LENGTH(a.prefix) DESC LIMIT 1))
END
END AS rate
FROM tableA a;
其背后的逻辑有点像下面这样:
- 检查是否满足条件 3。
- 如果是,则使用该值。
- 检查是否满足条件 4 和 5。
- 如果是,检查条件 4 的前缀是否更长。
- 如果是,就使用它。如果不是,则使用条件 5 中的前缀。
- 如果不是,则从条件 4 和 5 中选择第一个非空条件。
- 如果是,检查条件 4 的前缀是否更长。
关于php - 从具有多个要求的两个表中选择值,但只使用其中一个,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27529792/