2017-04-20 12 views
0

내가처럼 보이는 SQLAlchemy의 테이블을 가정합니다. 그래서 나는 내가 선택 가능하려면이 옵션을 변경할 수있는 옵션이 없습니다 내 응용 프로그램에서 원시 쿼리를 허용 동적으로 SQLAlchemy의 TextClause에 필터를 추가

"select name, population from Country" 

처럼 보이는 TextClause 있습니다.

런타임에 사용자가 필드 이름을 선택하고 필터링을 허용 할 필드 값을 입력 할 수있게하려고합니다. 예 : 사용자는 대륙이 아시아 인 국가의 이름과 인구 만보고 싶다고 말할 수 있습니다. 그래서 동적 필터

.where(Country.c.continent == 'Asia') 

를 추가 할 그러나 나는 TextClause.where를 추가 할 수 없습니다.

마찬가지로, 내 사용자는 num_states 그래서 내가 동적 필터를

.where(Country.c.num_states > 10) 

를 추가 할 더 (10)보다 여기서 국가 이름과 인구를 표시하도록 선택할 수 있습니다 그러나 다시 나는 TextClause.where를 추가 할 수 없습니다 .

이 문제를 해결할 수있는 옵션은 무엇입니까?

하위 쿼리는 어떤 식 으로든 여기에서 도움이 될 수 있습니까?

+0

당신은 어떤 제약을 받습니까? TextClause를 수정할 수 있습니까? 'TextClause'의 구조를 아십니까? – univerio

+0

TextClause를 수정할 수 없습니다. 나는 TextClause의 구조를 모른다. 이 프로그램은 사용자에게 표 이름 만 알려줍니다. 해당 사용자가 TextClause를 입력 한 후 사용자는 TextClause와 결합해야하는 다른 열 (예 : num_states) 및 값 (예 : 10 미만)을 정의합니다. –

답변

0

조건에 따라 필터를 추가하십시오. 필터는 sqlalchemy의 조건을 추가하는 데 사용됩니다.

Country.query.filter(Country.num_states > 10).all() 

또한이 작업을 수행 할 수 있습니다

query = Country.query.filter(Country.continent == 'Asia') 
if user_input == 'states': 
    query = query.filter(Country.num_states > 10) 
query = query.all() 
+0

여기서 TextClause를 어디에서 사용하고 있습니까? –

1

이 쿼리를 구문 분석하지 않고 일반적인 의미에서 행할 수 없습니다. 관계 대수학 용어에서 사용자는 투영 및 선택 조작을 테이블에 적용하고 선택 조작을 적용하려고합니다. 사용자는 임의의 투영법 (예 : 사용자 용품 SELECT id FROM table)을 적용 할 수 있기 때문에 항상 상단에 필터를 적용 할 수 있다고 보장 할 수 없으므로 사용자가 전에 필터 을 적용해야합니다. 즉, 사용자의 검색어를 구문 분석해야하는 SELECT id FROM (some subquery)으로 다시 작성해야합니다.

그러나 데이터베이스 엔진이 사용자를 위해 구문 분석을 수행하여 사용중인 데이터베이스에 따라 치트를 정렬 할 수 있습니다. 이를 수행하는 방법은 기본적으로 CTE로 테이블 이름을 섀도 잉함으로써 CTE와 관련됩니다.

예제를 사용하면 다음과 같이 보입니다. 사용자 공급 당신은 CTE와 country 그림자

SELECT name, population FROM country; 

조회 :

WITH country AS (
    SELECT * FROM country 
    WHERE continent = 'Asia' 
) SELECT name, population FROM country; 

유감스럽게도, SQLAlchemy의의 CTE 지원 작동 방식,이 TextClause에 대한 CTE를 생성 할 수 힘들 것입니다.이 솔루션은 기본적으로 다음과 같이 정의 편집 확장, 뭔가를 사용하여 문자열을 직접 생성하는 것입니다 : 내 테스트에서

class WrappedQuery(Executable, ClauseElement): 
    def __init__(self, name, outer, inner): 
     self.name = name 
     self.outer = outer 
     self.inner = inner 

@compiles(WrappedQuery) 
def compile_wrapped_query(element, compiler, **kwargs): 
    return "WITH {} AS ({}) {}".format(
     element.name, 
     compiler.process(element.outer), 
     compiler.process(element.inner)) 

c = Country.__table__ 
cte = select(["*"]).select_from(c).where(c.c.continent == "Asia") 
query = WrappedQuery("country", cte, text("SELECT name, population FROM country")) 
session.execute(query) 

, PostgreSQL의에서이에만 작동합니다. SQLite와 SQL Server는 모두 섀도 잉 대신 재귀 적으로 처리하며, MySQL은 CTE를 지원하지 않습니다.

0

설명서에서 이와 관련하여 좋은 것을 찾을 수 없습니다. 나는 거의 단지 문자열 처리에 의지하는 것을 끝내었다. ... 그러나 적어도 그것은 일한다! 당신은 다음 절 및 사용 WHERE 첫 번째 및 후속 것들에 대한 부울 플래그를 만들어야하지만

from sqlalchemy.sql import text 

query = """select name, population from Country""" 

if continent is not None: 
    additional_clause = """WHERE continent = {continent};""" 
    query = query + additional_clause 
    text_clause = text(
     query.format(
      continent=continent, 
     ), 
    ) 
else: 
    text_clause = text(query) 

with sql_connection() as conn: 
    results = conn.execute(text_clause) 

당신은 더 많은 조항으로이 논리를 체인도 할 수있다.