我该如何为自引用SELECT编写SQL,该自引用SELECT的某些字段与同一字段不同,而另一些条件不相同?

问题描述

我有以下(简化的)表:

CREATE TABLE IF NOT EXISTS `resource` (
  `id`         INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,`host`       TEXT NOT NULL,`inspecting` INTEGER DEFAULT 0,`visitedAt`  TEXT
);

可以有多个记录,它们具有相同的host值和/或一个被视为host的子域的值。例如:

 id |      host       | inspecting |      visitedAt
---------------------------------------------------------
  1 |     example.com |          0 |                null
  2 |     example.com |          0 | 2020-09-28 00:00:00
  3 | sub.example.com |          1 |                null
  4 |     example.org |          0 |                null

因此,这些主机可能已被访问或当前可以被检查。我想找到最旧的主机,该主机最近没有被访问过并且当前未被检查,并且该主机也不被认为是最近访问或当前被检查的主机的子域。

因此,假设example.com当前正在检查中或最近被访问过,那么我不想匹配example.comsub.example.com。在以上数据示例中,example.org应该匹配。

我已经用JOINWHERE (NOT) EXISTS尝试了各种查询,但是我无法使其正常工作。

最接近的查询类似(虽然可能不准确):

SELECT `self`.*
FROM `resource` AS `self`
WHERE 
  `self`.`inspecting` != 1 AND 
  (`self`.`visitedAt` IS NULL OR datetime( `self`.`visitedAt` ) <= datetime( 'now','-10 minutes' )) AND
  NOT EXISTS (  
    SELECT 1
    FROM 
      `resource` AS `probe`
    WHERE
      `probe`.`inspecting` = 1 AND 
      (`self`.`host` = `probe`.`host` OR `self`.`host` LIKE "%." || `probe`.`host`) AND 
      (`probe`.`visitedAt` IS NOT NULL AND datetime( `probe`.`visitedAt` ) > datetime( 'now','-10 minutes' ))
  )
ORDER BY `self`.`visitedAt` ASC
LIMIT 1

是否可以通过单个查询过滤出这样的行?

解决方法

您可以在选择中使用带有子查询的公用表表达式来创建条件列,如下所示:

context['form2'] = self.second_form_class(instance=request.Sitiocontratado.sitioproyecto)

现在结果应如下所示:

WITH `t` AS (
  SELECT  
    -- Create a conditional column `inspectionFlag`
    CASE WHEN
    (
    -- Checks the `resource` table for hosts that has inspecting = 1
     SELECT 1 FROM `resource` AS `probe` 
      WHERE (`probe`.`host` LIKE '%.' || `self`.`host` OR `self`.`host` LIKE '%.' || `probe`.`host` OR `self`.`host` = `probe`.`host`)
      AND `probe`.`inspecting` = 1
    ) IS NOT NULL THEN 1 ELSE 0 END
    AS `inspectionFlag`,CASE 
    WHEN     
    -- Checks the `resource` table for hosts that are being visited
    (SELECT 1 FROM `resource` AS `probe`
            WHERE (`probe`.`host` LIKE '%.' || `self`.`host` OR `self`.`host` LIKE '%.' || `probe`.`host` OR `self`.`host` = `probe`.`host`)
      AND `probe`.`visitedAt` IS NOT NULL
      AND datetime( `probe`.`visitedAt` ) > datetime( 'now','-10 minutes' )
    ) IS NOT NULL THEN 1 ELSE 0 END 
    AS `visitedFlag`,`self`.*
  FROM `resource` AS `self`
) 
SELECT `t`.* FROM `t`

现在只需要使用新的“标志”列来过滤出主机,就像这样:

| inspectionFlag | visitedFlag | id  | host            | inspecting | visitedAt           |
| -------------- | ----------- | --- | --------------- | ---------- | ------------------- |
| 1              | 1           | 1   | example.com     | 0          |                     |
| 1              | 1           | 2   | example.com     | 0          | 2020-09-28 08:00:00 |
| 1              | 1           | 3   | sub.example.com | 1          |                     |
| 0              | 0           | 4   | example.org     | 0          |                     |

结果:

WITH `t` AS (
  SELECT  
    CASE WHEN
    (
     SELECT 1 FROM `resource` AS `probe` 
      WHERE (`probe`.`host` LIKE '%.' || `self`.`host` OR `self`.`host` LIKE '%.' || `probe`.`host` OR `self`.`host` = `probe`.`host`)
      AND `probe`.`inspecting` = 1
    ) IS NOT NULL THEN 1 ELSE 0 END
    AS `inspectionFlag`,CASE 
    WHEN     
    (SELECT 1 FROM `resource` AS `probe`
            WHERE (`probe`.`host` LIKE '%.' || `self`.`host` OR `self`.`host` LIKE '%.' || `probe`.`host` OR `self`.`host` = `probe`.`host`)
      AND `probe`.`visitedAt` IS NOT NULL
      AND datetime( `probe`.`visitedAt` ) > datetime( 'now',`self`.*
  FROM `resource` AS `self`
) 
SELECT `t`.* FROM `t`
WHERE `t`.`inspectionFlag` = 0 AND `t`.`visitedFlag` = 0

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...