Ruby on Rails и Querys (понимание вопроса) - PullRequest
0 голосов
/ 12 декабря 2018

У меня есть таблица с именем Codes в моем проекте.

irb(main):017:0> Code.new                                      
=> #<Code id: nil, company_id: nil, name: nil, employee_uuid: nil, employee_email: nil, redeemed_at: nil, created_at: nil, updated_at: nil>

В моей базе данных у меня в общей сложности 97994 записей кода.

irb(main):018:0> Code.all.count
(127.7ms)  SELECT COUNT(*) FROM "codes"
=> 97994

Итак, чего я не делаюпонять это следующее.До сих пор я проверял его с помощью атрибута name.

irb(main):019:0> Code.where(name: "").count
(135.0ms)  SELECT COUNT(*) FROM "codes" WHERE "codes"."name" = ?  [["name", ""]]
=> 0
irb(main):020:0> Code.where(name: " ").count
(18.3ms)  SELECT COUNT(*) FROM "codes" WHERE "codes"."name" = ?  [["name", " "]]
=> 0

, если при выполнении oposite Query он должен дать мне пропущенные объекты, в этом случае мой общий объем кодов.

irb(main):021:0> Code.where.not(name: "").count 
(116.3ms)  SELECT COUNT(*) FROM "codes" WHERE ("codes"."name" != ?)  [["name", ""]]
=> 94652
irb(main):022:0> Code.where.not(name: " ").count
(19.9ms)  SELECT COUNT(*) FROM "codes" WHERE ("codes"."name" != ?)  [["name", " "]]
=> 94652

Но в результате я получаю 94652 вместо 97994 (из Code.all.count)

Это заставляет меня задуматься.Я проверил, какие левые коды:

irb(main):023:0> rest = Code.all - Code.where(name: "") - Code.where.not(name: "")
Code Load (1030.6ms)  SELECT "codes".* FROM "codes"
Code Load (16.1ms)  SELECT "codes".* FROM "codes" WHERE "codes"."name" = ?  [["name", ""]]
Code Load (489.1ms)  SELECT "codes".* FROM "codes" WHERE ("codes"."name" != ?)  [["name", ""]]
... a huge array was returned
irb(main):024:0> rest.last
=> #<Code id: 86217, company_id: 307, name: nil, employee_uuid: "XXXXXXXXXXXXXX", employee_email: "XXXXX@EMAIL.COM", redeemed_at: "2018-07-09 12:30:29", created_at: "2018-12-11 13:07:57", updated_at: "2018-12-11 13:07:57">

Мне было интересно об этом, поэтому я проверил еще одну вещь:

irb(main):027:0> rest.last.name == ""
=> false
irb(main):028:0> rest.last.name != ""
=> true

, так что rest.last.name не ""(конечно, нет, зовут nil)

но все же я получаю это

irb(main):025:0> Code.where(name: "").include? rest.last
Code Load (108.1ms)  SELECT "codes".* FROM "codes" WHERE "codes"."name" = ?  [["name", ""]]
=> false
irb(main):026:0> Code.where.not(name: "").include? rest.last
Code Load (365.9ms)  SELECT "codes".* FROM "codes" WHERE ("codes"."name" != ?)  [["name", ""]]
=> false

Я всегда думал, где что-то, и его отрицательный всегда будет составлять общую сумму, то есть когдачто-то случается, и когда этого не происходит, мы всегда отвечаем.A + !A = 1 Почему я это вижу?я не могу следить за этим.

Заранее спасибо за помощь.

Обновите вопрос, чтобы ответить на комментарии:

irb(main):002:0> Code.where(name: [nil, '']).count                                                   
(432.2ms)  SELECT COUNT(*) FROM "codes" WHERE ("codes"."name" = '' OR "codes"."name" IS NULL)
=> 3342

и это число в точности равно

irb(main):003:0> Code.all.count - Code.where.not(name: "").count
(315.2ms)  SELECT COUNT(*) FROM "codes"
(332.5ms)  SELECT COUNT(*) FROM "codes" WHERE ("codes"."name" != ?)  [["name", ""]]
=> 3342

Хорошо, пока я понимаю, что SQL не может сравниваться с Nil или нет, когда я проверяю, является ли строка пустой.Это означает, что мне нужно либо выполнить запрос с массивом [nil, ''], либо подумать иначе ...

Ответы [ 3 ]

0 голосов
/ 12 декабря 2018

Это потому, что операторы sql != и = не могут сравниваться с NULL.Для сравнения NULL вам нужно использовать IS NULL и IS NOT NULL или в синтаксисе ROR

Code.where(name: [nil, '']).count
Code.where.not(name: [nil, '']).count
0 голосов
/ 17 декабря 2018

В этом случае значение по умолчанию для name, хранимое в базе данных, составляет NULL.Если вы не сохранили name для записи code в базе данных, она будет сохранена как NULL вместо пустой строки "".

Итак, если вы выполните запрос Code.where(name: "").count, это явно попытается вернуть только те строки, которые имеют имя, равное пустой строке (""), и проигнорируют все записи, имеющие имя = NULL или " ".Это 0 в вашем случае

Когда вы запускаете запрос Code.where(name: [nil, '']).count, вы получаете результат 3342, который точно равен разнице между всеми строками в таблице и строками, которые делаютне иметь имя, равное пустой строке (Code.where.not(name: "").count).Что доказывает, что в таблице есть 3342 строки, в которых name хранится как NULL.

Итак, чтобы избежать этой ситуации, вы можете установить значение по умолчанию "" (пустая строка) вваш атрибут имени в миграции, которая создает таблицу кодов.Таким образом, результаты вашего запроса по поиску записей, в которых имя отсутствует, то есть (Code.where(name: "").count) согласованы.

Обновление:

Code.where.not(name: '') будет игнорировать записи, где name = NULL вбаза данных.Причиной является запрос, который сформирован:

SELECT * FROM Codes WHERE name != "";

Этот запрос явно пытается найти те строки, где name не равно "", но для проверки, существует ли NULL или нет, мынеобходимо написать запрос, подобный приведенному ниже, в SQL:

SELECT * FROM Codes WHERE name IS NOT NULL;

Вышеупомянутый запрос генерируется, если мы пишем Codes.where.not(name: nil) в ActiveRecord.

Для реализацииоба условия, которые были упомянуты выше в двух разных запросах в одном запросе, мы будем использовать в ActiveRecord следующее:

Code.where.not(name: [nil, ""])

Это сгенерирует следующий запрос:

SELECT * FROM "codes" WHERE AND (NOT (("codes"."name" = "" OR "codes"."name" IS NULL)))

Приведенный выше запрос гарантирует, что мы избегаем записей с условиями как пустой строки, так и имени с нулевым значением в базе данных.

0 голосов
/ 12 декабря 2018

SQL-запросы не возвращают записи со значениями NULL при использовании предложения , где .

Некоторые дополнительные ресурсы:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...