创建一个获取行及其相邻行的查询
Create a query that fetches rows plus their adjacent rows
我在处理特定查询时遇到问题 - 分别首先创建查询。
这些列可以减少为 id
、seconds
和 status
.
=============================
| id | seconds | status |
-----------------------------
| 0 | 0 | 0 |
| 1 | 12 | 1 |
| 2 | 25 | 0 |
| 3 | 37 | 1 |
| 4 | 42 | 0 |
=============================
我想要的是:所有带有 status = 1
的条目加上所有与这些条目相距不到 10 秒的条目。 基本上,我想获取所有可能的行对(或三元组等)以手动(稍后自动)检查它们是否需要配对(为此目的有一列 parent_id
,但我们不需要它用于查询).我可以在代码中执行此操作(首先 select 所有 status=1
,然后循环),但我想知道是否可以完全在数据库中执行此操作。
因此,我想要的输出如下:
=============================
| id | seconds | status |
-----------------------------
| 1 | 12 | 1 | <- status = 1
| 3 | 37 | 1 | <- status = 1
| 4 | 42 | 0 | <- only 5 seconds after status = 1
=============================
我目前最好的猜测是:
SELECT * FROM entries e0
WHERE
e0.status = 1 OR
e0.status = 0 AND
0 < (SELECT count(*)
FROM entries e1
WHERE e1.status = 1 AND abs(e1.seconds - e0.seconds) < 10)
但这会获取整个 table,我真的不知道为什么 - 这样做需要很长时间(列 seconds
上有一个索引,table 有 9000 个条目)。
有没有办法做到这一点(甚至可能有效)?
这是 union all
和 exists
的一个选项:
select * from entries where status = 1
union all
select * from entries e where status = 0 and
exists (select 1
from entries e2
where e2.status = 1 and
abs(e.seconds - e2.seconds) < 10
)
或者您可以使用 outer join
和 distinct
而不是 exists
:
select distinct e.*
from entries e
left join entries e2 on e2.status = 1
where e.status = 1 or abs(e.seconds - e2.seconds) < 10
我更喜欢在单个查询中完成。但是,也有一些方法可以使用 exists 或子查询来实现。使用外部联接意味着您可以使用精心设计的 where 和 join 语句一次获取所有内容,根据您的性能情况添加 group by 或 distinct 将整理您的结果并使它们成为唯一的行。
关于在何处声明以确保满足您的意图,我的建议是使用括号来确定您的预期优先级。它将使您的代码更清楚您的意图。
WHERE Condition1 = True OR Condition2 = True AND Condition3 = True
应该是
WHERE Condition1 = True 或(Condition2 = True AND Condition3 = True)
奇怪的是,由于过去的经验,我不会认为它会以您提到的方式进行评估,但话又说回来,我总是使用括号来确定我的优先级,以便更清楚、更容易地制定更复杂的条件。
你得到整个的原因 table。是因为你table里面的数据。说真的,有时我们会去寻找答案并使它变得复杂,我更喜欢我的方式来解决你的查询,但给定你的结果集示例,我的查询和你的查询得到相同的结果!尝试将 10 秒更改为 1/2/3 等,看看您的查询效果如何。我的假设是在您的完整数据集中,您的任何状态为 0 的记录都在状态为 1 的记录的 10 秒内......我会回复,但这是我的第一个问题之一已回答
下面是一些基于您的数据集和查询的示例代码。
DECLARE @Entries AS TABLE (
Id INT
,Seconds INT
,[Status] BIT
)
INSERT INTO @Entries (Id, Seconds, [Status])
VALUES (0,0,0 )
,(1,12,1 )
,(2,25,0 )
,(3,37,1 )
,(4,42,0 )
SELECT *
FROM
@Entries e0
WHERE
e0.Status = 1
OR e0.Status = 0
AND 0 < (SELECT count(*)
FROM
@Entries e1
WHERE e1.Status = 1 AND ABS(e1.Seconds - e0.Seconds) < 10)
SELECT DISTINCT
e0.*
FROM
@Entries e0
LEFT JOIN @Entries e1
ON e1.[Status] = 1
AND ABS(e1.seconds - e0.seconds) < 10
WHERE
e0.[Status] = 1
OR e1.id IS NOT NULL
我在处理特定查询时遇到问题 - 分别首先创建查询。
这些列可以减少为 id
、seconds
和 status
.
=============================
| id | seconds | status |
-----------------------------
| 0 | 0 | 0 |
| 1 | 12 | 1 |
| 2 | 25 | 0 |
| 3 | 37 | 1 |
| 4 | 42 | 0 |
=============================
我想要的是:所有带有 status = 1
的条目加上所有与这些条目相距不到 10 秒的条目。 基本上,我想获取所有可能的行对(或三元组等)以手动(稍后自动)检查它们是否需要配对(为此目的有一列 parent_id
,但我们不需要它用于查询).我可以在代码中执行此操作(首先 select 所有 status=1
,然后循环),但我想知道是否可以完全在数据库中执行此操作。
因此,我想要的输出如下:
=============================
| id | seconds | status |
-----------------------------
| 1 | 12 | 1 | <- status = 1
| 3 | 37 | 1 | <- status = 1
| 4 | 42 | 0 | <- only 5 seconds after status = 1
=============================
我目前最好的猜测是:
SELECT * FROM entries e0
WHERE
e0.status = 1 OR
e0.status = 0 AND
0 < (SELECT count(*)
FROM entries e1
WHERE e1.status = 1 AND abs(e1.seconds - e0.seconds) < 10)
但这会获取整个 table,我真的不知道为什么 - 这样做需要很长时间(列 seconds
上有一个索引,table 有 9000 个条目)。
有没有办法做到这一点(甚至可能有效)?
这是 union all
和 exists
的一个选项:
select * from entries where status = 1
union all
select * from entries e where status = 0 and
exists (select 1
from entries e2
where e2.status = 1 and
abs(e.seconds - e2.seconds) < 10
)
或者您可以使用 outer join
和 distinct
而不是 exists
:
select distinct e.*
from entries e
left join entries e2 on e2.status = 1
where e.status = 1 or abs(e.seconds - e2.seconds) < 10
我更喜欢在单个查询中完成。但是,也有一些方法可以使用 exists 或子查询来实现。使用外部联接意味着您可以使用精心设计的 where 和 join 语句一次获取所有内容,根据您的性能情况添加 group by 或 distinct 将整理您的结果并使它们成为唯一的行。
关于在何处声明以确保满足您的意图,我的建议是使用括号来确定您的预期优先级。它将使您的代码更清楚您的意图。
WHERE Condition1 = True OR Condition2 = True AND Condition3 = True
应该是
WHERE Condition1 = True 或(Condition2 = True AND Condition3 = True)
奇怪的是,由于过去的经验,我不会认为它会以您提到的方式进行评估,但话又说回来,我总是使用括号来确定我的优先级,以便更清楚、更容易地制定更复杂的条件。
你得到整个的原因 table。是因为你table里面的数据。说真的,有时我们会去寻找答案并使它变得复杂,我更喜欢我的方式来解决你的查询,但给定你的结果集示例,我的查询和你的查询得到相同的结果!尝试将 10 秒更改为 1/2/3 等,看看您的查询效果如何。我的假设是在您的完整数据集中,您的任何状态为 0 的记录都在状态为 1 的记录的 10 秒内......我会回复,但这是我的第一个问题之一已回答
下面是一些基于您的数据集和查询的示例代码。
DECLARE @Entries AS TABLE (
Id INT
,Seconds INT
,[Status] BIT
)
INSERT INTO @Entries (Id, Seconds, [Status])
VALUES (0,0,0 )
,(1,12,1 )
,(2,25,0 )
,(3,37,1 )
,(4,42,0 )
SELECT *
FROM
@Entries e0
WHERE
e0.Status = 1
OR e0.Status = 0
AND 0 < (SELECT count(*)
FROM
@Entries e1
WHERE e1.Status = 1 AND ABS(e1.Seconds - e0.Seconds) < 10)
SELECT DISTINCT
e0.*
FROM
@Entries e0
LEFT JOIN @Entries e1
ON e1.[Status] = 1
AND ABS(e1.seconds - e0.seconds) < 10
WHERE
e0.[Status] = 1
OR e1.id IS NOT NULL