Skip to content

Instantly share code, notes, and snippets.

@pybokeh
Created December 6, 2013 18:46
Show Gist options
  • Save pybokeh/7830114 to your computer and use it in GitHub Desktop.
Save pybokeh/7830114 to your computer and use it in GitHub Desktop.
Using SQL Prepared Statements using IN() Filtering Operator with Python and Pandas
{
"metadata": {
"name": "PreparedStatement_Using_IN()"
},
"nbformat": 3,
"nbformat_minor": 0,
"worksheets": [
{
"cells": [
{
"cell_type": "heading",
"level": 3,
"metadata": {},
"source": "Example on how to use SQL prepared statement with the in() operator"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "You may or may not already realize this, but using a prepared statement with in() can be problematic when you don't know beforehand how many values the user will enter since the number of question marks (?) must be the same as the number of values the user has provided. Typically, prepared statements are used where we assume the user enters just one value, but it is possible to use them where the user can enter any number of values.\n\nFor example, we can't assume the user will provide just one name as in this sql example:<br>\nselect last_name from table where name in(?)\n\nWhat if the user wants to submit more than one name? 2 names? 3 names? How do we address this?<br><br>\nThe solution? Use Python's .join() function. For example, we can do:<br>\n\"select last_name from table where name in(%s)\" % (\",\".join(\"?\" * N), where N is the number of names the user submitted. Suppose N = 4, then the result of this statement would be:<br> select last_name from table where name in(?,?,?,?).<br><br>\nLooks good, but is there a better way?"
},
{
"cell_type": "heading",
"level": 4,
"metadata": {},
"source": "If you're wondering why people would use prepared statements and not just concatenate the sql string, please research what sql injection attacks are. Plus, concatenated sql string just looks plain messy."
},
{
"cell_type": "code",
"collapsed": false,
"input": "import pyodbc # Needed to connect to ODBC data sources\nimport base64 # Needed to de-fuzzy my encrypted password\nimport numpy as np\nimport matplotlib.pyplot as plt\nfrom matplotlib.dates import MonthLocator, WeekdayLocator, DateFormatter\nfrom matplotlib.ticker import MultipleLocator\nimport pandas as pd\n\npw_file = open(r'Q:\\password.txt', 'r')\npw = base64.b64decode(pw_file.read()).decode('utf-8')\nuserid = 'yomama'\npw_file.close()\n\ncnxn_string = 'DSN=myDB;UID=' + userid + ';PWD=' + pw\n\ncnxn = pyodbc.connect(cnxn_string)\ncursor = cnxn.cursor()\n\n# Get the necessary input from the user\nrepl_part = input(\"Enter replaced part#(s) separated by comma: \")\nyear = input(\"Enter model year(s) separated by comma: \")\nfactory = input(\"Enter factory code(s) separated by comma: \")\nmodel = input(\"Enter model name(s) separated by comma: \")\ndest_code = input(\"Enter destination code(s), separated by comma: \")\n\n# Make a list for each parameter input\nrepl_parts = repl_part.split(',')\nyears = year.split(',')\nfactories = factory.split(',')\nmodels = model.split(',')\ndest_codes = dest_code.split(',')\n\n# Now get the number of items in each list so that we can properly use th .join() function above\nR = len(repl_parts) # The number of replaced part #s the user entered\nY = len(years) # The number of years the user entered\nF = len(factories) # The number of factories the user entered\nM = len(models) # The number of models the user entered\nD = len(dest_codes) # The number of destination codes the user entered\n\n# In this SQL, there are 5 parameters that we want to get input from the user using IN(%s)\nsql = \"\"\"\nWITH REPL AS\n(SELECT\nREPL_PART_SK,\nCLM_SK\n\nFROM CMQ.V_FACT_CLM_REPL_PART REPL\nINNER JOIN CMQ.V_DIM_PART PART\nON REPL.REPL_PART_SK = PART.PART_SK\n\nWHERE\nPART.SHRT_PART_NO IN(%s)\n),\n\nVINS AS\n(SELECT DISTINCT\nPROD.VIN_SK,\nPROD.VIN_NO\n\nFROM\nCMQ.V_FACT_VHCL_PRDN_SLS PROD\n\nINNER JOIN CMQ.V_DIM_MTO MTO\nON PROD.MTO_SK = MTO.MTO_SK\n\nWHERE\nMTO.MDL_YR IN(%s)\nAND MTO.FCTRY_CD IN(%s)\nAND MTO.MDL_NM IN(%s)\nAND DEST_CD IN(%s)\n)\n\nSELECT\nREC_DT,\nCOUNT(*) AS QTY\n\nFROM(\nSELECT\nREPL.CLM_SK,\nVINS.VIN_NO,\nREC_CAL.CAL_DT AS REC_DT,\nDPART.SHRT_PART_NO AS REPL_PART\n\nFROM\nCMQ.V_FACT_CLM_TRX CLAIMS\nINNER JOIN REPL\nON CLAIMS.CLM_SK = REPL.CLM_SK\n\nINNER JOIN VINS\nON CLAIMS.VIN_SK = VINS.VIN_SK\n\nINNER JOIN CMQ.V_DIM_DATE REC_CAL\nON CLAIMS.CMQ_RCV_DT_SK = REC_CAL.CAL_DT_SK\n\nINNER JOIN CMQ.V_DIM_PART DPART\nON REPL.REPL_PART_SK = DPART.PART_SK\n) AS TEMP\n\nGROUP BY\nREC_DT\n\"\"\" % (\",\".join(\"?\" * R), \",\".join(\"?\" * Y), \",\".join(\"?\" * F), \",\".join(\"?\" * M), \",\".join(\"?\" * D))\n# The join functions above are what makes prepared statements with IN() possible! R, Y, F, M, and D are the \n# number of values that the user has submitted for those respective ? parameters\n# The join() function will generate a string such that we get: ?,?,?,...where the number of ?s are determined\n# by how many values that were entered by the user separated by commas\n\nparameter_list = []\nfor part in repl_parts:\n parameter_list.append(part)\n \nfor year in years:\n parameter_list.append(year)\n \nfor factory in factories:\n parameter_list.append(factory)\n\nfor model in models:\n parameter_list.append(model)\n \nfor code in dest_codes:\n parameter_list.append(code)\n\ndf = pd.read_sql(sql, cnxn, index_col=\"REC_DT\", params=parameter_list)\n\n# Close connections\ncursor.close()\ncnxn.close()",
"language": "python",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"stream": "stdout",
"text": "Enter replaced part#(s) separated by comma: 79115\n"
},
{
"name": "stdout",
"output_type": "stream",
"stream": "stdout",
"text": "Enter model year(s) separated by comma: 2012\n"
},
{
"name": "stdout",
"output_type": "stream",
"stream": "stdout",
"text": "Enter factory code(s) separated by comma: SSS\n"
},
{
"name": "stdout",
"output_type": "stream",
"stream": "stdout",
"text": "Enter model name(s) separated by comma: FOCUS\n"
},
{
"name": "stdout",
"output_type": "stream",
"stream": "stdout",
"text": "Enter destination code(s), separated by comma: KY,KZ\n"
}
],
"prompt_number": 8
},
{
"cell_type": "code",
"collapsed": false,
"input": "fig = plt.figure()\nax = plt.subplot(1,1,1)\n\n# Let's define x-axis date interval sizes: month, week, or day\nmonth_interval = 1 \nmonths = MonthLocator(bymonth=range(1,13), bymonthday=1, interval=month_interval)\nmonth = MonthLocator(bymonth=range(1,13), bymonthday=1, interval=1)\nweek = WeekdayLocator(byweekday=MO) # Every MOnday\nday = DayLocator(bymonthday=range(1,32), interval=1)\n\n# Let's define x-axis formatting intervals\nmonthsFmt = DateFormatter(\"%b '%y\")\nax.xaxis.set_major_locator(months)\nax.xaxis.set_major_formatter(monthsFmt)\nax.xaxis.set_minor_locator(week)\nax.xaxis.grid(which='major')\n\n# Let's define y-axis formatting\ny_major_ticks = MultipleLocator(5)\nax.yaxis.set_major_locator(y_major_ticks)\nax.yaxis.grid(which='major')\n\n#plt.title(\"\\large{Plotting Dates}\")\nplt.bar(df.index, df.values)\nplt.title(\"Some Data\")\nplt.xticks(rotation=-90)\nplt.xlabel(\"Received Date\\nMajor ticks=months\\nMinor ticks=weeks\")\nplt.ylabel(\"Qty\")\nplt.show()",
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "display_data",
"png": "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\nnT59mjIzM4V1T548ESVLqiPFkkctISEhws9i3JikV69eFBcXR0RFN7Jo1KgRHTt2jBITE8nT09Pk\neVIeHeocPHiQli1bJty56Pz583o38KjJpPrkWVzJ92HxZVO/RwMCAmjPnj1UWFhIW7dupWbNmtHW\nrVtpz5491L17d5Nm6bi4uFBBQYGwfOLECSIq+t2a+s5eVc1S5IAvpaVLl5Kvry8tWrSIunXrRnPn\nziVvb2/q1q0bzZ8/32Q5bm5uQomlsLCQ7O3thWUxPsKePHmS2rVrR+3ataOOHTvSiRMnqFu3btS+\nfXs6dOiQyfPMMUDJmZSDr46UZbI///yTevXqRdbW1uTn50dXr16lMWPGkL+/v2h3Sis50OruLmbo\nOXNlKe6krdTmzp0LT09PxMfHIywsDH5+frhw4QLS09NNermkt7c35s6diyFDhmDbtm1wcnLCG2+8\ngfr165c6sWoKXbt2xd9//4379+8Ll2f+73//M3mOjtQnUeVOq9UiLy8P9evXx4MHD/D3338jNzcX\ndevWxePHj0XJ1JXJAgIC8NNPPwllslq1apm8TCb1SXCgqIx07do1tGnTBpcuXUJSUhKSkpJQv359\nk0/aVuUsk/7ZYWaTm5tL7733Hg0aNIhCQ0OpoKCAvvzyS/roo4/0Slc1ldxPokpNqk+eJcm5TPbz\nzz9Tq1atqF+/ftSmTRvavXs3tWvXjmxtbWnbtm3VIktx1+GzmmnZsmWIjo4Wjg579+6NmJgY1KpV\nC3379i331m6stEOHDiE+Ph7e3t6iffJUmqysLPz5559wcnJCo0aNAIh316uqZPGAz2oMHqAYezo8\n4DPGmEIo7jp8xhhTKh7wGWNMIXjAZ4wxheABn9UItWrVgkajgbu7O4YPH46cnByT7n/QoEHIysp6\n6v2EhoYanKY6NDQUDg4O0Gg06NixI0aMGIGLFy+Wu79NmzYhJSXlqdvFGMADPqshGjRogPj4eCQm\nJsLa2hrr16836f5/+uknWFtbP/V+jE1Xq1KpMGvWLMTHx+PKlSsYM2YM+vXrZ3Q+G52IiAjcvn37\nqdvFGMADPquBevTogb///hsA8Pfff+OFF16At7c3evfujcuXLwMA7t69i2HDhkGtVkOtVgvfAv72\n22/RrVs3aDQaTJ06VZjAy9HREffv38f8+fPxxRdfCFnFj9iXLVsGHx8feHh4IDQ0VHjNxx9/jE6d\n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\nSUVORK5CYII=\n",
"text": "<matplotlib.figure.Figure at 0x459c330>"
}
],
"prompt_number": 6
}
],
"metadata": {}
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment