Использование выражения CASE внутри предложения SELECT

avatar
Lirum
8 апреля 2018 в 00:08
395
1
0

У меня большие трудности с репликацией результирующего набора с помощью SQLAlchemy, который я могу сгенерировать с помощью SQL. Большая проблема заключается в том, что мне трудно понять, как правильно создать специальный столбец, который можно вставить в качестве аргумента в query(). Во-вторых, меня смущают различия в целях и реализации между ORM и языком выражений.

Вот мои модели:

class User(db.Model):

    id = db.Column(db.Integer, primary_key=True)

    sz_shirt_dress_sleeve = db.relationship(
    'SizeKeyShirtDressSleeve', secondary=LinkUserSizeShirtDressSleeve, backref=db.backref('users', lazy='dynamic'))

LinkUserSizeShirtDressSleeve = db.Table(
    'link_user_size_shirt_dress_sleeve',
    db.Column('size_id', db.Integer, db.ForeignKey('size_key_shirt_dress_sleeve.id'), primary_key=True),
    db.Column('user_id', db.Integer, db.ForeignKey('user.id'), primary_key=True)
)

class SizeKeyShirtDressSleeve(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    size = db.Column(db.Numeric(4,2))

Я пытаюсь реплицировать этот SQL:

SELECT  
    size, 
    case    WHEN link_user_size_shirt_dress_sleeve.size_id IS NOT NULL
            THEN 'true' ELSE 'false' END AS present
    FROM size_key_shirt_dress_sleeve 
    LEFT JOIN link_user_size_shirt_dress_sleeve
    ON size_key_shirt_dress_sleeve.id = link_user_size_shirt_dress_sleeve.size_id
;

Вещи, которые я пробовал, не сработали. (Если вы можете сделать вывод о каких-либо ошибочных мыслях, читая их, укажите на них.)

Настройка CASE заранее:

case = ([(LinkUserSizeShirtDressSleeve.c.size_id != None, True)], else_=False)

query = db.session.query(SizeKeyShirtDressSleeve.size, case)
    .outerjoin(LinkUserSizeShirtDressSleeve, SizeKeyShirtDressSleeve.id == LinkUserSizeShirtDressSleeve.size_id, )
    .filter(LinkUserSizeShirtDressSleeve.id == 1)

Моя оболочка python ругается, что есть синтаксическая ошибка с else_=False, хотя я считаю, что это так же, как оно представлено в документации для case:

>>> case = ([(LinkUserSizeShirtDressSleeve.c.size_id != None, True)], else_= False)
  File "<stdin>", line 1
    case = ([(LinkUserSizeShirtDressSleeve.c.size_id != None, True)], else_= False)
                                                                           ^
SyntaxError: invalid syntax

Если я пропущу else_ и выполню следующее:

case = ([(LinkUserSizeShirtDressSleeve.c.size_id != None, True)])

query = db.session.query(SizeKeyShirtDressSleeve.size, case)
    .outerjoin(LinkUserSizeShirtDressSleeve, SizeKeyShirtDressSleeve.id == LinkUserSizeShirtDressSleeve.size_id, )
    .filter(LinkUserSizeShirtDressSleeve.id == 1)

Я все еще ошибка:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/lirum/Envs/LTF-PhP3R-bs/lib/python3.6/site-packages/sqlalchemy/orm/scoping.py", line 153, in do
    return getattr(self.registry(), name)(*args, **kwargs)
  File "/Users/lirum/Envs/LTF-PhP3R-bs/lib/python3.6/site-packages/sqlalchemy/orm/session.py", line 1399, in query
    return self._query_cls(entities, self, **kwargs)
  File "/Users/lirum/Envs/LTF-PhP3R-bs/lib/python3.6/site-packages/sqlalchemy/orm/query.py", line 140, in __init__
    self._set_entities(entities)
  File "/Users/lirum/Envs/LTF-PhP3R-bs/lib/python3.6/site-packages/sqlalchemy/orm/query.py", line 149, in _set_entities
    entity_wrapper(self, ent)
  File "/Users/lirum/Envs/LTF-PhP3R-bs/lib/python3.6/site-packages/sqlalchemy/orm/query.py", line 3999, in __init__
    "expected - got '%r'" % (column, )
sqlalchemy.exc.InvalidRequestError: SQL expression, column, or mapped entity expected - got '[(<sqlalchemy.sql.elements.BinaryExpression object at 0x10f633240>  True)]'
>>> 

И я тоже не понимаю это сообщение об ошибке. Может ли это означать, что мне нужно обернуть случай в экземпляр Column или column_literal? Я не очень хорошо их понимаю, но я видел их в документах, и ошибка намекает на это. Хотя, боже, я бы хотел, чтобы это было просто формирование случая.

Контекст того, что я пытаюсь сделать:

Я пишу представление, которое будет генерировать страницу со списком всех размеров пользователя (в том числе рукава), а также всех возможных размеров (рукава) (пользователь может быть связан с несколькими размерами). Возможные размеры втулки варьируются от 30,0 до 38,0 с шагом 0,5. Например, пользователь с идентификатором 1 связан с размерами 30.0, 30.5, 31.0 и 32.0. В конечном итоге результирующий набор выглядит так (заголовки не нужны):

Size        |   UserIsAssociated
--------|-------------------
30.0    |   True
30.5    |   True
31.0    |   True
31.5    |   False
32.0    |   True
32.5    |   False
33.0    |   False
...
38.0    |   False
Источник
Ilja Everilä
8 апреля 2018 в 05:44
0

case — это функция, вы должны вызвать ее и присвоить результат какому-то непересекающемуся имени: has_size = case([(...)], else_=...). Последняя ошибка означает, что вы не можете передать простой список из двух кортежей в Query как сущность.

Ilja Everilä
8 апреля 2018 в 06:28
0

Кроме того, если вы хотите получить логическое значение на основе size_id, вам вообще не нужен регистр. Просто используйте LinkUserSizeShirtDressSleeve.c.size_id != None.

Lirum
8 апреля 2018 в 21:38
0

...правильно. case() — это функция. Вот это да. И мне это даже не понадобилось, чтобы получить логическое значение. Я думаю, что у меня есть то, что я хочу. Большое спасибо Илья!

Ответы (1)

avatar
RiyajKhan
8 апреля 2018 в 08:05
-2

Я не могу понять вопрос...

Я думаю, вы хотите отобразить «Истина», если идентификатор размера не равен нулю, иначе ложь

поэтому напишите ниже запрос

выберите размер с., случай, когда s.size_id имеет значение null, тогда «False», иначе «True» заканчивается как настоящее -- или это может быть похоже на -- случай, когда s.size_id не равен нулю, тогда 'True', иначе 'False' завершается как настоящее от size_key_shirt_dress_sleeve s ЛЕВОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ link_user_size_shirt_dress_sleeve m на m.id=s.size_id

или вы можете использовать метод isnull, например

выбрать размер, isnull (s.size_id, 'Ложь') от size_key_shirt_dress_sleeve s ЛЕВОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ link_user_size_shirt_dress_sleeve m на m.id=s.size_id

Надеюсь, это поможет вам, спасибо!