@Ambulate

Почему Postgres возвращает только нечетные записи при поиске, включающем pkey?

При поиске по содержимому 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.
63e81b3ebbc9a834345084.png

Модель 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 обоих запросов. Один возвращает данные другой нет
63e7e0291c002550541668.png

Я протестировал кучу разных записей и он ровно находит согласно запросу записи только с нечетным числом в PK среди тех записей, которые должны найтись с совпадением по PK (item_id == %value%)
  • Вопрос задан
  • 153 просмотра
Пригласить эксперта
Ответы на вопрос 1
@Zerg89
А почему у вас по запросу 2199 выдало ещё и 871, значит что-то делаете не правильно, скорее всего ищите не по одной таблице а по всем подключённым при любом совпадения с 2199 в нескольких таблицах одновременно и поидее если ремонт завершён то из выдачи это должно убиратся как минимум сразу выборку по рабочим задачам делать
Скорее всего проблема здесь
ILIKE ~=
LIKE ==
Ps postgress глубоко не копал
Но это трындец
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%')
Причём если
CAST("t1"."item_id" AS text) ILIKE '%2200%') =0 и упоминания именно числа нет то 0 в конце так как as text только в первой стоке а может и на оборот потому что там не текст
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы