连接和写入行为不符合预期

时间:2018-07-13 09:40:03

标签: python sql sql-server pyodbc

我有一个在SQL中运行的查询,该查询通过循环将结果返回到变量中,然后将其插入HTML文件中。当我通过打印到Jupyter Notebook的控制台中进行测试时,它将按预期的顺序打印日历的后30天。

但是,当我告诉它使用来连接数据时

dates = ''.join(variable)

它似乎不仅会重新排列日期,以便8月13日位于7月13日之前,而且还会在页面中重复日期div的4次。参见下面的完整代码;

from os import getenv
import pyodbc
import os

cnxn = pyodbc.connect('DRIVER={ODBC Driver 13 for SQL Server};SERVER=MYVM\SQLEXPRESS;DATABASE=MyTables;UID=test;PWD=t')

cursor = cnxn.cursor() #makes connection
cursor.execute('DECLARE @today as date SET @today = GetDate() SELECT style112, day, month, year, dayofweek, showroom_name, isbusy from ShowroomCal where Date Between @today and dateadd(month,1,@today) order by style112') #runs statement


while row is not None:
    inset = inset + ['<div class="'+ str(row.isbusy) + '"><a href="#" id="' + str(row.style112) + '" onclick="parent.updateField(field38, ' + str(row.style112) + ');">' + str(row.day) + '</a></div>']
    row = cursor.fetchone()



dates = ''.join(inset)    
f = open("C:\\tes.html",'r') # open file with read permissions
filedata = f.read() # read contents
f.close() # closes file
filedata = filedata.replace("{inset}", dates) 

#os.remove("c:\\inetpub\\wwwroot\\cal\\tes.html")



f = open("c:\\inetpub\\wwwroot\\cal\\tes.html",'w') 
f.write(filedata) # update it replacing the previous strings 
f.close() # closes the file

cnxn.close()

1 个答案:

答案 0 :(得分:2)

''.join()不会以任何方式改变顺序。如果获得不同的顺序,则数据库查询会以不同的顺序生成行。

我认为您不是在告诉数据库按日期对结果进行排序。您通过style112进行排序,并且数据库可以随意按其任意顺序对具有相同style112列值的值进行排序。如果style112不包括日期信息(固定长度的年,月,日序列),并且日期顺序很重要,请告诉数据库使用正确的顺序!这里至少要包含year, month, day

我还将重构代码,以避免二次性能行为; inset = inset + [....]表达式每次都必须创建一个新的列表对象,并将inset中的所有元素复制到该列表中。当以这种方式将N个元素添加到列表时,Python必须执行N * N个步骤。对于1000个元素,这是一百万个步骤!使用list.append()添加单个元素,这会将工作量减少到大约N步。

您可以直接在光标上循环;这会更有效,因为它可以缓冲行,这里的cursor.fetchone()不能假设您将获取更多数据。 for row in cursor:循环也更具可读性。

您还可以使用string formatting而不是字符串连接,这将有助于避免所有这些str()调用和冗余,并进一步降低性能问题;所有这些字符串串联也可以创建和重新创建很多根本不需要创建的中间字符串对象。

所以使用这个:

cnxn = pyodbc.connect(
    'DRIVER={ODBC Driver 13 for SQL Server};SERVER=MYVM\SQLEXPRESS;'
    'DATABASE=MyTables;UID=test;PWD=t')

cursor = cnxn.cursor()
cursor.execute('''
    DECLARE @today as date
    SET @today = GetDate()
    SELECT
        style112, day, month, year, dayofweek, showroom_name, isbusy
    from ShowroomCal
    where Date Between @today and dateadd(month,1,@today)
    order by year, month, day, style112
''')

inset = []
for row in cursor:
    inset.append(
        '<div class="{r.isbusy}">'
        '<a href="#" id="{r.style112}"'
        ' onclick="parent.updateField(field38, {r.style112});">'
        '{r.day}</a></div>'.format(r=row))

with open(r"C:\tes.html") as template:
    template = f.read()

html = template.format(inset=''.join(inset))

with open(r"C:\inetpub\wwwroot\cal\tes.html", 'w') as output:
    output.write(html)

注意:如果用户输入了任何数据库数据,则必须确保将数据正确转义以首先包含在HTML中 em>,否则您将对XSS cross-site scripting attacks开放。就个人而言,我将使用具有默认转义支持的HTML模板引擎,例如Jinja