2016-05-05 7 views
6

मैं SQL सर्वर में एक क्वेरी का उपयोग कर रहा हूं जिसके लिए यह जांचने के लिए एक सीमा की आवश्यकता है कि उस श्रेणी में कोई संख्या है (उदाहरण के लिए नीचे DemographicGroupDimID है या नहीं । या तो (1,2 या 3) मुझे लगता है कि ऐसा करने में सक्षम हो पाया एक ही रास्ता googling कुछ करने के बाद नीचे था:पैरामीटर के साथ SQL सर्वर से पढ़ना: पांडा (या pyodbc) ठीक से काम नहीं कर रहा है

एसक्यूएल

DECLARE @adults table (Id int) 
INSERT INTO @adults VALUES (1), (2), (3) 

SELECT [date], [station], [impression] = SUM([impressions])/COUNT(DISTINCT [datetime]) 
     FROM 
     (SELECT [datetime] = DATEADD(minute,td.Minute,DATEADD(hour,td.NielsenLocalHour,CONVERT(smalldatetime, ddt.DateKey))), [date] = ddt.DateKey, [station] = nd.Name, [impressions] = SUM(naf.Impression) 
     FROM [Nielsen].[dbo].[NielsenAnalyticsFact] as naf 
     LEFT JOIN [dbo].[DateDim] AS ddt 
     ON naf.StartDateDimID = ddt.DateDimID 
     LEFT JOIN [dbo].NetworkDim as nd 
     ON naf.NetworkDimID = nd.NetworkDimID 
     LEFT JOIN [dbo].TimeDim as td 
     ON naf.QuarterHourDimID = td.TimeDimID 
     WHERE (naf.NielsenMarketDimID = 1 
        AND naf.RecordTypeDimID = 2 
        AND naf.AudienceEstimateTypeDimID = 1 
        AND naf.DailyOrWeeklyDimID = 1 
        AND naf.RecordSequenceCodeDimID = 5 
        AND naf.ViewingTypeDimID = 4 
        AND naf.QuarterHourDimID IS NOT NULL 
        AND naf.DemographicGroupDimID < 31 
        AND nd.Affiliation = 'Cable' 
        AND naf.NetworkDimID != 1278 
        AND naf.DemographicGroupDimID in (SELECT Id FROM @adults)) 
     GROUP BY DATEADD(minute,td.Minute,DATEADD(hour,td.NielsenLocalHour,CONVERT(smalldatetime, ddt.DateKey))), nd.Name, ddt.DateKey) 
AS grouped_table 
GROUP BY [date], [station] 
ORDER BY [date], [station] 

मैं गतिशील अलग के साथ ऐसा करना चाहते हैं तो श्रेणियां, यह विफल हो जाती है, जैसे:

पांडा क्वेरी

from queries import DB_CREDENTIALS 
import pyodbc 
import pandas as pd 

sql_ = """DECLARE @adults table (Id int) 
INSERT INTO @adults VALUES ? 

SELECT [date], [station], [impression] = SUM([impressions])/COUNT(DISTINCT [datetime]) 
     FROM 
     (SELECT [datetime] = DATEADD(minute,td.Minute,DATEADD(hour,td.NielsenLocalHour,CONVERT(smalldatetime, ddt.DateKey))), [date] = ddt.DateKey, [station] = nd.Name, [impressions] = SUM(naf.Impression) 
     FROM [Nielsen].[dbo].[NielsenAnalyticsFact] as naf 
     LEFT JOIN [dbo].[DateDim] AS ddt 
     ON naf.StartDateDimID = ddt.DateDimID 
     LEFT JOIN [dbo].NetworkDim as nd 
     ON naf.NetworkDimID = nd.NetworkDimID 
     LEFT JOIN [dbo].TimeDim as td 
     ON naf.QuarterHourDimID = td.TimeDimID 
     WHERE (naf.NielsenMarketDimID = 1 
        AND naf.RecordTypeDimID = 2 
        AND naf.AudienceEstimateTypeDimID = 1 
        AND naf.DailyOrWeeklyDimID = 1 
        AND naf.RecordSequenceCodeDimID = 5 
        AND naf.ViewingTypeDimID = 4 
        AND naf.QuarterHourDimID IS NOT NULL 
        AND naf.DemographicGroupDimID < 31 
        AND nd.Affiliation = 'Cable' 
        AND naf.NetworkDimID != 1278 
        AND naf.DemographicGroupDimID in (SELECT Id FROM @adults)) 
     GROUP BY DATEADD(minute,td.Minute,DATEADD(hour,td.NielsenLocalHour,CONVERT(smalldatetime, ddt.DateKey))), nd.Name, ddt.DateKey) 
AS grouped_table 
GROUP BY [date], [station] 
ORDER BY [date], [station]""" 

with pyodbc.connect(DB_CREDENTIALS) as cnxn: 
    df = pd.read_sql(sql=sql_, con=cnxn, params=['(30)']) 

त्रुटि:

--------------------------------------------------------------------------- 
DatabaseError        Traceback (most recent call last) 
<ipython-input-5-4b63847d007f> in <module>() 
     1 with pyodbc.connect(DB_CREDENTIALS) as cnxn: 
----> 2  df = pd.read_sql(sql=sql_, con=cnxn, params=['(30)']) 

C:\Users\mburke\AppData\Local\Continuum\Anaconda64\lib\site-packages\pandas\io\sql.pyc in read_sql(sql, con, index_col, coerce_float, params, parse_dates, columns, chunksize) 
    497    sql, index_col=index_col, params=params, 
    498    coerce_float=coerce_float, parse_dates=parse_dates, 
--> 499    chunksize=chunksize) 
    500 
    501  try: 

C:\Users\mburke\AppData\Local\Continuum\Anaconda64\lib\site-packages\pandas\io\sql.pyc in read_query(self, sql, index_col, coerce_float, params, parse_dates, chunksize) 
    1593 
    1594   args = _convert_params(sql, params) 
-> 1595   cursor = self.execute(*args) 
    1596   columns = [col_desc[0] for col_desc in cursor.description] 
    1597 

C:\Users\mburke\AppData\Local\Continuum\Anaconda64\lib\site-packages\pandas\io\sql.pyc in execute(self, *args, **kwargs) 
    1570    ex = DatabaseError(
    1571     "Execution failed on sql '%s': %s" % (args[0], exc)) 
-> 1572    raise_with_traceback(ex) 
    1573 
    1574  @staticmethod 

C:\Users\mburke\AppData\Local\Continuum\Anaconda64\lib\site-packages\pandas\io\sql.pyc in execute(self, *args, **kwargs) 
    1558     cur.execute(*args, **kwargs) 
    1559    else: 
-> 1560     cur.execute(*args) 
    1561    return cur 
    1562   except Exception as exc: 

DatabaseError: Execution failed on sql 'DECLARE @adults table (Id int) 
INSERT INTO @adults VALUES ? 

SELECT [date], [station], [impression] = SUM([impressions])/COUNT(DISTINCT [datetime]) 
     FROM 
     (SELECT [datetime] = DATEADD(minute,td.Minute,DATEADD(hour,td.NielsenLocalHour,CONVERT(smalldatetime, ddt.DateKey))), [date] = ddt.DateKey, [station] = nd.Name, [impressions] = SUM(naf.Impression) 
     FROM [Nielsen].[dbo].[NielsenAnalyticsFact] as naf 
     LEFT JOIN [dbo].[DateDim] AS ddt 
     ON naf.StartDateDimID = ddt.DateDimID 
     LEFT JOIN [dbo].NetworkDim as nd 
     ON naf.NetworkDimID = nd.NetworkDimID 
     LEFT JOIN [dbo].TimeDim as td 
     ON naf.QuarterHourDimID = td.TimeDimID 
     WHERE (naf.NielsenMarketDimID = 1 
        AND naf.RecordTypeDimID = 2 
        AND naf.AudienceEstimateTypeDimID = 1 
        AND naf.DailyOrWeeklyDimID = 1 
        AND naf.RecordSequenceCodeDimID = 5 
        AND naf.ViewingTypeDimID = 4 
        AND naf.QuarterHourDimID IS NOT NULL 
        AND naf.DemographicGroupDimID < 31 
        AND nd.Affiliation = 'Cable' 
        AND naf.NetworkDimID != 1278 
        AND naf.DemographicGroupDimID in (SELECT Id FROM @adults)) 
     GROUP BY DATEADD(minute,td.Minute,DATEADD(hour,td.NielsenLocalHour,CONVERT(smalldatetime, ddt.DateKey))), nd.Name, ddt.DateKey) 
AS grouped_table 
GROUP BY [date], [station] 
ORDER BY [date], [station]': ('42000', "[42000] [Microsoft][ODBC SQL Server Driver][SQL Server]Incorrect syntax near '@P1'. (102) (SQLExecDirectW); [42000] [Microsoft][ODBC SQL Server Driver][SQL Server]Statement(s) could not be prepared. (8180)") 

इस वजह घोषणा बयान का चयन बयान खुद की सीमा के भीतर होने की जरूरत है है? मुझे यकीन नहीं है कि pandaspyodbc कर्सर ऑब्जेक्ट को संभालता है, इसलिए मुझे यह पता नहीं है कि यह त्रुटि कहां से उत्पन्न होती है।

संपादित करें: बस ध्यान दें, इस उदाहरण में पारित पैराम (30) बस उस साधारण मामले का उपयोग करने के लिए होता है जब असफलता में केवल एक संख्या होती है। यह निश्चित रूप से ऊपर के उदाहरण के मामले में (1), (2), (3) जैसे अधिक जटिल तारों के लिए विफल रहता है।

+0

एक अतिरिक्त नोट: यदि पैरा को वास्तविक मान के साथ प्रतिस्थापित किया गया है तो यह क्वेरी ठीक काम करती है। तो शायद एक वर्कअराउंड सिर्फ SQL क्वेरी स्ट्रिंग को गतिशील रूप से प्रारूपित करना होगा। – mburke05

+0

दो चीजें: 1) एसक्यूएल के 'IN (?,?,?) 'खंड का उपयोग क्यों नहीं करते हैं यदि एक पूर्णांक पूर्णांक स्केलर पास करते हैं; या 2) पैराम में गुजरने वाली संग्रहीत प्रक्रिया को क्यों न बुलाएं? – Parfait

उत्तर

5

यदि आप अपने SQL में prepared statements का उपयोग करते हैं, तो आप एक प्लेसहोल्डर/पैरामीटर/बाइंड वैरिएबल के लिए एकाधिक मान नहीं डाल सकते हैं!

इस आप केवल literals के स्थान पर प्लेसहोल्डर/मानकों/बाँध चर का उपयोग कर सकते हैं के अलावा, आप SQL विवरण का हिस्सा जो है नहीं एक शाब्दिक के लिए इसका इस्तेमाल नहीं कर सकते हैं।

अपने मामले में आप ( और ) जो SQL का हिस्सा है, लेकिन नहीं पैरामीटर के रूप में एक शाब्दिक डालने की कोशिश की।

पैरामीटर/तैयार कथन/बाइंड वैरिएबल का उपयोग करने से आपको कुछ एसक्यूएल इंजेक्शन से भी बचाया जाएगा।

कि ने कहा, अपने कोड को बदलने के लिए इस प्रकार का प्रयास करें:

परिवर्तन

INSERT INTO @adults VALUES ? 

को
INSERT INTO @adults VALUES (?) 

और

df = pd.read_sql(sql=sql_, con=cnxn, params=['(30)']) 

करने के लिए
df = pd.read_sql(sql=sql_, con=cnxn, params=['30']) 

अद्यतन:

आप अपने एसक्यूएल इस तरह से तैयार कर सकते हैं:

In [9]: vals = [20,30,40] 

In [32]: vals 
Out[32]: [20, 30, 40] 

In [33]: ' (?)' * len(vals) 
Out[33]: ' (?) (?) (?)' 

तो: पर

In [14]: sql_ = """DECLARE @adults table (Id int) 
    ....: INSERT INTO @adults VALUES {} 
    ....: 
    ....: SELECT [date], 
    ....: """ 

In [15]: sql_.format(' (?)' * len(vals)) 
Out[15]: 'DECLARE @adults table (Id int)\nINSERT INTO @adults VALUES (?) (?) (?)\n\nSELECT [date],\n' 

वेतन ध्यान उत्पन्न (?) (?) (?)

और अंत में अपने एसक्यूएल को कॉल करें:

df = pd.read_sql(sql=sql_.format(' (?)' * len(vals)), con=cnxn, params=vals) 
+0

लेकिन यह केवल उस मामले में काम करता है जहां मेरे पास एक मूल्य सही है? उदाहरण के लिए यदि मुझे 4 मानों को पारित करने की आवश्यकता है, [1,2,3,4]? क्या मुझे 'sql_' को 'VALUES (?), (?), (?), (?)' में बदलने की आवश्यकता होगी? मैं भी आपके पिछले दो वाक्यों का पालन नहीं करता (या शायद 'VALUES' कथन की भूमिका को गलत समझा) क्या आप "केवल शाब्दिक के लिए" का अर्थ समझ सकते हैं, एक स्ट्रिंग का मतलब शाब्दिक नहीं है? एक बार फिर धन्यवाद! – mburke05

+0

धन्यवाद अधिकतम, हाँ, यही वह है जिसे मैंने पाया था। लेकिन मुझे यकीन नहीं था कि शायद मैं पैराम का दुरुपयोग कर रहा था या अगर यह पांडा में एक बग था। – mburke05

+0

मैंने आपके उत्तर को अधिकतम स्वीकार कर लिया है, लेकिन मुझे लगता है कि सवाल अभी भी बनी हुई है, क्या यह पांडा/पायडबैक में अपेक्षित व्यवहार है या यह एक बग है। – mburke05

संबंधित मुद्दे