SQL - Select 全部唯一,其中 2 列可以具有相同的值
SQL - Select All Unique Where 2 Columns Can Have Same Value
这是我目前正在使用的 table。
+----+-------------+------------+---------+
| id | number_from | number_to | message |
+----+-------------+------------+---------+
| 1 | 5365323350 | 5368177083 | Hello |
| 2 | 5368177083 | 5365323350 | HRU |
| 3 | 5363916551 | 5365323350 | Hola |
| 4 | 5365323350 | 5363916551 | Howdy |
+----+-------------+------------+---------+
我想要做的是 select number_from = 5365323350 或 number_to = 5365323350 的所有列。但是我只想显示一个基于相反的最新行列。有点难以解释所以下面是我想要的结果
+----+-------------+------------+---------+
| id | number_from | number_to | message |
+----+-------------+------------+---------+
| 2 | 5368177083 | 5365323350 | HRU |
| 4 | 5365323350 | 5363916551 | Howdy |
+----+-------------+------------+---------+
这里是最新的行,它们在其中的 where 部分之后没有重复。
我是 SQL 的新手,我已经搜索了几个小时,但还没有想出办法,所以希望能得到一些帮助。
如果我理解正确你的问题,你可以尝试这样的事情
SELECT tb1.id, sub_tb1.number_from, sub_tb1.number_to, tb1.message
FROM table1 tb1
JOIN
(select max(number_from) as number_from, number_to
from table1
WHERE number_to = 5365323350
group by number_to
)as sub_tb1 on tb1.number_from = sub_tb1.number_from
UNION ALL
SELECT tb1.id, sub_tb1.number_from, sub_tb1.number_to, tb1.message
FROM table1 tb1
JOIN
(select number_from, min(number_to) as number_to
from table1
WHERE number_from = 5365323350
group by number_from
)as sub_tb1 on tb1.number_to = sub_tb1.number_to
你试图描述的听起来像是 A 和 B 两个人之间的聊天。A 通过 ID = 1 向 B 发起聊天,B 通过 ID = 2 回复 A。所以,这对,您想要聊天对话的最高 ID。不知道实际上下文,但示例看起来像您要描述的内容。从最近的 ID,您需要该行的值。
修改后的工作查询[=11=]
select
yt2.*
from
table1 yt2
JOIN
( select
case when yt.number_from = 5365323350
then yt.number_to
else yt.number_from end ResponseTo,
max( yt.id ) lastReplyID
from
table1 yt
where
yt.number_from = 5365323350
OR yt.number_to = 5365323350
group by
case when yt.number_from = 5365323350
then yt.number_to
else yt.number_from end ) PQ
on yt2.id = PQ.LastReplyID
在此查询中,内部 PRE-QUERY(pq 别名),我通过将该用户限定为发件人或收件人来获取仅与相关用户关联的记录。分组依据的列是通过 case/when。如果发件人是有问题的人,请抓住收件人。如果 TO 人是用户,则抓住回复反对的 FROM 人。对于那个特定的人,以及与相关用户的对话,获取该对话的最新 ID。
完成后,根据正在进行的给定聊天对话的最新 ID 加入原始 table。
注意:第一部分是通用解决方案,显示任何对话中的最新消息。具体phone号的答案在最后。
如果是我,我想我可能会尝试想出某种唯一标识符来聚合 id,这样我就可以找到任何分组的最后一个。看看这个fiddle:
https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=11a246693a7c61455b2dd17b144eb472
在这里,我使用 CONCAT 创建了一个包含两个 phone 数字的字段,并使用了 LEAST 和 GREATEST 来确保它们是有序的。然后我可以使用 phone 数字的组合来找到具有相同组合的最大 id:
SELECT
concat(
greatest(number_from, number_to),
least(number_from, number_to)
) as chatID,
max(id) as lastID
FROM table1
GROUP BY 1;
我在这里使用 GROUP BY 1 是因为 mySQL 允许您按列号指定分组,而且我不想在子句中重复连接,因为它有点笨拙。您也可以使用子查询执行此操作,以便您可以对可读值进行分组:
SELECT chatID, max(id) as lastID
FROM (
SELECT id, concat(
greatest(number_from, number_to),
least(number_from, number_to)
) as chatID
FROM table1
) z GROUP BY chatID;
现在您已经有了聊天中最后一个条目的 ID,您只需将其用作 IN 的参数以 return table1 中与这些 ID 匹配的条目。子查询必须稍微重写,因为它有两列并且 IN 需要一个操作数。这是带有子选择的那个,因为如果有人看到它可能更容易阅读:
SELECT * FROM table1 WHERE id IN (
SELECT max(id) FROM (
SELECT id, concat(
greatest(number_from, number_to),
least(number_from, number_to)
) as chatID
FROM table1
) z GROUP BY chatID
);
但您可以轻松地使用没有子选择的那个:
SELECT * FROM table1 WHERE id IN (
SELECT max(id)
FROM table1
group by concat(
greatest(number_from, number_to),
least(number_from, number_to)
)
);
您也可以使用带有 ID 的连接,如下所示:
SELECT t1.*
FROM table1 t1
JOIN (
SELECT
concat(
greatest(number_from, number_to),
least(number_from, number_to)
) as chatID,
max(id) as lastID
FROM table1
GROUP BY 1
) ids on t1.id = ids.lastID;
或
SELECT t1.*
FROM table1 t1
JOIN (
SELECT
concat(
greatest(number_from, number_to),
least(number_from, number_to)
) as chatID,
max(id) as lastID
FROM table1
GROUP BY 1
) ids on t1.id = ids.lastID;
因此,为特定 phone 号码设置规范非常简单。您将它们添加到获取 max(id) 的子查询中。我只会针对其中一个查询执行此操作,因为所有版本的修改都是相同的:
SELECT * FROM table1 WHERE id IN (
SELECT max(id) FROM (
SELECT id, concat(
greatest(number_from, number_to),
least(number_from, number_to)
) as chatID
FROM table1
WHERE number_to = '5365323350'
OR number_from = '5365323350'
) z GROUP BY chatID
);
这些查询都使用您在评论中提供的 fiddle 中的扩展数据集。您可以使用 explain 查看执行计划。评价都一样
如果有帮助请告诉我。
这是我目前正在使用的 table。
+----+-------------+------------+---------+
| id | number_from | number_to | message |
+----+-------------+------------+---------+
| 1 | 5365323350 | 5368177083 | Hello |
| 2 | 5368177083 | 5365323350 | HRU |
| 3 | 5363916551 | 5365323350 | Hola |
| 4 | 5365323350 | 5363916551 | Howdy |
+----+-------------+------------+---------+
我想要做的是 select number_from = 5365323350 或 number_to = 5365323350 的所有列。但是我只想显示一个基于相反的最新行列。有点难以解释所以下面是我想要的结果
+----+-------------+------------+---------+
| id | number_from | number_to | message |
+----+-------------+------------+---------+
| 2 | 5368177083 | 5365323350 | HRU |
| 4 | 5365323350 | 5363916551 | Howdy |
+----+-------------+------------+---------+
这里是最新的行,它们在其中的 where 部分之后没有重复。
我是 SQL 的新手,我已经搜索了几个小时,但还没有想出办法,所以希望能得到一些帮助。
如果我理解正确你的问题,你可以尝试这样的事情
SELECT tb1.id, sub_tb1.number_from, sub_tb1.number_to, tb1.message
FROM table1 tb1
JOIN
(select max(number_from) as number_from, number_to
from table1
WHERE number_to = 5365323350
group by number_to
)as sub_tb1 on tb1.number_from = sub_tb1.number_from
UNION ALL
SELECT tb1.id, sub_tb1.number_from, sub_tb1.number_to, tb1.message
FROM table1 tb1
JOIN
(select number_from, min(number_to) as number_to
from table1
WHERE number_from = 5365323350
group by number_from
)as sub_tb1 on tb1.number_to = sub_tb1.number_to
你试图描述的听起来像是 A 和 B 两个人之间的聊天。A 通过 ID = 1 向 B 发起聊天,B 通过 ID = 2 回复 A。所以,这对,您想要聊天对话的最高 ID。不知道实际上下文,但示例看起来像您要描述的内容。从最近的 ID,您需要该行的值。
修改后的工作查询[=11=]
select
yt2.*
from
table1 yt2
JOIN
( select
case when yt.number_from = 5365323350
then yt.number_to
else yt.number_from end ResponseTo,
max( yt.id ) lastReplyID
from
table1 yt
where
yt.number_from = 5365323350
OR yt.number_to = 5365323350
group by
case when yt.number_from = 5365323350
then yt.number_to
else yt.number_from end ) PQ
on yt2.id = PQ.LastReplyID
在此查询中,内部 PRE-QUERY(pq 别名),我通过将该用户限定为发件人或收件人来获取仅与相关用户关联的记录。分组依据的列是通过 case/when。如果发件人是有问题的人,请抓住收件人。如果 TO 人是用户,则抓住回复反对的 FROM 人。对于那个特定的人,以及与相关用户的对话,获取该对话的最新 ID。
完成后,根据正在进行的给定聊天对话的最新 ID 加入原始 table。
注意:第一部分是通用解决方案,显示任何对话中的最新消息。具体phone号的答案在最后。
如果是我,我想我可能会尝试想出某种唯一标识符来聚合 id,这样我就可以找到任何分组的最后一个。看看这个fiddle:
https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=11a246693a7c61455b2dd17b144eb472
在这里,我使用 CONCAT 创建了一个包含两个 phone 数字的字段,并使用了 LEAST 和 GREATEST 来确保它们是有序的。然后我可以使用 phone 数字的组合来找到具有相同组合的最大 id:
SELECT
concat(
greatest(number_from, number_to),
least(number_from, number_to)
) as chatID,
max(id) as lastID
FROM table1
GROUP BY 1;
我在这里使用 GROUP BY 1 是因为 mySQL 允许您按列号指定分组,而且我不想在子句中重复连接,因为它有点笨拙。您也可以使用子查询执行此操作,以便您可以对可读值进行分组:
SELECT chatID, max(id) as lastID
FROM (
SELECT id, concat(
greatest(number_from, number_to),
least(number_from, number_to)
) as chatID
FROM table1
) z GROUP BY chatID;
现在您已经有了聊天中最后一个条目的 ID,您只需将其用作 IN 的参数以 return table1 中与这些 ID 匹配的条目。子查询必须稍微重写,因为它有两列并且 IN 需要一个操作数。这是带有子选择的那个,因为如果有人看到它可能更容易阅读:
SELECT * FROM table1 WHERE id IN (
SELECT max(id) FROM (
SELECT id, concat(
greatest(number_from, number_to),
least(number_from, number_to)
) as chatID
FROM table1
) z GROUP BY chatID
);
但您可以轻松地使用没有子选择的那个:
SELECT * FROM table1 WHERE id IN (
SELECT max(id)
FROM table1
group by concat(
greatest(number_from, number_to),
least(number_from, number_to)
)
);
您也可以使用带有 ID 的连接,如下所示:
SELECT t1.*
FROM table1 t1
JOIN (
SELECT
concat(
greatest(number_from, number_to),
least(number_from, number_to)
) as chatID,
max(id) as lastID
FROM table1
GROUP BY 1
) ids on t1.id = ids.lastID;
或
SELECT t1.*
FROM table1 t1
JOIN (
SELECT
concat(
greatest(number_from, number_to),
least(number_from, number_to)
) as chatID,
max(id) as lastID
FROM table1
GROUP BY 1
) ids on t1.id = ids.lastID;
因此,为特定 phone 号码设置规范非常简单。您将它们添加到获取 max(id) 的子查询中。我只会针对其中一个查询执行此操作,因为所有版本的修改都是相同的:
SELECT * FROM table1 WHERE id IN (
SELECT max(id) FROM (
SELECT id, concat(
greatest(number_from, number_to),
least(number_from, number_to)
) as chatID
FROM table1
WHERE number_to = '5365323350'
OR number_from = '5365323350'
) z GROUP BY chatID
);
这些查询都使用您在评论中提供的 fiddle 中的扩展数据集。您可以使用 explain 查看执行计划。评价都一样
如果有帮助请告诉我。