developer tip

단일 열을 반환하는 SQL Alchemy ORM, 일반적인 사후 처리를 방지하는 방법

copycodes 2020. 11. 12. 08:25
반응형

단일 열을 반환하는 SQL Alchemy ORM, 일반적인 사후 처리를 방지하는 방법


SQL Alchemy의 ORM을 사용하고 있는데 단일 열을 반환하면 다음과 같은 결과가 나타납니다.

[(result,), (result_2,)] # etc...

이와 같은 세트를 사용하면이 작업을 자주 수행해야합니다.

results = [r[0] for r in results] # So that I just have a list of result values

내 결과 집합이 일반적으로 작기 때문에 "나쁜"것은 아니지만 그렇지 않으면 상당한 오버 헤드가 추가 될 수 있습니다. 가장 큰 문제는 소스를 복잡하게 만들고이 단계를 놓치는 것은 제가 겪는 매우 일반적인 오류입니다.

이 추가 단계를 피할 수있는 방법이 있습니까?

관련 측면 :이 경우 orm의이 동작이 불편 해 보이지만 내 결과 집합이 [(id, value)] 인 또 다른 경우는 다음과 같이 끝납니다.

[(result_1_id, result_1_val), (result_2_id, result_2_val)]

그런 다음 할 수 있습니다.

results = dict(results) # so I have a map of id to value

이것은 결과를 반환 한 후 유용한 단계로 이해하는 장점이 있습니다.

이것이 정말로 문제입니까? 아니면 그냥 멍청하고 결과 세트를 얻은 후 사후 처리가 두 경우 모두 의미가 있습니까? 응용 프로그램 코드에서 결과 집합을 더 유용하게 만들기 위해 다른 일반적인 사후 처리 작업을 생각할 수 있다고 확신합니다. 전반적으로 고성능 및 편리한 솔루션이 있습니까? 아니면 사후 처리가 불가피하고 다양한 애플리케이션 용도에만 필요한가요?

내 응용 프로그램이 실제로 SQL Alchemy의 ORM에서 반환하는 개체를 활용할 수 있다면 매우 유용 해 보이지만 할 수 없거나 그렇지 않은 경우에는 그다지 많지 않습니다. 이것은 일반적으로 ORM의 일반적인 문제입니까? 이와 같은 경우 ORM 레이어를 사용하지 않는 것이 더 낫습니까?

내가 말하는 실제 orm 쿼리의 예를 보여 주어야한다고 생각합니다.

session.query(OrmObj.column_name).all()

또는

session.query(OrmObj.id_column_name, OrmObj.value_column_name).all()

물론 실제 쿼리에는 일반적으로 일부 필터 등이 있습니다.


* 인라인 확장 연산자와 결합 된 Python의 zip은 이에 대한 매우 편리한 솔루션입니다.

>>> results = [('result',), ('result_2',), ('result_3',)]
>>> zip(*results)
[('result', 'result_2', 'result_3')]

그런 다음 한 번만 [0] 인덱싱하면됩니다. 이러한 짧은 목록의 경우 이해가 더 빠릅니다.

>>> timeit('result = zip(*[("result",), ("result_2",), ("result_3",)])', number=10000)
0.010490894317626953
>>> timeit('result = [ result[0] for result in [("result",), ("result_2",), ("result_3",)] ]', number=10000)
0.0028390884399414062

그러나 긴 목록의 경우 zip이 더 빠릅니다.

>>> timeit('result = zip(*[(1,)]*100)', number=10000)
0.049577951431274414
>>> timeit('result = [ result[0] for result in [(1,)]*100 ]', number=10000)
0.11178708076477051

따라서 어떤 것이 귀하의 상황에 더 적합한 지 결정하는 것은 귀하에게 달려 있습니다.


소스의 혼란을 줄이는 한 가지 방법은 다음과 같이 반복하는 것입니다.

results = [r for (r, ) in results]

이 솔루션은 []연산자를 사용하는 것보다 한 문자 더 길지만 눈에는 더 쉽다고 생각합니다.

깔끔하게 정리하려면 괄호를 제거하세요. 이렇게하면 코드를 읽을 때 실제로 튜플을 처리하고 있음을 알기가 더 어려워집니다.

results = [r for r, in results]

나는 다른 쿼리와 똑같다는 것을 깨달을 때까지 이것으로도 고생했습니다.

for result in results:
     print result.column_name

I found the following more readable, also includes the answer for the dict (in Python 2.7):

d = {id_: name for id_, name in session.query(Customer.id, Customer.name).all()}
l = [r.id for r in session.query(Customer).all()]

For the single value, borrowing from another answer:

l = [name for (name, ) in session.query(Customer.name).all()]

Compare with the built-in zip solution, adapted to the list:

l = list(zip(*session.query(Customer.id).all())[0])

which in my timeits provides only about 4% speed improvements.


My solution looks like this ;)

def column(self):
    for column, *_ in Model.query.with_entities(Model.column).all():
        yield column

NOTE: py3 only.


Wow, guys, why strain? There are method steeper way, faster and more elegant)

>>> results = [('result',), ('result_2',), ('result_3',)]
>>> sum(results, tuple())
('result', 'result_2', 'result_3')

Speed:

>>> timeit('result = zip(*[("result",), ("result_2",), ("result_3",)])', number=10000)
0.004222994000883773
>>> timeit('result = sum([("result",), ("result_2",), ("result_3",)], ())', number=10000)
0.0038205889868550003

But if more elements in list - use only zip. Zip more speed.

참고URL : https://stackoverflow.com/questions/9486180/sql-alchemy-orm-returning-a-single-column-how-to-avoid-common-post-processing

반응형