2012-09-12 2 views
0

두 개의 매개 변수가있는 SQL 문자열을 사용하여 장고 모델에서 원시 쿼리를 수행합니다. 헤드 스크래치는 문자열 대체를 사용하여 매개 변수를 채우면 매개 변수 대체를 사용할 때보 다 많은 결과를 얻는다는 것입니다. 후자의 경우 결과가 정확하며 불완전합니다. 이 코드는 다음과 같이 변경되었습니다. 정확한 SQL을 생략했습니다.매개 변수화 된 장고 원시 쿼리는 매개 변수화되지 않은 원시 쿼리와 다른 결과를 생성합니다.

# I have a long and ornate SQL statement that looks basically like this. 
sql = "SELECT blah blah WHERE something = %s AND something_else in (%s)" 

# If I do a raw query with string substitution I get more results (22) ...  
sqlInsecureFilled = sql % (divID, storeRestrictStr) 
promos_insecured = Promotions.objects.raw(sqlInsecureFilled) 

# ... than if I use a parameterized raw query, which produces (10) 
promos_secure = Promotions.objects.raw(sql, [divID, storeRestrictStr]) 

그러나 더 이상해집니다. 명령 줄에서이 작업을 수행하면 raw_query 객체 (즉, promos_secure.query)에서 SQL을 가져와 Sequel Pro 터미널에 복사 한 다음 두 쿼리 모두 동일한 수의 결과를 생성합니다 - 22! 그럼에도 불구하고 : (오히려 긴, 그래서 정확히 얘기하기 어렵다) 쿼리가 안구에 의해 동일하게 나타나는 promos_xx.query 문자열은 MySQL의 터미널에 복사 할 때, 그리고 : 그래서

In [35]: [len(list(promos_insecured)), len(list(promos_secure))] 
Out[35]: [22, 10] 

은 요약 그들은 완전한 결과 세트를 생성합니다. 전술 한 바와 같이 수행 될 때 다른 버전의 완전성에 대한 전체 22

를 반환 반면 그렇지만, 파라미터 화 된 버전이있어, 10의 결과를 promos_secure.query (promos_insecured은 동일)은 리턴

SELECT DISTINCT promotion_id, promotion_name, promotion_up_date, promotion_down_date, promotion_asset_id, promotion_notes, promotion_promo_id FROM promotions, promo_detail WHERE promotion_id = promo_detail_promotion_id AND promotion_start_date < now() AND promotion_end_date > now() AND promo_detail_cust_division_id = 1 AND promo_detail_not_expired = 1 AND promo_detail_store_id in (8214, 8217, 4952, 8194, 8198, 8162, 5010, 5011, 5012, 8219, 8182, 5048, 5076, 5095, 5096, 5102, 5109, 5131, 5156, 5160, 5161, 5165, 5166, 5173, 5182, 5198, 5200, 5201, 5202, 5203, 5227, 5228, 5229, 5230, 5232, 5233, 5234, <bunch of other comma-separated numbers omitted>, 9281) ORDER BY promotion_end_date ASC 

편집 : 어쩌면이 무슨 일이 일어나고 있는지 보여주는 가장 간결한 방법이며 이상한 이유 : 문자열 대체와

promo_u = promotions.models.Promotions.objects.raw(sql % (1, storeRestrictStr)) 
promo_s = promotions.models.Promotions.objects.raw(sql, (1, storeRestrictStr)) 

pid_u = [s.promotion_id for s in promo_u] 
pid_s = [s.promotion_id for s in promo_s] 

In [76]: [len(list(pid_u)), len(list(pid_s))] 
Out[76]: [22, 10] 

# You can see the smaller number of results is a subset of the larger. 
In [77]: [pid in pid_u for pid in pid_s] 
Out[77]: [True, True, True, True, True, True, True, True, True, True] 

# The larger number results shows no obvious pattern as to why they're missing. 
In [87]: [pid in pid_s for pid in pid_u] 
Out[87]: [False, False, False, False, True, False, False, False, True, True, True, True, 
      True, False, True, False, False, True, False, True, False, True] 

답변

2

문제는 말했다 things are not properly quoted, as they are in parameter substitution.이며, 가능성은 기대하지 않는 일을하고있다 인용. 어떤 것들은 시도 :

  • 을 지금, 당신은 문자열 (storeRestrictStr)로 ID 목록을 전달하고 있습니다. 대신 목록으로 전달하십시오.

  • Django Debug Toolbar을 설치하고 생성 된 실제 SQL과 출력을 확인하는 데 사용하십시오.

  • 10 개의 결과가 정확하고 22 개의 결과가 12 개의 잘못된 일치를 나타내거나 22 개의 결과가 정확하고 10 개의 값이 12 개 또는 그 사이에 누락되었다고 말하지 않았습니다.

+0

22가 정확하고 완전합니다. 10은 또한 정확하지만 다른 하나는 누락되었습니다. 누락 된 결과에 패턴이 있으면 감지하기에 너무 미묘합니다. 나는 당신의 다른 제안을 시도 할 것이지만, 질문 : RawQuerySet 객체로 가서 "query"속성을 얻는 것이 위에서 설명한 것처럼 실제로 실행되는 쿼리가 아닌가? – shanusmagnus

+0

RawQuerySets을 망쳐 놓지는 않았지만 효과가있을 수 있습니다. 실제 쿼리를 가져 오는 메커니즘이 있다는 것을 알고 있습니다. DjDT는 그것을 사용합니다. –

+0

제안 해 주셔서 감사합니다. Django 툴바는이 질문의 범위를 벗어나는 미묘한 차이를 보여주었습니다. 궁금한 점을 위해서 다음은 새로운 질문입니다. http://stackoverflow.com/questions/12545331/mysql-query-using-in-operator-why-different-results-w-quotes – shanusmagnus

관련 문제