#python #sqlalchemy #flask-sqlalchemy
#python #sqlalchemy #flask-sqlalchemy
Вопрос:
Выполнение order_by
операции над запросом SQLAlchemy, где сортируемые объекты имеют одинаковое значение, всегда возвращает их в том порядке, в котором они находятся в базе данных.
Есть ли функция для дополнительного перемешивания тех результатов, которые совпадают?
Практический пример:
ITEM PRICE
hamburger 20
burrito 10
sandwich 10
quesadilla 15
Запуск db.session.query(FoodItem).order_by(FoodItem.price).all()
вернет их в следующем порядке:
- Гамбургер
- Кесадилья
- Буррито
- Сандвичи
burrito
всегда будет предшествовать sandwich
, как и раньше в базе данных, независимо от того, сколько раз вы запускали функцию.
Я попытался случайным образом отсортировать результаты перед заказом, как так:
from sqlalchemy.sql.expression import func
db.session.query(FoodItem).order_by(func.random()).order_by(FoodItem.price).all()
Однако это не дает желаемого эффекта — окончательный заказ по-прежнему сохраняется в соответствии с базой данных. Есть ли способ — sqlalchemy
или лямбда-выражение / функция Python — для достижения желаемого результата отсортированных элементов с элементами, имеющими одинаковые значения в случайном порядке?
Комментарии:
1. «всегда возвращает их в том порядке, в котором они находятся в базе данных» — это не совсем верно или гарантировано. Например, план параллельного запроса может перепутать порядок. Иными словами: в SQL нет порядка в базе данных. Единственный способ гарантировать порядок — это использовать ORDER BY . Конечно, реализация может большую часть времени считывать строки так, как будто они находятся на диске, но порядок дисков также может меняться, и разные планы читаются по-разному.
Ответ №1:
При передаче нескольких критериев необходимо использовать правильный order_by()
порядок вызовов; критерии упорядочены от наиболее значимых к наименьшим, первый order_by
параметр применяется ко всем строкам, второй — только к строкам, где первый параметр равен.
Итак, если нужно рандомизировать только товары с одинаковой ценой, поместите случайный порядок последним:
db.session.query(FoodItem).order_by(FoodItem.price).order_by(func.random())
Обратите внимание, что для этого Query.order_by()
требуется несколько критериев, поэтому вам не нужно использовать несколько вызовов:
db.session.query(FoodItem).order_by(FoodItem.price, func.random())
Таким образом, строки сначала сортируются по цене, затем, если две строки имеют одинаковую цену, используется следующий критерий, и поэтому они рандомизируются только в пределах одной ценовой группы.
Для дальнейшего использования: распечатайте свой объект запроса (без .all()
), чтобы получить представление о том, что генерируется SQL; например, используя мое лучшее предположение о том, как может выглядеть ваша модель, ваш запрос выдает:
SELECT food_item.id AS food_item_id, food_item.name AS food_item_name, food_item.price AS food_item_price
FROM food_item ORDER BY random(), food_item.price
и, поменяв местами критерии, вы получите:
SELECT food_item.id AS food_item_id, food_item.name AS food_item_name, food_item.price AS food_item_price
FROM food_item ORDER BY food_item.price, random()
Примечание: random()
специфично для PostgreSQL и SQLite, если вам нужно поддерживать другие базы данных, вам нужно будет настроить выражение.