首页 > 解决方案 > 如果 NULL 值在列中可用,则查询条件

问题描述

我不明白两个查询之间的区别,请参阅图片。注意最后一个条件。mysql版本是5.7有什么神奇之处?

select distinct(pc) as aggregate 
from `installers` 
where 
    `success` =1 
    and 
    date(created_at) >= '2018-08-15' 
    and 
    date(created_at) <= '2018-08-21' 
    and 
    (free=0 or free is null)

(免费为空或免费=0)

在此处输入图像描述

select distinct(pc) as aggregate 
from `installers` 
where 
    `success` =1 
    and 
    date(created_at) >= '2018-08-15' 
    and 
    date(created_at) <= '2018-08-21' 
    and 
    free!=1

免费!=1

在此处输入图像描述

表结构

    CREATE TABLE `installers` (
    `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
    `driver_id` BIGINT(20) UNSIGNED NOT NULL,
    `created_at` TIMESTAMP NULL DEFAULT NULL,
    `updated_at` TIMESTAMP NULL DEFAULT NULL,
    `success` TINYINT(4) NULL DEFAULT NULL,
    `version` BIGINT(20) UNSIGNED NULL DEFAULT NULL,
    `pc` VARCHAR(255) NOT NULL COLLATE 'utf8mb4_unicode_ci',
    `status` VARCHAR(180) NULL DEFAULT NULL COLLATE 'utf8mb4_unicode_ci',
    `error` VARCHAR(180) NULL DEFAULT NULL COLLATE 'utf8mb4_unicode_ci',
    `free` INT(11) NULL DEFAULT NULL,
    `time` VARCHAR(100) NULL DEFAULT NULL COLLATE 'utf8mb4_unicode_ci',
    PRIMARY KEY (`id`),
    INDEX `installers_created_at_index` (`created_at`),
    INDEX `installers_updated_at_index` (`updated_at`),
    INDEX `installers_driver_id_foreign` (`driver_id`),
    INDEX `installers_success_index` (`success`),
    INDEX `installers_version_index` (`version`),
    INDEX `installers_pc_index` (`pc`(191)),
    INDEX `installers_status_index` (`status`),
    INDEX `installers_error_index` (`error`),
    INDEX `installers_free_index` (`free`),
    INDEX `installers_time_index` (`time`),
    CONSTRAINT `installers_driver_id_foreign` FOREIGN KEY (`driver_id`) REFERENCES `drivers` (`id`) ON UPDATE CASCADE ON DELETE CASCADE
)
COLLATE='utf8mb4_unicode_ci'
ENGINE=InnoDB
AUTO_INCREMENT=4709971
;

'free' 的不同值为 NULL,0,1

标签: mysqlsql

解决方案


NULL 不是值,NULL(根据WIKI - NULL):

Null(或 NULL)是结构化查询语言中使用的特殊标记,用于指示数据库中不存在数据值。

这不应与值 0 混淆。空值表示缺少值 — 缺少值与值 0 不同,就像缺少答案不一样事情作为“不”的答案。例如,考虑“亚当拥有多少本书?”这个问题。答案可能是“零”(我们知道他没有拥有)或“空”(我们不知道他拥有多少)。在数据库表中,报告此答案的列一开始将没有值(由 Null 标记),并且在我们确定 Adam 没有任何书籍之前,它不会更新为“零”值。

SQL null 是一个状态,而不是一个值。这种用法与大多数编程语言完全不同,其中引用的 null 值意味着它没有指向任何对象。

由于 Null 不是任何数据域的成员,因此它不被视为“值”,而是指示不存在值的标记(或占位符)。因此,与 Null 的比较永远不会导致 True 或 False,但总是会产生第三个逻辑结果 Unknown。

那是:

  • 1 = 0为假,但1 = NULL未知
  • 1 != 0是 TRUE 但1 != NULL也是 UNKNOWN

WHERE 子句中的UNKNOWN状态相当于 FALSE。

这是直观的——因为 x 为 NULL(未知),所以我们不能说 x = 1 或 x != 1 是否为真——在这两种情况下,比较结果都是未知的。

由于上述原因,SQL 中有特殊的运算符来检查列是否为空 -x IS NULLx IS NOT NULL.

您可以在这个简单的演示中看到这种行为:http ://www.sqlfiddle.com/#!9/9f78b0/5

SELECT * FROM t;
| id |      x |
|----|--------|
|  1 |      1 |
|  2 |      0 |
|  3 | (null) |

SELECT * FROM t WHERE x =1;
| id | x |
|----|---|
|  1 | 1 |

SELECT * FROM t WHERE x != 1;
| id | x |
|----|---|
|  2 | 0 |

请注意,上面的查询只返回了带有的记录,x = 2但跳过了带有的记录,x = NULL因为比较x != NULL评估为 UNKNOWN,相当于 FALSE。


SELECT * FROM t WHERE x IS NULL;

| id |      x |
|----|--------|
|  3 | (null) |

SELECT * FROM t WHERE x IS NOT NULL;
| id | x |
|----|---|
|  1 | 1 |
|  2 | 0 |

SELECT * FROM t WHERE x = 1 OR x IS NULL;
| id |      x |
|----|--------|
|  1 |      1 |
|  3 | (null) |

SELECT * FROM t WHERE x != 1 OR x IS NULL;
| id |      x |
|----|--------|
|  2 |      0 |
|  3 | (null) |

推荐阅读