При поиске по содержимому PrimaryKey() в постргес с джоинами находятся только нечетные записи.
Например, я ищу заказ по номеру 2199 (находит) и 2200 (ненаход).
Подробности ->>>
Примеры (сформированы ORM):
Запрос с нечетным числом
(корректно сопоставляет значение в поиске и PrimaryKey и возвращает запись с подходящим значением поля):
```
SELECT "t1"."item_id",
"t1"."client",
"t1"."trouble",
"t1"."pic_path",
"t1"."pic_id",
"t1"."oriented_timestamp",
"t1"."status",
"t1"."predefined_price",
"t1"."price",
"t1"."prepayment",
"t1"."payment",
"t1"."delivery_check",
"t1"."geo_check",
"t1"."address_check",
"t1"."call_check",
"t1"."high_priority",
"t1"."creator",
"t1"."added"
FROM "orders_clients" AS "t1"
INNER JOIN "comments_orders" AS "t2"
ON ("t2"."order_id" = "t1"."item_id")
INNER JOIN "numbs_clients" AS "t3"
ON ("t3"."client_id" = "t1"."client")
INNER JOIN "clients" AS "t4"
ON ("t4"."item_id" = "t1"."client")
INNER JOIN "devices" AS "t5"
ON ("t5"."order_id" = "t1"."item_id")
WHERE ((((((((((CAST("t1"."item_id" AS text) ILIKE '%2199%')
OR ("t2"."comment" ILIKE '%2199%'))
OR ("t3"."number" ILIKE '%2199%'))
OR ("t1"."trouble" ILIKE '%2199%'))
OR ("t5"."brand_name" ILIKE '%2199%'))
OR ("t5"."model_name" ILIKE '%2199%'))
OR ("t5"."color" ILIKE '%2199%'))
OR ("t5"."imei" ILIKE '%2199%'))
OR ("t4"."name" ILIKE '%2199%'))
OR ("t4"."surname" ILIKE '%2199%'))
ORDER BY "t1"."item_id"
```
Запрос с четным числом
(некорректно сопоставляет значение в поиске и PrimaryKey и не возвращает запись с подходящим значением поля (хотя запись присуствует)):
```
SELECT "t1"."item_id",
"t1"."client",
"t1"."trouble",
"t1"."pic_path",
"t1"."pic_id",
"t1"."oriented_timestamp",
"t1"."status",
"t1"."predefined_price",
"t1"."price",
"t1"."prepayment",
"t1"."payment",
"t1"."delivery_check",
"t1"."geo_check",
"t1"."address_check",
"t1"."call_check",
"t1"."high_priority",
"t1"."creator",
"t1"."added"
FROM "orders_clients" AS "t1"
INNER JOIN "comments_orders" AS "t2"
ON ("t2"."order_id" = "t1"."item_id")
INNER JOIN "numbs_clients" AS "t3"
ON ("t3"."client_id" = "t1"."client")
INNER JOIN "clients" AS "t4"
ON ("t4"."item_id" = "t1"."client")
INNER JOIN "devices" AS "t5"
ON ("t5"."order_id" = "t1"."item_id")
WHERE ((((((((((CAST("t1"."item_id" AS text) ILIKE '%2200%')
OR ("t2"."comment" ILIKE '%2200%'))
OR ("t3"."number" ILIKE '%2200%'))
OR ("t1"."trouble" ILIKE '%2200%'))
OR ("t5"."brand_name" ILIKE '%2200%'))
OR ("t5"."model_name" ILIKE '%2200%'))
OR ("t5"."color" ILIKE '%2200%'))
OR ("t5"."imei" ILIKE '%2200%'))
OR ("t4"."name" ILIKE '%2200%'))
OR ("t4"."surname" ILIKE '%2200%'))
ORDER BY "t1"."item_id"
```
Любой подобный запрос содержащий четные числа (целенаправленно перебирал все записи) пропускает записи если совпадение имеется только в pk.
Ниже на скриншоте это показано:
Поиск четного числа в item_id.
Поиск нечетного числа в item_id
Выборка разных заказов со смешением разных item_id.
Модель ORM Peewee3:
class Order(BaseModel):
"""
Status: StatusOrderMenu.item.value
"""
item_id: PrimaryKeyField = PrimaryKeyField(index=True, unique=True,)
client: Client = ForeignKeyField(Client, column_name='client',
backref='orders')
trouble: TextField = TextField(default='не указано', index=True)
pic_path: TextField = TextField(default='')
pic_id: TextField = TextField(default='')
oriented_timestamp: TextField = TextField(default='расчет не произведен')
status: str = TextField(default='')
predefined_price: TextField = BigIntegerField(default=0)
price: TextField = BigIntegerField(default=0, index=True, )
prepayment: TextField = BigIntegerField(default=0, index=True)
payment: TextField = BigIntegerField(default=0, index=True)
delivery_check: TextField = BooleanField(default=False)
geo_check: TextField = BooleanField(default=False)
address_check: TextField = BooleanField(default=False)
call_check: TextField = BooleanField(default=False)
high_priority: TextField = BooleanField(default=False)
creator: Client = ForeignKeyField(Client, column_name='creator',
backref='created_orders')
added: time = TimestampField()
class Meta:
db_table = f'orders_clients'
Метод класса, который делает запрос для поиска:
def searching_for(self):
selection = Order.select() \
.join(CommentOrder, on=(CommentOrder.order == Order.item_id)) \
.join(ContactClient, on=(ContactClient.client == Order.client)) \
.join(Client, on=(Client.item_id == Order.client)) \
.join(Device, on=(Device.order == Order.item_id))
queries = (
selection.where(
Order.item_id.cast('text').ilike(f"%{word}%") |
CommentOrder.comment.ilike(f"%{word}%") |
ContactClient.number.ilike(f"%{word}%") |
Order.trouble.ilike(f"%{word}%") |
Device.brand_name.ilike(f"%{word}%") |
Device.model_name.ilike(f"%{word}%") |
Device.color.ilike(f"%{word}%") |
Device.imei.ilike(f"%{word}%") |
Client.name.ilike(f"%{word}%") |
Client.surname.ilike(f"%{word}%")
# Order.item_id.cast('text') == f"%{word}%"
# Order.item_id.cast('text').like(f"%{word}%")
# Order.item_id.cast(TextField()).ilike(f"%{word}%")
)
.distinct()
for word in self.query_list
)
print('query list', self.query_list)
for i, query in enumerate(queries):
if i == 0:
self.items = query
else:
self.items = self.items & query
self.items = self.items.order_by(Order.item_id)
print("items", self.items)
Вывод в консоль с принтов с кода выше:
query list ['2199']
items SELECT "t1"."item_id", "t1"."client", "t1"."trouble", "t1"."pic_path", "t1"."pic_id", "t1"."oriented_timestamp", "t1"."status", "t1"."predefined_price", "t1"."price", "t1"."prepayment", "t1"."payment", "t1"."delivery_check", "t1"."geo_check", "t1"."address_check", "t1"."call_check", "t1"."high_priority", "t1"."creator", "t1"."added" FROM "orders_clients" AS "t1" INNER JOIN "comments_orders" AS "t2" ON ("t2"."order_id" = "t1"."item_id") INNER JOIN "numbs_clients" AS "t3" ON ("t3"."client_id" = "t1"."client") INNER JOIN "clients" AS "t4" ON ("t4"."item_id" = "t1"."client") INNER JOIN "devices" AS "t5" ON ("t5"."order_id" = "t1"."item_id") WHERE ((((((((((CAST("t1"."item_id" AS text) ILIKE '%2199%') OR ("t2"."comment" ILIKE '%2199%')) OR ("t3"."number" ILIKE '%2199%')) OR ("t1"."trouble" ILIKE '%2199%')) OR ("t5"."brand_name" ILIKE '%2199%')) OR ("t5"."model_name" ILIKE '%2199%')) OR ("t5"."color" ILIKE '%2199%')) OR ("t5"."imei" ILIKE '%2199%')) OR ("t4"."name" ILIKE '%2199%')) OR ("t4"."surname" ILIKE '%2199%')) ORDER BY "t1"."item_id"
Простой селект работает корректно (для комментаторов) :
order = Order().get(Order == 1234)
orders = Order().select().where(Order.status == "in_work")
Ниже прикрепил скриншот с Explain обоих запросов. Один возвращает данные другой нет
Я протестировал кучу разных записей и он ровно находит согласно запросу записи только с нечетным числом в PK среди тех записей, которые должны найтись с совпадением по PK (item_id == %value%)