查询参数的语法错误,用于百分比计算

时间:2017-11-06 17:29:33

标签: python sql-server python-3.x sql-server-2014 pyodbc

我有一个pyodbc查询工作正常但我正在尝试应用更新来为结果添加新的计算字段。工作查询是:

cursor = cnxn.cursor()
cursor.execute("SELECT RestaurantLocation.ID, Restaurant.DisplayName FROM 
    Restaurant INNER JOIN RestaurantLocation ON Restaurant.ID = 
    RestaurantLocation.Restaurant_ID WHERE (RestaurantLocation.Active = 1)")
row = cursor.fetchall()

columns = [column[0] for column in cursor.description]
for ID,DisplayName in row:
    DisplayName = DisplayName.replace(" ","")
    cursor = cnxn.cursor()
    cursor.execute("SET NOCOUNT ON; SELECT ScheduledService.ServiceDate, 
    Restaurant.DisplayName AS RestaurantName, InvoiceLineItem.Invoice_ID, 
    ScheduledRestaurantService.Location_ID, ScheduledService.Service_ID, 
    Service.DisplayName AS ServiceName, InvoiceLineItem.Description, 
    InvoiceLineItem.Amount AS 'Subtotal' INTO #Subtotal FROM 
    ScheduledService INNER JOIN Invoice ON ScheduledService.Invoice_ID = 
    Invoice.ID INNER JOIN InvoiceLineItem ON Invoice.ID = 
    InvoiceLineItem.Invoice_ID INNER JOIN Payment ON Invoice.ID = 
    Payment.RelatedInvoice_ID INNER JOIN ScheduledRestaurantService ON 
    ScheduledService.ID = ScheduledRestaurantService.ID INNER JOIN 
    RMenuAllocatedScheduleSlot ON ScheduledRestaurantService.TimeSlot_ID = 
    RMenuAllocatedScheduleSlot.ID INNER JOIN [User] ON 
    ScheduledService.RelatedUser_ID = [User].ID INNER JOIN 
    RestaurantLocation ON ScheduledRestaurantService.Location_ID = 
    RestaurantLocation.ID INNER JOIN Restaurant ON 
    RestaurantLocation.Restaurant_ID = Restaurant.ID INNER JOIN Service ON 
    ScheduledService.Service_ID = Service.ID WHERE 
    (ScheduledService.ServiceDate BETWEEN ? AND ?) AND (NOT 
    (ScheduledService.Status_ID = 6)) AND (ScheduledService.Service_ID IN 
    (17, 18, 23, 24, 25)) AND (InvoiceLineItem.Description IN ('Subtotal')) 
    AND (ScheduledRestaurantService.Location_ID = ?) SELECT 
    #Subtotal.Invoice_ID, InvoiceLineItem.Amount AS 'SalesTax' INTO 
    #SalesTax FROM #Subtotal LEFT OUTER JOIN InvoiceLineItem ON 
    #Subtotal.Invoice_ID = InvoiceLineItem.Invoice_ID WHERE 
    (InvoiceLineItem.Description IN ('Sales Tax')) SELECT 
    #Subtotal.Invoice_ID, CASE WHEN #Subtotal.Service_ID IN (17,23,25,26) 
    THEN 0.00 ELSE InvoiceLineItem.Amount END AS 'Tip' INTO #Tip FROM 
    #Subtotal LEFT OUTER JOIN InvoiceLineItem ON #Subtotal.Invoice_ID = 
    InvoiceLineItem.Invoice_ID WHERE (InvoiceLineItem.Description IN 
    ('Tip')) Select #Subtotal.ServiceDate, #Subtotal.RestaurantName, 
    #Subtotal.Invoice_ID, #Subtotal.Location_ID, #Subtotal.Service_ID, 
    #Subtotal.Subtotal, #SalesTax.SalesTax, #Tip.Tip Into #Final From 
    #Subtotal LEFT OUTER JOIN #SalesTax ON #Subtotal.Invoice_ID = 
    #SalesTax.Invoice_ID LEFT OUTER JOIN #Tip ON #Subtotal.Invoice_ID = 
    #Tip.Invoice_ID SET NOCOUNT OFF; Select * From #Final Order By 
    #Final.Service_ID, #Final.ServiceDate Drop Table #Subtotal Drop Table 
    #SalesTax Drop Table #Tip Drop Table #Final", (firstDay,lastDay,ID))
    rows = cursor.fetchall()

那里的一切都很好。第二个查询的结果基于第一个查询中创建的唯一ID。

但是当我尝试向第二个查询添加一个新的计算字段时,我从SQL Db中得到一个“不正确的语法错误”。这是更新的查询:

cursor = cnxn.cursor()
cursor.execute("SELECT RestaurantLocation.ID, Restaurant.DisplayName FROM 
    Restaurant INNER JOIN RestaurantLocation ON Restaurant.ID = 
    RestaurantLocation.Restaurant_ID WHERE (RestaurantLocation.Active = 1)")
row = cursor.fetchall()

columns = [column[0] for column in cursor.description]
for ID,DisplayName in row:
    DisplayName = DisplayName.replace(" ","")
    cursor = cnxn.cursor()
    print(firstDay,lastDay,ID)
    if ID == 13:
        percentage = 0.18
    else:
        if ID == 25:
            percentage = 0.18
        else:
            percentage = 0.20
    cursor.execute("SET NOCOUNT ON; SELECT ScheduledService.ServiceDate, 
        Restaurant.DisplayName AS RestaurantName, 
        InvoiceLineItem.Invoice_ID, ScheduledRestaurantService.Location_ID, 
        ScheduledService.Service_ID, Service.DisplayName AS ServiceName, 
        InvoiceLineItem.Description, InvoiceLineItem.Amount AS 'Subtotal' 
        INTO #Subtotal FROM ScheduledService INNER JOIN Invoice ON 
        ScheduledService.Invoice_ID = Invoice.ID INNER JOIN InvoiceLineItem 
        ON Invoice.ID = InvoiceLineItem.Invoice_ID INNER JOIN Payment ON 
        Invoice.ID = Payment.RelatedInvoice_ID INNER JOIN 
        ScheduledRestaurantService ON ScheduledService.ID =                                                 
        ScheduledRestaurantService.ID INNER JOIN RMenuAllocatedScheduleSlot 
        ON ScheduledRestaurantService.TimeSlot_ID = 
        RMenuAllocatedScheduleSlot.ID INNER JOIN [User] ON 
        ScheduledService.RelatedUser_ID = [User].ID INNER JOIN 
        RestaurantLocation ON ScheduledRestaurantService.Location_ID = 
        RestaurantLocation.ID INNER JOIN Restaurant ON 
        RestaurantLocation.Restaurant_ID = Restaurant.ID INNER JOIN Service 
        ON ScheduledService.Service_ID = Service.ID WHERE 
        (ScheduledService.ServiceDate BETWEEN ? AND ?) AND (NOT 
        (ScheduledService.Status_ID = 6)) AND (ScheduledService.Service_ID 
        IN (17, 18, 23, 24, 25)) AND (InvoiceLineItem.Description IN 
        ('Subtotal')) AND (ScheduledRestaurantService.Location_ID = ?) 
        SELECT #Subtotal.Invoice_ID, InvoiceLineItem.Amount AS 'SalesTax' 
        INTO #SalesTax FROM #Subtotal LEFT OUTER JOIN InvoiceLineItem ON 
        #Subtotal.Invoice_ID = InvoiceLineItem.Invoice_ID WHERE 
        (InvoiceLineItem.Description IN ('Sales Tax')) SELECT 
        #Subtotal.Invoice_ID, CASE WHEN #Subtotal.Service_ID IN 
        (17,23,25,26) THEN 0.00 ELSE InvoiceLineItem.Amount END AS 'Tip' 
        INTO #Tip FROM #Subtotal LEFT OUTER JOIN InvoiceLineItem ON 
        #Subtotal.Invoice_ID = InvoiceLineItem.Invoice_ID WHERE 
        (InvoiceLineItem.Description IN ('Tip')) Select 
        #Subtotal.ServiceDate, #Subtotal.RestaurantName, 
        #Subtotal.Invoice_ID, #Subtotal.Location_ID, #Subtotal.Service_ID, 
        #Subtotal.Subtotal, #SalesTax.SalesTax, #Subtotal.Subtotal * .? AS 
        Discount, #Tip.Tip Into #Final From #Subtotal LEFT OUTER JOIN 
        #SalesTax ON #Subtotal.Invoice_ID = #SalesTax.Invoice_ID LEFT OUTER 
        JOIN #Tip ON #Subtotal.Invoice_ID = #Tip.Invoice_ID SET NOCOUNT OFF; 
        Select * From #Final Order By #Final.Service_ID, #Final.ServiceDate 
        Drop Table #Subtotal Drop Table #SalesTax Drop Table #Tip Drop Table 
        #Final", (firstDay,lastDay,ID,percentage))
    rows = cursor.fetchall()

错误是由我分配给“百分比”的值引发的。我首先尝试使用int()来解决这个问题,所以我的IF语句变为:

if ID == 13:
    percentage = int(0.18)
else:
    if ID == 25:
        percentage = int(0.18)
    else:
        percentage = int(0.20)

我的错误是没有识别int()是使用无小数位转换的。所以我更新了IF语句以使用float():

if ID == 13:
        percentage = float(0.18)
    else:
        if ID == 25:
            percentage = float(0.18)
        else:
            percentage = float(0.20)

使用float()设置“百分比”后,我从SQL得到完全相同的错误。我已尝试过上述IF语句的多种变体,但它们都会导致完全相同的错误。

我做错了什么?

1 个答案:

答案 0 :(得分:1)

错误是由第四个参数占位符之前的句点(小数点)引起的:

... #Subtotal.Subtotal * .? AS Discount

这导致pyodbc使用类似

的查询调用sp_prepexec
SELECT ... #Subtotal.Subtotal * .@P1 AS Discount FROM #Subtotal

这是无效的语法。

参数占位符应始终独立显示,并且永远不要依赖分隔符或命令文本的其他元素来修改其行为。在这种情况下,

sql = "SELECT id, Subtotal, #Subtotal.Subtotal * ? AS Discount FROM #Subtotal"
params = (Decimal('0.05'),)
crsr.execute(sql, params)

发送

exec sp_prepexec @p1 output,N'@P1 numeric(3,3)',N'SELECT id, Subtotal, #Subtotal.Subtotal * @P1 AS Discount FROM #Subtotal',50

并执行且没有错误。